# Stripe > View the state requirements for 1099-K forms. --- # Source: https://docs.stripe.com/connect/1099-K.md # 1099-K form state requirements View the state requirements for 1099-K forms. > Some participating State regulatory agencies haven’t fully finalized filing requirements and requirements remain subject to change for the 2025 tax season. Updates that occur to this page are automatically reflected in the form status badges and counts in the tax reporting Dashboard. For 1099-K forms, the IRS requires filing if, in a calendar year, the gross amount of total reportable payments exceeds $20,000 and there are more than 200 transactions. Filing requirements for some states might differ from federal requirements. We outline state filing requirements for 1099-K forms to help you identify which [states you can file directly](https://docs.stripe.com/connect/tax-forms-state-requirements.md) in your Dashboard, which states require a state tax registration or withholding ID when filing, and which states you’re responsible for filing directly with. > If you have done backup withholding or state withholding, you might have additional reporting requirements with states. We recommend that you consult a tax advisor. | STATE | 1099-K FILING REQUIRED | DOES STRIPE FILE | FILING DUE DATE* | FILING THRESHOLD | IF ISSUED, PROVIDE STATE NUMBER | | ------------------------ | ---------------------- | --------------------- | ---------------- | ------------------------- | ------------------------------------- | | **Alabama** | State Portal | ✓ Stripe files | April 30 | Same as IRS | – | | **Alaska** | No | – | – | - | – | | **Arizona** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Arkansas** | CFSF | ✓ Stripe files | Same as IRS | $2,500 | – | | **California** | CFSF | ✓ Stripe files | Same as IRS | Same as IRS | – | | **Colorado** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Connecticut** | State Portal | ✓ Stripe files | April 30 | Same as IRS | Connecticut Tax Registration Number | | **Delaware** | No | – | – | - | – | | **District of Columbia** | State Portal | ✓ Stripe files | Same as IRS | $600 | – | | **Florida** | State Portal | ✓ Stripe files | April 30 | Same as IRS | – | | **Georgia** | State Portal | ✓ Stripe files | Same as IRS | Same as IRS | – | | **Hawaii** | CFSF | ✓ Stripe files | Same as IRS | Same as IRS | – | | **Idaho** | No | – | – | - | – | | **Illinois** | State Portal | ✓ Stripe files | Same as IRS | $1,000 and 4 transactions | – | | **Indiana** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Iowa** | If State Witholding | ✗ Stripe doesn't file | February 15 | $0 | – | | **Kansas** | CFSF | ✓ Stripe files | Same as IRS | Same as IRS | Kansas Withholding Tax Account Number | | **Kentucky** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Louisiana** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Maine** | State Portal | ✓ Stripe files | – | Same as IRS | – | | **Maryland** | State Portal | ✓ Stripe files | Same as IRS | $600 | Maryland Central Registration Number | | **Massachusetts** | State Portal | ✓ Stripe files | Same as IRS | $600 | – | | **Michigan** | No | – | – | - | – | | **Minnesota** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Mississippi** | CFSF | ✓ Stripe files | – | Same as IRS | – | | **Missouri** | No | – | – | - | – | | **Montana** | State Portal | ✓ Stripe files | April 1 | $600 | – | | **Nebraska** | No | – | – | - | – | | **Nevada** | No | – | – | - | – | | **New Hampshire** | No | – | – | - | – | | **New Jersey** | CFSF | ✓ Stripe files | Same as IRS | $1,000 | – | | **New Mexico** | No | – | – | - | – | | **New York** | State Portal | ✓ Stripe files | April 30 | Same as IRS | – | | **North Carolina** | State Portal | ✓ Stripe files | Same as IRS | Same as IRS | NC Withholding ID Number or EIN | | **North Dakota** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Ohio** | No | – | – | - | – | | **Oklahoma** | No | – | – | - | – | | **Oregon** | State Portal | ✓ Stripe files | Same as IRS | Same as IRS | – | | **Pennsylvania** | No | – | – | - | – | | **Rhode Island** | State Portal | ✓ Stripe files | Same as IRS | $100 | – | | **South Carolina** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | SC Withholding File Number or EIN | | **South Dakota** | No | – | – | - | – | | **Tennessee** | State Portal | ✓ Stripe files | April 30 | Same as IRS | – | | **Texas** | No | – | – | - | – | | **Utah** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Vermont** | State Portal | ✓ Stripe files | April 30 | $600 | Vermont Withholding Account Number | | **Virginia** | State Portal | ✓ Stripe files | April 30 | $600 | – | | **Washington** | No | – | – | - | – | | **West Virginia** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Wisconsin** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | Wisconsin Withholding Tax Number** | | **Wyoming** | No | – | – | - | – | \*January 22, 2026 is the latest recommended date to file forms with the IRS and states in your Stripe Dashboard \**If a Wisconsin withholding tax number isn’t provided, Stripe uses the default value of `036888888888801` instead. ## How to interpret form state requirements Stripe supports filing in all states that require 1099-K filing and don’t have withholding-based filing requirements. When you file your 1099-K forms from the [Tax forms view](https://dashboard.stripe.com/connect/taxes/forms) in the Dashboard, Stripe submits your forms to the IRS and all qualifying states. ### 1099-K FILING REQUIRED | State Portal | Stripe submits the forms directly to these states. An additional state filing fee of 1.49 USD applies per 1099-K form filed directly with state revenue authorities. | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | CFSF | States listed as CFSF are part of the Combined Federal / State Filing (CFSF) program. Forms filed to the IRS are automatically forwarded to the state, eliminating separate reporting to the participating states. If forms have already been filed with the IRS, you won’t be charged an additional state filing fee for filing in these states. Some states still require direct filing with the state, even though they participate in the CFSF program. Stripe submits the forms directly to these states. | | If State Withholding | You’re required to file a 1099-K form with that state only if you withheld state taxes. In your Dashboard, you can specify the amount withheld by updating the form and updating the `state_tax_withheld` column. When you file your 1099-K forms in the Dashboard, we automatically export forms eligible for state filing and with `state_tax_withheld` so you can file directly with applicable states. | > Some forms that appear to be below the federal filing threshold can also appear as `Ready` or `Needs attention` due to Grouped TINs or state filing thresholds. [Learn more](https://docs.stripe.com/connect/file-tax-forms.md#below-threshold-forms) ### FILING DUE DATE While the IRS filing deadline for 1099-K forms is March 31 and the IRS deadline to deliver 1099 forms to your payees is January 31, we coupled filing and delivery together to streamline the tax reporting process. **January 22, 2026** is the latest recommended date to file forms with the IRS and states in your Stripe Dashboard. This guarantees forms are filed with the IRS and a copy is sent to the recipients before the IRS delivery deadline of January 31. ### STATE NUMBERS State Tax Registration or Withholding IDs are only required for some states. After you obtain the registration or withholding ID, add the states in which you’ll file and the corresponding IDs on the [Tax forms settings](https://dashboard.stripe.com/settings/connect/tax_forms) page. In the Dashboard, click **Settings**. On **Product settings**, under **Connect**, click **Tax form settings**. When filing forms in your Dashboard, you must provide an appropriate ID in states that require one. ## See also - [File form with states](https://docs.stripe.com/connect/tax-forms-state-requirements.md) - [Add the state tax Registration or withholding ID](https://docs.stripe.com/connect/tax-forms-state-requirements.md#add-state-reg) --- # Source: https://docs.stripe.com/connect/1099-NEC.md # 1099-NEC form state requirements View the state requirements for 1099-NEC forms. > Some participating State regulatory agencies haven’t fully finalized filing requirements and requirements remain subject to change for the 2025 tax season. Updates that occur to this page are automatically reflected in the form status badges and counts in the tax reporting Dashboard. For 1099-NEC forms, the IRS requires filing if the amount of total reportable payments is $600 or more. Filing requirements for some states might differ from federal requirements. We outline state filing requirements for 1099-NEC forms to help you identify which [states you can file directly](https://docs.stripe.com/connect/tax-forms-state-requirements.md) in your Dashboard, which states require a state tax registration or withholding ID when filing, and which states you’re responsible for filing directly with. > If you have done backup withholding or state withholding, you might have additional reporting requirements with states. We recommend that you consult a tax advisor. | STATE | 1099-NEC FILING REQUIRED | DOES STRIPE FILE | FILING DUE DATE* | FILING THRESHOLD | IF ISSUED, PROVIDE STATE NUMBER | | ------------------------ | ------------------------ | --------------------- | ---------------- | ---------------- | ------------------------------------- | | **Alabama** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Alaska** | No | – | – | - | – | | **Arizona** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Arkansas** | CFSF | ✓ Stripe files | Same as IRS | Same as IRS | – | | **California** | CFSF | ✓ Stripe files | Same as IRS | Same as IRS | – | | **Colorado** | If State Witholding | ✗ Stripe doesn't file | March 31 | $0 | – | | **Connecticut** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | Connecticut Tax Registration Number | | **Delaware** | State Portal | ✓ Stripe files | Same as IRS | Same as IRS | Must use EIN | | **District of Columbia** | State Portal | ✓ Stripe files | Same as IRS | Same as IRS | – | | **Florida** | No | – | – | - | – | | **Georgia** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Hawaii** | CFSF | ✓ Stripe files | Same as IRS | Same as IRS | – | | **Idaho** | CFSF | ✓ Stripe files | February 28 | Same as IRS | Idaho Withholding Account Number | | **Illinois** | No | – | – | - | – | | **Indiana** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Iowa** | If State Witholding | ✗ Stripe doesn't file | February 15 | $0 | – | | **Kansas** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | Kansas Withholding Tax Account Number | | **Kentucky** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Louisiana** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Maine** | State Portal | ✓ Stripe files | – | Same as IRS | – | | **Maryland** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | Maryland Central Registration Number | | **Massachusetts** | State Portal | ✓ Stripe files | Same as IRS | Same as IRS | – | | **Michigan** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Minnesota** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Mississippi** | CFSF | ✓ Stripe files | February 28 | $601 | – | | **Missouri** | State Portal | ✓ Stripe files | February 28 | $1,200 | – | | **Montana** | State Portal | ✓ Stripe files | Same as IRS | Same as IRS | – | | **Nebraska** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | Nebraska Number | | **Nevada** | No | – | – | - | – | | **New Hampshire** | No | – | – | - | – | | **New Jersey** | CFSF | ✓ Stripe files | Same as IRS | $1,000 | – | | **New Mexico** | No | – | – | - | – | | **New York** | No | – | – | - | – | | **North Carolina** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | NC Withholding ID Number or EIN | | **North Dakota** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Ohio** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Oklahoma** | CFSF | ✓ Stripe files | Same as IRS | $750 | – | | **Oregon** | State Portal | ✓ Stripe files | Same as IRS | Same as IRS | – | | **Pennsylvania** | State Portal | ✓ Stripe files | Same as IRS | Same as IRS | PA Employer Account ID | | **Rhode Island** | State Portal | ✓ Stripe files | Same as IRS | $100 | – | | **South Carolina** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | SC Withholding File Number or EIN | | **South Dakota** | No | – | – | - | – | | **Tennessee** | No | – | – | - | – | | **Texas** | No | – | – | - | – | | **Utah** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Vermont** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | Vermont Withholding Account Number | | **Virginia** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Washington** | No | – | – | - | – | | **West Virginia** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | – | | **Wisconsin** | If State Witholding | ✗ Stripe doesn't file | Same as IRS | $0 | Wisconsin Withholding Tax Number** | | **Wyoming** | No | – | – | - | – | \*January 22, 2026 is the latest recommended date to file forms with the IRS and states in your Stripe Dashboard \**If a Wisconsin withholding tax number isn’t provided, Stripe uses the default value of `036888888888801` instead. ## How to interpret form state requirements Stripe supports filing in all states that require 1099-NEC filing and don’t have withholding-based filing requirements. When you file your 1099-NEC forms from the [Tax forms view](https://dashboard.stripe.com/connect/taxes/forms) in the Dashboard, Stripe submits your forms to the IRS and all qualifying states. ### 1099-NEC FILING REQUIRED | State Portal | Stripe submits the forms directly to these states. An additional state filing fee of 1.49 USD applies per 1099-NEC form filed directly with state revenue authorities. | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | CFSF | States listed as CFSF are part of the Combined Federal / State Filing (CFSF) program. Forms filed to the IRS are automatically forwarded to the state, eliminating separate reporting to the participating states. If forms have already been filed with the IRS, you won’t be charged an additional state filing fee for filing in these states. Some states still require direct filing with the state, even though they participate in the CFSF program. Stripe submits the forms directly to these states. | | If State Withholding | You’re required to file a 1099-NEC form with that state only if you withheld state taxes. In your Dashboard, you can specify the amount withheld by updating the form and updating the `state_tax_withheld` column. When you file your 1099-NEC forms in the Dashboard, we automatically export forms eligible for state filing and with `state_tax_withheld` so you can file directly with applicable states. | > Some forms that appear to be below the federal filing threshold can also appear as `Ready` or `Needs attention` due to Grouped TINs or state filing thresholds. [Learn more](https://docs.stripe.com/connect/file-tax-forms.md#below-threshold-forms) ### FILING DUE DATE While the IRS deadline to file 1099-NEC forms and deliver forms to your payees is January 31, we coupled filing and delivery together to streamline the process. **January 22, 2026** is the latest recommended date to file forms with the IRS and states in your Stripe Dashboard. This guarantees forms are filed with the IRS and a copy is sent to the recipients before the IRS delivery deadline of January 31. ### STATE NUMBERS Some states require State Tax Registration or Withholding IDs. Delaware and Pennsylvania typically reject state filings for 1099-NEC, when state IDs are missing and a state ID was issued. After you obtain the registration or withholding ID, add the states in which you’ll file and the corresponding IDs on the [Tax forms settings](https://dashboard.stripe.com/settings/connect/tax_forms) page. In the Dashboard, click **Settings**. On **Product settings**, under **Connect**, click **Tax form settings**. When filing forms in your Dashboard, you must provide an appropriate ID in states that require one. ## See also - [File form with states](https://docs.stripe.com/connect/tax-forms-state-requirements.md) - [Add the state tax Registration or withholding ID](https://docs.stripe.com/connect/tax-forms-state-requirements.md#add-state-reg) --- # Source: https://docs.stripe.com/issuing/3d-secure.md # Cardholder authentication using 3D Secure Learn about 3D Secure, an additional layer of authentication used by businesses to combat fraud. 3D Secure (3DS) uses multi-factor authentication to reduce fraud for online transactions where a card isn’t physically present. 3DS is triggered by businesses in online checkout flows, and requires multi-factor authentication (usually through SMS or email-based one-time passcode that Stripe sends) to complete. ## Example of a 3D Secure flow ![A Stripe checkout page with the payment information filled out, including the Pay button](https://b.stripecdn.com/docs-statics-srv/assets/3ds-flow-1-checkout-page.039294e0dee3a6dede8ea8a32185aae5.png) Step 1: The customer enters their card details. ![A dialog that displays a loading animation after clicking the Pay button, which now says Processing.](https://b.stripecdn.com/docs-statics-srv/assets/3ds-flow-3-challenge-flow.9052a220f336bbdb75a51799622c6477.png) Step 2: The acquirer requests 3DS verification. If the Stripe issuing card is enrolled in 3DS, the cardholder sees a prompt to complete an additional verification step. As shown above, the additional 3D Secure step at checkout typically involves showing the cardholder an authentication page from their Issuer, where the cardholder sees a prompt to enter a verification code sent to their phone or email. ## Why 3DS is important In most cases, businesses are responsible for online fraud losses in card-not-present transactions. To protect themselves, businesses can trigger 3DS verification to reduce the chances of accepting a fraudulent transaction. Even if a business triggers 3DS verification, the cardholder only needs to complete the step if your Stripe cards are enrolled in 3DS. In the UK and EU, 3DS is the standard for implementing the regulatory requirements of [Strong Customer Authentication](https://docs.stripe.com/strong-customer-authentication.md) (SCA). ## Liability shift When a business triggers 3DS verification, liability for fraud shifts from the business to the issuer in most cases. This applies whether or not your Issuing cards are enrolled in 3DS, meaning issuers can take on increased liability without any additional verification. ## 3DS enrollment Depending on your location, 3DS enrollment is either optional and opt-in or required and enabled by default. ### US 3DS enrollment in the US is optional, and your cards aren’t enrolled in 3DS unless you contact support to request enrollment. While enrollment does increase friction for a subset of your cardholder transactions, it helps to significantly reduce the risk of potential losses because of transaction fraud with online, card-not-present transactions. As part of our [best practices](https://docs.stripe.com/issuing/manage-fraud.md) for managing transaction fraud, we recommend enrolling your cards in 3DS early in your Issuing program’s life cycle. After you request enrollment, we enroll all active cards associated with your account and automatically enroll all cards created going forward. Cardholders without a phone number or email on file aren’t enrolled in 3DS. After requesting enrollment, add contact information to [Cardholder objects](https://docs.stripe.com/api/issuing/cardholders/object.md) to enroll those cards. Conversely, removing the contact info for a cardholder results in the card being unenrolled from 3DS. When you update a cardholder’s phone number or email address, we automatically re-enroll the card with the updated contact information. You don’t need to manually re-enroll the card. ### UK and EU After creation, cards are enrolled in 3DS by default because of local regulations. To allow the implementation of SCA over 3DS and comply with local regulations, all cards issued within the EU and UK require a valid phone number on file for the relevant [cardholder](https://docs.stripe.com/api.md#create_issuing_cardholder). When you update a cardholder’s phone number or email address, we automatically re-enroll the card with the updated contact information. You don’t need to manually re-enroll the card. ## 3DS authentication When a 3DS authentication request comes through for your [cardholder](https://docs.stripe.com/api.md#create_issuing_cardholder), Stripe sends them either a text message or an email containing a one-time verification code. The method of authentication depends on the contact information provided for the cardholder. In the UK and EU markets supported by Stripe Issuing, cardholders must have a phone number on file to authenticate with a one-time text message verification code. In the US, the phone number or email on file will be used to authenticate cardholders, but if both the phone number and email are present, then the phone number will be used for authentication. Otherwise, the authentication request uses whichever contact information is available. To enable us to best secure you and your cardholders, we recommend keeping phone numbers and email addresses up to date for cardholders. This enables us to contact them during authentication. You can update your cardholders’ information by changing the field to its new value through the API or Dashboard. In the UK and EU, cardholders should see an additional security question. The cardholder sees a list of transactions on the card, and they can select the transactions they recognize. If the cardholder is using the card for the first time, they select the option indicating they don’t recognize any of the presented transactions. ![A dialog showing a sample security question with choices of payment history. The header has a Your Bank placeholder logo and Card Network placeholder logo. The security question says, From the following list please identify a recent payment you have made using this card. There are 5 options with payment information of whether or not the payment was online, the purchase amount, and the merchant name. The last option says None of the above. There is a blurple button at the bottom that says Verify.](https://b.stripecdn.com/docs-statics-srv/assets/3ds-issuing-knowledge-factor-netcetera.37258cc6c8e63cadf3dbb9b22f94d786.png) The list of transactions the cardholder is presented with. ## Choose the 3D Secure language The [preferred_locales](https://docs.stripe.com/api/issuing/cardholders/object.md#issuing_cardholder_object-preferred_locales) field of the Cardholder object determines the display language of the 3DS flow. The default 3DS language is English. To pick a 3DS language for a cardholder, use the API to set their `preferred_locales` to an array of preferred languages, in order of preference. If you want, you can provide one language only. The supported languages are English (`en`), French (`fr`), German (`de`), Italian (`it`), and Spanish (`es`). ```curl curl https://api.stripe.com/v1/issuing/cardholders \ -u "<>:" \ -d type=individual \ -d name="Jane D. Rocket" \ --data-urlencode email="jane@example.com" \ -d "preferred_locales[]"=fr \ -d "preferred_locales[]"=en \ -d "billing[address][line1]"="1234 Main Street" \ -d "billing[address][city]"="San Francisco" \ -d "billing[address][state]"=CA \ -d "billing[address][country]"=US \ -d "billing[address][postal_code]"=94111 ``` ```cli stripe issuing cardholders create \ --type=individual \ --name="Jane D. Rocket" \ --email="jane@example.com" \ -d "preferred_locales[0]"=fr \ -d "preferred_locales[1]"=en \ -d "billing[address][line1]"="1234 Main Street" \ -d "billing[address][city]"="San Francisco" \ -d "billing[address][state]"=CA \ -d "billing[address][country]"=US \ -d "billing[address][postal_code]"=94111 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") cardholder = client.v1.issuing.cardholders.create({ type: 'individual', name: 'Jane D. Rocket', email: 'jane@example.com', preferred_locales: ['fr', 'en'], billing: { address: { line1: '1234 Main Street', city: 'San Francisco', state: 'CA', country: 'US', postal_code: '94111', }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. cardholder = client.v1.issuing.cardholders.create({ "type": "individual", "name": "Jane D. Rocket", "email": "jane@example.com", "preferred_locales": ["fr", "en"], "billing": { "address": { "line1": "1234 Main Street", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94111", }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $cardholder = $stripe->issuing->cardholders->create([ 'type' => 'individual', 'name' => 'Jane D. Rocket', 'email' => 'jane@example.com', 'preferred_locales' => ['fr', 'en'], 'billing' => [ 'address' => [ 'line1' => '1234 Main Street', 'city' => 'San Francisco', 'state' => 'CA', 'country' => 'US', 'postal_code' => '94111', ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CardholderCreateParams params = CardholderCreateParams.builder() .setType(CardholderCreateParams.Type.INDIVIDUAL) .setName("Jane D. Rocket") .setEmail("jane@example.com") .addPreferredLocale(CardholderCreateParams.PreferredLocale.FR) .addPreferredLocale(CardholderCreateParams.PreferredLocale.EN) .setBilling( CardholderCreateParams.Billing.builder() .setAddress( CardholderCreateParams.Billing.Address.builder() .setLine1("1234 Main Street") .setCity("San Francisco") .setState("CA") .setCountry("US") .setPostalCode("94111") .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Cardholder cardholder = client.v1().issuing().cardholders().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const cardholder = await stripe.issuing.cardholders.create({ type: 'individual', name: 'Jane D. Rocket', email: 'jane@example.com', preferred_locales: ['fr', 'en'], billing: { address: { line1: '1234 Main Street', city: 'San Francisco', state: 'CA', country: 'US', postal_code: '94111', }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.IssuingCardholderCreateParams{ Type: stripe.String(stripe.IssuingCardholderTypeIndividual), Name: stripe.String("Jane D. Rocket"), Email: stripe.String("jane@example.com"), PreferredLocales: []*string{ stripe.String(stripe.IssuingCardholderPreferredLocaleFR), stripe.String(stripe.IssuingCardholderPreferredLocaleEN), }, Billing: &stripe.IssuingCardholderCreateBillingParams{ Address: &stripe.AddressParams{ Line1: stripe.String("1234 Main Street"), City: stripe.String("San Francisco"), State: stripe.String("CA"), Country: stripe.String("US"), PostalCode: stripe.String("94111"), }, }, } result, err := sc.V1IssuingCardholders.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Issuing.CardholderCreateOptions { Type = "individual", Name = "Jane D. Rocket", Email = "jane@example.com", PreferredLocales = new List { "fr", "en" }, Billing = new Stripe.Issuing.CardholderBillingOptions { Address = new AddressOptions { Line1 = "1234 Main Street", City = "San Francisco", State = "CA", Country = "US", PostalCode = "94111", }, }, }; var client = new StripeClient("<>"); var service = client.V1.Issuing.Cardholders; Stripe.Issuing.Cardholder cardholder = service.Create(options); ``` In the US, Stripe also supports authentication through a native iOS and Android application. If you want to use this functionality, [please reach out to support](https://support.stripe.com/contact). Regardless of the authentication method used, if a cardholder can’t complete three consecutive 3DS attempts in a short period of time, it disables 3DS on their cards for 60 minutes. ## Exemptions Certain types of low-risk payments might be exempt from SCA. Exemptions limit friction for low-risk payments by reducing the frequency of customer authentication. By default, Stripe might claim the following exemptions for 3DS-eligible cards to limit the friction associated with transactions it deems low risk or low value: | Type | Meaning | | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | transaction_risk_analysis (US only) | An issuer (such as Stripe) can do a real-time risk analysis to determine whether or not to claim a low-risk exemption to a transaction. | | low_value_transaction | Transactions below 30 GBP/EUR (or equivalent converted amount) are considered “low value” and might be exempt from SCA. If the exemption has been used five times since the cardholder’s last successful authentication or if the sum of previously exempted payments exceeds 100 GBP or EUR, then the exemption doesn’t apply, and the cardholder must be authenticated. | Acquirers can also request exemptions, and Stripe might honor them. In these scenarios, loss liability stays with the acquirer and doesn’t shift to the issuer. When an issuer-claimed exemption is applied, the [Authorization object](https://docs.stripe.com/api/issuing/authorizations.md) looks like this: ```json { "object": "issuing.authorization", ..."verification_data" : { ... "authentication_exemption": { "type": "low_value_transaction", "claimed_by": "issuer" }, ... }, ... } ``` Conversely, when an acquirer-claimed exemption is applied, the [Authorization object](https://docs.stripe.com/api/issuing/authorizations.md) looks like this: ```json { "object": "issuing.authorization", ..."verification_data" : { ... "authentication_exemption": { "type": "low_value_transaction", "claimed_by": "acquirer" }, ... }, ... } ``` If you’re based in the UK or EU and your use case only requires virtual cards, you can contact Stripe Support to discuss whether a Secure Corporate Payment (SCP) exemption is applicable to your program. ## Manage fraud through 3DS Stripe includes details about a 3DS attempt through the API in the authorization endpoint. Use the `three_d_secure` hash in the [verification_data](https://docs.stripe.com/api/issuing/authorizations/object.md#issuing_authorization_object-verification_data) hash to determine if an authorization was successfully authenticated. If you maintain your own authorization logic, we suggest using these values as key inputs that determine whether to approve or reject an authorization. Additionally, if the business didn’t attempt 3DS, the `three_d_secure` field is null. If 3DS was exempted, then the `authentication_exemption` is present and the `three_d_secure` field is null. An authorization can’t contain both `three_d_secure` and `authentication_exemption`. If the authentication fails, Stripe automatically denies the authorization to protect against fraudulent transactions. No action is required. You can find guidelines on what the values represent and how you can use them to combat fraud in the table below. | Result | Meaning | Suggested action | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | attempt_acknowledged | The business attempted to authenticate the authorization, but the card isn’t enrolled or couldn’t reach Stripe. | There is insufficient evidence to determine if the authorization is fraudulent or not. | | authenticated | The shopper was successfully verified as the cardholder as they entered the correct verification code sent to their phone. The online purchase was legitimate and not fraudulent. | Approve the transaction. | | required | The authorization was declined because regulatory requirements mandated an authentication for this transaction but it wasn’t submitted correctly by the merchant, and they didn’t claim an applicable exemption. | Decline the transaction. | ## Test 3DS To test 3D Secure functionality, use the Checkout Sessions API. The response includes a URL to a Stripe-hosted payment page where you can enter your issued card details to attempt a payment. 3DS testing is only available in livemode. For the following example, replace the API key with your livemode API key. ### Create a Checkout Session To trigger 3D Secure manually for a Checkout Session, set [payment_method_options[card][request_three_d_secure]](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_method_options-card-request_three_d_secure) to `challenge` or `any` in your request. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"="3DS test" \ -d "line_items[0][price_data][unit_amount]"=1000 \ -d "line_items[0][quantity]"=1 \ -d "payment_method_options[card][request_three_d_secure]"=challenge \ -d mode=payment \ --data-urlencode success_url="https://example.com/success?session_id={CHECKOUT_SESSION_ID}" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"="3DS test" \ -d "line_items[0][price_data][unit_amount]"=1000 \ -d "line_items[0][quantity]"=1 \ -d "payment_method_options[card][request_three_d_secure]"=challenge \ --mode=payment \ --success-url="https://example.com/success?session_id={CHECKOUT_SESSION_ID}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: {name: '3DS test'}, unit_amount: 1000, }, quantity: 1, }, ], payment_method_options: {card: {request_three_d_secure: 'challenge'}}, mode: 'payment', success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "3DS test"}, "unit_amount": 1000, }, "quantity": 1, }, ], "payment_method_options": {"card": {"request_three_d_secure": "challenge"}}, "mode": "payment", "success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => '3DS test'], 'unit_amount' => 1000, ], 'quantity' => 1, ], ], 'payment_method_options' => ['card' => ['request_three_d_secure' => 'challenge']], 'mode' => 'payment', 'success_url' => 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("3DS test") .build() ) .setUnitAmount(1000L) .build() ) .setQuantity(1L) .build() ) .setPaymentMethodOptions( SessionCreateParams.PaymentMethodOptions.builder() .setCard( SessionCreateParams.PaymentMethodOptions.Card.builder() .setRequestThreeDSecure( SessionCreateParams.PaymentMethodOptions.Card.RequestThreeDSecure.CHALLENGE ) .build() ) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success?session_id={CHECKOUT_SESSION_ID}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: { name: '3DS test', }, unit_amount: 1000, }, quantity: 1, }, ], payment_method_options: { card: { request_three_d_secure: 'challenge', }, }, mode: 'payment', success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("3DS test"), }, UnitAmount: stripe.Int64(1000), }, Quantity: stripe.Int64(1), }, }, PaymentMethodOptions: &stripe.CheckoutSessionCreatePaymentMethodOptionsParams{ Card: &stripe.CheckoutSessionCreatePaymentMethodOptionsCardParams{ RequestThreeDSecure: stripe.String(stripe.CheckoutSessionPaymentMethodOptionsCardRequestThreeDSecureChallenge), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success?session_id={CHECKOUT_SESSION_ID}"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "3DS test", }, UnitAmount = 1000, }, Quantity = 1, }, }, PaymentMethodOptions = new Stripe.Checkout.SessionPaymentMethodOptionsOptions { Card = new Stripe.Checkout.SessionPaymentMethodOptionsCardOptions { RequestThreeDSecure = "challenge", }, }, Mode = "payment", SuccessUrl = "https://example.com/success?session_id={CHECKOUT_SESSION_ID}", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` This creates a Checkout Session and returns a response containing a URL to a Stripe-hosted payment page. You can access this URL in any browser. Enter your issued card information to attempt a payment and trigger a 3DS challenge. ```json { "id": "cs_live_...", "object": "checkout.session", "payment_method_options": { "card": { "request_three_d_secure": "challenge" } }, ..."url": "https://checkout.stripe.com/c/pay/cs_live_...", ... } ``` A 3DS challenge still isn’t guaranteed even when you set `request_three_d_secure` to `challenge`. If a challenge doesn’t occur, attempt another purchase with a greater `unit_amount`. --- # Source: https://docs.stripe.com/atlas/83b-election.md # Section 83(b) elections Learn about common considerations for Section 83(b) elections. > #### Note > > Stripe Atlas doesn’t provide tax or legal advice. Consult tax and legal professionals for advice on how to meet ongoing legal, tax, and accounting obligations that apply to you and your company. A Section 83(b) election is a form that lets the Internal Revenue Service (IRS) know you’d like to have your founder stock taxed at the time of purchase rather than at the time of vesting. In many cases, a Section 83(b) election can save you a significant amount on your future taxes. If you make a Section 83(b) election, most importantly, you won’t pay taxes when your stock vests. Instead, you choose to pay very little (if any at all) taxes at the time of stock purchase, and you won’t owe taxes until you actually sell your stock. [Atlas files 83(b) elections for all C-corp founders](https://support.stripe.com/questions/atlas-filing-your-83%28b%29-election-using-auto-83%28b%29). LLC founders don’t need to file an 83(b) tax election, as equity in an LLC created with Atlas doesn’t vest. ## Benefits of the Section 83(b) election for newly incorporated startups Startup lawyers recommend filing a Section 83(b) election if founders purchase their stock when the company is still at its early stage. If you recently incorporated your startup, are currently a US taxpayer, or plan to become one in the future, this filing could save you a significant amount on future taxes. Not all stock is eligible for a Section 83(b) election, but if you’re incorporating a C corporation through Atlas, your company’s stock is eligible because it’s subject to a vesting schedule of 4 years with a one-year cliff. ## Section 83(b) elections for non US residents If you live outside the US but file US tax returns, startup lawyers recommend making a Section 83(b) election because it might save you on future US taxes. If you do not currently file US tax returns but think you might become a US taxpayer in the future, making a Section 83(b) election is important. Not doing so could result in additional US tax liability when your stock vests. If you are not currently a US taxpayer and do not anticipate becoming one in the future, making a Section 83(b) election doesn’t matter because it affects only US tax liability. The IRS requires a US Taxpayer Identification Number (TIN) at the time of filing. This can be either a Social Security Number (SSN) or an Individual Taxpayer Identification Number (ITIN). If you don’t have either of these when you incorporate with Stripe Atlas, Stripe informs the IRS that you’re a non-US taxpayer, and you intend to apply for an ITIN upon becoming a US taxpayer. Consult a tax advisor about if and when to get an ITIN. ## Tax impact of a Section 83(b) election in detail, with an example This election impacts when you owe taxes and the amount that you’re taxed on your founder’s stock. - Without a Section 83(b) election, you aren’t taxed at the time stock is issued to you. However, every time your stock vests in the future, you have to pay ordinary income taxes to the extent your stock value (often referred to as “fair market value”) has increased from the date you purchased your stock. When you sell your stock, you’ll owe capital gains tax on the difference between the value of your stock at sale and the value you were taxed on at vesting. (Capital gains tax rates on property held for more than one year are generally lower than ordinary income tax rates. The length of time you hold your stock is called the “holding period." If you don’t make a Section 83(b) election, your holding period begins when the stock vests.) - With a Section 83(b) election, you only owe ordinary income taxes at the time of stock issuance to the extent the value of the purchased stock is greater than what you pay. If you pay fully for your stock at the time of your stock purchase, you should owe no additional income taxes. This is because our stock purchase agreement template presumes your stock value equals the issuance price (also called par value), reflecting that your company doesn’t have significant assets in it yet. If your company is beyond the “raw idea” stage, when the stock value as assessed by a 409a valuation is higher than the issuance price, consult with your tax advisor. When you later sell your shares, you’re taxed on the capital gains, which is the difference between the stock’s value per share when you sell it and the value when the stock was issued to you. Another advantage of making a Section 83(b) election is that your holding period begins earlier (when you’re issued the stock), which is typically a year earlier than when you vest the first round of the initial grant. For example, your company issues you 200,000 shares valued at 0.0001 USD per share and you pay 0.0001 USD per share using cash. With an 83(b), you don’t have an income inclusion in the year the stock is issued as you paid for the value of the shares. If you don’t pay for the value of the shares using cash or other assets, a Section 83(b) election means you choose to include as ordinary income in the year the shares are issued the full value of the stock (20 USD). If half of your stock vests 1 year later and the other half vests 2 years later, you have no tax consequences because you made a Section 83(b) election. If 3 years from now you sell your stock for 2.00 USD per share (total of 400,000 USD), then you pay capital gains taxes on 399,980 USD (400,000 USD minus 20 USD). If you don’t make a Section 83(b) election, you don’t have tax consequences on issuance of stock subject to vesting. However, if the value of your shares is 0.50 USD per share when half vest in 1 year then you would pay ordinary income taxes on 49,990 USD (0.50 USD value minus 0.0001 USD paid per share, multiplied by 100,000 shares) at vesting. If the value of your shares is 1.00 USD per share when the second half vest in 2 years from issuance, then you’d pay ordinary income taxes on 99,990 USD (1.00 USD value minus 0.0001 USD paid per share, multiplied by 100,000 shares) at vesting. If you sell your stock in 3 years for 2.00 USD per share (total of 400,000 USD), then you pay capital gains taxes on 250,000 USD (400,000 USD minus 20.00 USD paid for the shares, minus 149,980 USD). Non-founder employees receiving stock subject to vesting are also eligible for a Section 83(b) election, but might have additional tax considerations at the time of stock issuance. We suggest they consult with their tax advisors before making the election. --- # Source: https://docs.stripe.com/atlas/83b-elections-non-us-founders.md # File Section 83(b) elections as a non-US founder Learn about filing an 83(b) election as a non-US founder. > #### Note > > Stripe Atlas does not provide tax or legal advice. Consult tax and legal professionals for advice on how to meet ongoing legal, tax, and accounting obligations that apply to you and your company. If you live outside the US but file US tax returns, startup lawyers recommend making a Section 83(b) election because it might save you on future US taxes. If you currently don’t file US tax returns but might become a US taxpayer in the future, it’s important to make a Section 83(b) election. Failing to do so could lead to additional US tax liability when your stock vests. If you’re not a US taxpayer and don’t plan to become one, making a Section 83(b) election is unnecessary as it only impacts US tax liability. The IRS requires a US Taxpayer Identification Number (TIN) at the time of filing. Use either your Social Security Number (SSN) or an Individual Taxpayer Identification Number (ITIN). If you don’t have either when you incorporate with Stripe Atlas, Stripe informs the IRS that you are a non-US taxpayer, and you intend to apply for an ITIN after you become a US taxpayer. Consult a tax advisor to determine if and when you should get an ITIN. [Atlas files 83(b) elections for all C-corp founders](https://support.stripe.com/questions/atlas-filing-your-83%28b%29-election-using-auto-83%28b%29). LLC founders don’t need to file an 83(b) tax election, as equity in an LLC created with Atlas doesn’t vest. --- # Source: https://docs.stripe.com/payments/accept-a-payment.md # Accept a payment Securely accept payments online. Build a payment form or use a prebuilt checkout page to start accepting online payments. > #### Not a developer? > > Use Stripe’s [no-code options](https://docs.stripe.com/no-code.md) or apps from [our partners](https://stripe.partners/) to get started and do more with your Stripe account—no code required. If you use a third-party platform to build and maintain a website, you can add Stripe payments with a plugin. # Stripe-hosted page > This is a Stripe-hosted page for when payment-ui is checkout and ui is stripe-hosted. View the full page at https://docs.stripe.com/payments/accept-a-payment?payment-ui=checkout&ui=stripe-hosted. Redirect to a Stripe-hosted payment page using [Stripe Checkout](https://docs.stripe.com/payments/checkout.md). See how this integration [compares to Stripe’s other integration types](https://docs.stripe.com/payments/online-payments.md#compare-features-and-availability). #### Integration effort Complexity: 2/5 #### Integration type Redirect to Stripe-hosted payment page #### UI customization Limited customization - 20 preset fonts - 3 preset border radius - Custom background and border color - Custom logo [Try it out](https://checkout.stripe.dev/) First, [register](https://dashboard.stripe.com/register) for a Stripe account. Use our official libraries to access the Stripe API from your application: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` #### Python ```bash # Install through pip pip3 install --upgrade stripe ``` ```bash # Or find the Stripe package on http://pypi.python.org/pypi/stripe/ ``` ```python # Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=5.0.0 ``` #### PHP ```bash # Install the PHP library with Composer composer require stripe/stripe-php ``` ```bash # Or download the source directly: https://github.com/stripe/stripe-php/releases ``` #### Java ```java /* For Gradle, add the following dependency to your build.gradle and replace with the version number you want to use from: - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:31.3.0" ``` ```xml com.stripe stripe-java 31.3.0 ``` ```bash # For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson ``` #### Node.js ```bash # Install with npm npm install stripe --save ``` #### Go ```bash # Make sure your project is using Go Modules go mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v84 ``` ```go // Then import the package import ( "github.com/stripe/stripe-go/v84" ) ``` #### .NET ```bash # Install with dotnet dotnet add package Stripe.net dotnet restore ``` ```bash # Or install with NuGet Install-Package Stripe.net ``` ## Redirect your customer to Stripe Checkout [Client-side] [Server-side] Add a checkout button to your website that calls a server-side endpoint to create a [Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md). You can also create a Checkout Session for an [existing customer](https://docs.stripe.com/payments/existing-customers.md?platform=web&ui=stripe-hosted), allowing you to prefill Checkout fields with known contact information and unify your purchase history for that customer. ```html Buy cool new product
``` A Checkout Session is the programmatic representation of what your customer sees when they’re redirected to the payment form. You can configure it with options such as: - [Line items](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items) to charge - Currencies to use You must populate `success_url` with the URL value of a page on your website that Checkout returns your customer to after they complete the payment. > Checkout Sessions expire 24 hours after creation by default. After creating a Checkout Session, redirect your customer to the [URL](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-url) returned in the response. #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. require 'json' require 'sinatra' require 'stripe' # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' post '/create-checkout-session' dosession = Stripe::Checkout::Session.create({ line_items: [{ price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }], mode: 'payment', # These placeholder URLs will be replaced in a following step. success_url: 'https://example.com/success', }) redirect session.url, 303 end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck. import os import stripe from flask import Flask, redirect app = Flask(__name__) stripe.api_key = '<>' @app.route('/create-checkout-session', methods=['POST']) def create_checkout_session():session = stripe.checkout.Session.create( line_items=[{ 'price_data': { 'currency': 'usd', 'product_data': { 'name': 'T-shirt', }, 'unit_amount': 2000, }, 'quantity': 1, }], mode='payment', success_url='http://localhost:4242/success', ) return redirect(session.url, code=303) if __name__== '__main__': app.run(port=4242) ``` #### PHP ```php >'); $checkout_session = $stripe->checkout->sessions->create([ 'line_items' => [[ 'price_data' => [ 'currency' => 'usd', 'product_data' => [ 'name' => 'T-shirt', ], 'unit_amount' => 2000, ], 'quantity' => 1, ]], 'mode' => 'payment', 'success_url' => 'http://localhost:4242/success', ]); header("HTTP/1.1 303 See Other"); header("Location: " . $checkout_session->url); ?> ``` #### Java ```java import java.util.HashMap; import java.util.Map; import static spark.Spark.get; import static spark.Spark.post; import static spark.Spark.port; import static spark.Spark.staticFiles; import com.stripe.Stripe; import com.stripe.model.checkout.Session; import com.stripe.param.checkout.SessionCreateParams; public class Server { public static void main(String[] args) { port(4242); Stripe.apiKey = "<>"; post("/create-checkout-session", (request, response) -> {SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("http://localhost:4242/success") .addLineItem( SessionCreateParams.LineItem.builder() .setQuantity(1L) .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setUnitAmount(2000L) .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build()) .build()) .build()) .build(); Session session = Session.create(params); response.redirect(session.getUrl(), 303); return ""; }); } } ``` #### Node.js ```javascript // This example sets up an endpoint using the Express framework. const express = require('express'); const app = express(); const stripe = require('stripe')('<>') app.post('/create-checkout-session', async (req, res) => {const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'http://localhost:4242/success', }); res.redirect(303, session.url); }); app.listen(4242, () => console.log(`Listening on port ${4242}!`)); ``` #### Go ```go package main import ( "net/http" "github.com/labstack/echo" "github.com/labstack/echo/middleware" "github.com/stripe/stripe-go/v76.0.0" "github.com/stripe/stripe-go/v76.0.0/checkout/session" ) // This example sets up an endpoint using the Echo framework. // Watch this video to get started: https://youtu.be/ePmEVBu8w6Y. func main() { stripe.Key = "<>" e := echo.New() e.Use(middleware.Logger()) e.Use(middleware.Recover()) e.POST("/create-checkout-session", createCheckoutSession) e.Logger.Fatal(e.Start("localhost:4242")) } func createCheckoutSession(c echo.Context) (err error) {params := &stripe.CheckoutSessionParams{ Mode: stripe.String(string(stripe.CheckoutSessionModePayment)), LineItems: []*stripe.CheckoutSessionLineItemParams{ &stripe.CheckoutSessionLineItemParams{ PriceData: &stripe.CheckoutSessionLineItemPriceDataParams{ Currency: stripe.String("usd"), ProductData: &stripe.CheckoutSessionLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, SuccessURL: stripe.String("http://localhost:4242/success"), } s, _ := session.New(params) if err != nil { return err } return c.Redirect(http.StatusSeeOther, s.URL) } ``` #### .NET ```dotnet // This example sets up an endpoint using the ASP.NET MVC framework. // Watch this video to get started: https://youtu.be/2-mMOB8MhmE. using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Stripe; using Stripe.Checkout; namespace server.Controllers { public class PaymentsController : Controller { public PaymentsController() { StripeConfiguration.ApiKey = "<>"; } [HttpPost("create-checkout-session")] public ActionResult CreateCheckoutSession() {var options = new SessionCreateOptions { LineItems = new List { new SessionLineItemOptions { PriceData = new SessionLineItemPriceDataOptions { UnitAmount = 2000, Currency = "usd", ProductData = new SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, }, Quantity = 1, }, }, Mode = "payment", SuccessUrl = "http://localhost:4242/success", }; var service = new SessionService(); Session session = service.Create(options); Response.Headers.Add("Location", session.Url); return new StatusCodeResult(303); } } } ``` ### Payment methods By default, Stripe enables cards and other common payment methods. You can turn individual payment methods on or off in the [Stripe Dashboard](https://dashboard.stripe.com/settings/payment_methods). In Checkout, Stripe evaluates the currency and any restrictions, then dynamically presents the supported payment methods to the customer. To see how your payment methods appear to customers, enter a transaction ID or set an order amount and currency in the Dashboard. You can enable Apple Pay and Google Pay in your [payment methods settings](https://dashboard.stripe.com/settings/payment_methods). By default, Apple Pay is enabled and Google Pay is disabled. However, in some cases Stripe filters them out even when they’re enabled. We filter Google Pay if you [enable automatic tax](https://docs.stripe.com/tax/checkout.md) without collecting a shipping address. Checkout’s Stripe-hosted pages don’t need integration changes to enable Apple Pay or Google Pay. Stripe handles these payments the same way as other card payments. ### Confirm your endpoint Confirm your endpoint is accessible by starting your web server (for example, `localhost:4242`) and running the following command: ```bash curl -X POST -is "http://localhost:4242/create-checkout-session" -d "" ``` You should see a response in your terminal that looks like this: ```bash HTTP/1.1 303 See Other Location: https://checkout.stripe.com/c/pay/cs_test_... ... ``` ### Testing You should now have a working checkout button that redirects your customer to Stripe Checkout. 1. Click the checkout button. 1. You’re redirected to the Stripe Checkout payment form. If your integration isn’t working: 1. Open the Network tab in your browser’s developer tools. 1. Click the checkout button and confirm it sent an XHR request to your server-side endpoint (`POST /create-checkout-session`). 1. Verify the request is returning a 200 status. 1. Use `console.log(session)` inside your button click listener to confirm the correct data returned. ## Show a success page [Client-side] [Server-side] It’s important for your customer to see a success page after they successfully submit the payment form. Host this success page on your site. Create a minimal success page: ```html Thanks for your order!

Thanks for your order!

We appreciate your business! If you have any questions, please email orders@example.com.

``` Next, update the Checkout Session creation endpoint to use this new page: ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode success_url="http://localhost:4242/success.html" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --success-url="http://localhost:4242/success.html" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'http://localhost:4242/success.html', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, }, "quantity": 1, }, ], "mode": "payment", "success_url": "http://localhost:4242/success.html", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, ], 'quantity' => 1, ], ], 'mode' => 'payment', 'success_url' => 'http://localhost:4242/success.html', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("http://localhost:4242/success.html") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'http://localhost:4242/success.html', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("http://localhost:4242/success.html"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, }, Quantity = 1, }, }, Mode = "payment", SuccessUrl = "http://localhost:4242/success.html", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` > If you want to customize your success page, read the [custom success page](https://docs.stripe.com/payments/checkout/custom-success-page.md) guide. ### Testing 1. Click your checkout button. 1. Fill out the payment details with the test card information: - Enter `4242 4242 4242 4242` as the card number. - Enter any future date for card expiry. - Enter any 3-digit number for CVC. - Enter any billing postal code. 1. Click **Pay**. 1. You’re redirected to your new success page. Next, find the new payment in the Stripe Dashboard. Successful payments appear in the Dashboard’s [list of payments](https://dashboard.stripe.com/payments). When you click a payment, it takes you to the payment details page. The **Checkout summary** section contains billing information and the list of items purchased, which you can use to manually fulfill the order. ## Handle post-payment events Stripe sends a [checkout.session.completed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) event when a customer completes a Checkout Session payment. Use the [Dashboard webhook tool](https://dashboard.stripe.com/webhooks) or follow the [webhook guide](https://docs.stripe.com/webhooks/quickstart.md) to receive and handle these events, which might trigger you to: - Send an order confirmation email to your customer. - Log the sale in a database. - Start a shipping workflow. Listen for these events rather than waiting for your customer to be redirected back to your website. Triggering fulfillment only from your Checkout landing page is unreliable. Setting up your integration to listen for asynchronous events allows you to accept [different types of payment methods](https://stripe.com/payments/payment-methods-guide) with a single integration. Learn more in our [fulfillment guide for Checkout](https://docs.stripe.com/checkout/fulfillment.md). Handle the following events when collecting payments with the Checkout: | Event | Description | Action | | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [checkout.session.completed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) | Sent when a customer successfully completes a Checkout Session. | Send the customer an order confirmation and *fulfill* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) their order. | | [checkout.session.async_payment_succeeded](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.async_payment_succeeded) | Sent when a payment made with a delayed payment method, such as ACH direct debt, succeeds. | Send the customer an order confirmation and *fulfill* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) their order. | | [checkout.session.async_payment_failed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.async_payment_failed) | Sent when a payment made with a delayed payment method, such as ACH direct debt, fails. | Notify the customer of the failure and bring them back on-session to attempt payment again. | ## Test your integration To test your Stripe-hosted payment form integration: 1. Create a Checkout Session. 1. Fill out the payment details with a method from the following table. - Enter any future date for card expiry. - Enter any 3-digit number for CVC. - Enter any billing postal code. 1. Click **Pay**. You’re redirected to your `success_url`. 1. Go to the Dashboard and look for the payment on the [Transactions page](https://dashboard.stripe.com/test/payments?status%5B0%5D=successful). If your payment succeeded, you’ll see it in that list. 1. Click your payment to see more details, like a Checkout summary with billing information and the list of purchased items. You can use this information to fulfill the order. Learn more about [testing your integration](https://docs.stripe.com/testing.md). #### Cards | Card number | Scenario | How to test | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | 4242424242424242 | The card payment succeeds and doesn’t require authentication. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000002500003155 | The card payment requires *authentication* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase). | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000000000009995 | The card is declined with a decline code like `insufficient_funds`. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 6205500000000000004 | The UnionPay card has a variable length of 13-19 digits. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | #### Wallets | Payment method | Scenario | How to test | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Alipay | Your customer successfully pays with a redirect-based and [immediate notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | #### Bank redirects | Payment method | Scenario | How to test | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | BECS Direct Debit | Your customer successfully pays with BECS Direct Debit. | Fill out the form using the account number `900123456` and BSB `000000`. The confirmed PaymentIntent initially transitions to `processing`, then transitions to the `succeeded` status 3 minutes later. | | BECS Direct Debit | Your customer’s payment fails with an `account_closed` error code. | Fill out the form using the account number `111111113` and BSB `000000`. | | Bancontact, EPS, iDEAL, and Przelewy24 | Your customer fails to authenticate on the redirect page for a redirect-based and immediate notification payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | Pay by Bank | Your customer successfully pays with a redirect-based and [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | | Pay by Bank | Your customer fails to authenticate on the redirect page for a redirect-based and delayed notification payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | BLIK | BLIK payments fail in a variety of ways—immediate failures (for example, the code is expired or invalid), delayed errors (the bank declines) or timeouts (the customer didn’t respond in time). | Use email patterns to [simulate the different failures.](https://docs.stripe.com/payments/blik/accept-a-payment.md#simulate-failures) | #### Bank debits | Payment method | Scenario | How to test | | ----------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SEPA Direct Debit | Your customer successfully pays with SEPA Direct Debit. | Fill out the form using the account number `AT321904300235473204`. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later. | | SEPA Direct Debit | Your customer’s payment intent status transitions from `processing` to `requires_payment_method`. | Fill out the form using the account number `AT861904300235473202`. | #### Vouchers | Payment method | Scenario | How to test | | -------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | Boleto, OXXO | Your customer pays with a Boleto or OXXO voucher. | Select Boleto or OXXO as the payment method and submit the payment. Close the dialog after it appears. | See [Testing](https://docs.stripe.com/testing.md) for additional information to test your integration. ### Test cards | Number | Description | | ------------------- | ------------------------------------------------------------- | | 4242 4242 4242 4242 | Succeeds and immediately processes the payment. | | 4000 0000 0000 3220 | Requires 3D Secure 2 authentication for a successful payment. | | 4000 0000 0000 9995 | Always fails with a decline code of `insufficient_funds`. | ## Optional: Create products and prices Before you create a Checkout Session, you can create *Products* (Products represent what your business sells—whether that's a good or a service) and *Prices* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) upfront. Use products to represent different physical goods or levels of service, and *Prices* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) to represent each product’s pricing. You can [set up your Checkout Session](https://docs.stripe.com/payments/checkout/pay-what-you-want.md) to accept tips and donations, or sell pay-what-you-want products and services. For example, you can create a T-shirt as a product with a price of 20 USD. This allows you to update and add prices without needing to change the details of your underlying products. You can either create products and prices with the Stripe Dashboard or API. Learn more about [how products and prices work](https://docs.stripe.com/products-prices/how-products-and-prices-work.md). #### API The API only requires a `name` to create a [Product](https://docs.stripe.com/api/products.md). Checkout displays the product `name`, `description`, and `images` that you supply. ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ -d name=T-shirt ``` ```cli stripe products create \ --name=T-shirt ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") product = client.v1.products.create({name: 'T-shirt'}) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. product = client.v1.products.create({"name": "T-shirt"}) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $product = $stripe->products->create(['name' => 'T-shirt']); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); ProductCreateParams params = ProductCreateParams.builder().setName("T-shirt").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Product product = client.v1().products().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const product = await stripe.products.create({ name: 'T-shirt', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.ProductCreateParams{Name: stripe.String("T-shirt")} result, err := sc.V1Products.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new ProductCreateOptions { Name = "T-shirt" }; var client = new StripeClient("<>"); var service = client.V1.Products; Product product = service.Create(options); ``` Next, create a [Price](https://docs.stripe.com/api/prices.md) to define how much to charge for your product. This includes how much the product costs and what currency to use. ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product="{{PRODUCT_ID}}" \ -d unit_amount=2000 \ -d currency=usd ``` ```cli stripe prices create \ --product="{{PRODUCT_ID}}" \ --unit-amount=2000 \ --currency=usd ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") price = client.v1.prices.create({ product: '{{PRODUCT_ID}}', unit_amount: 2000, currency: 'usd', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. price = client.v1.prices.create({ "product": "{{PRODUCT_ID}}", "unit_amount": 2000, "currency": "usd", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $price = $stripe->prices->create([ 'product' => '{{PRODUCT_ID}}', 'unit_amount' => 2000, 'currency' => 'usd', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PriceCreateParams params = PriceCreateParams.builder() .setProduct("{{PRODUCT_ID}}") .setUnitAmount(2000L) .setCurrency("usd") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Price price = client.v1().prices().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const price = await stripe.prices.create({ product: '{{PRODUCT_ID}}', unit_amount: 2000, currency: 'usd', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PriceCreateParams{ Product: stripe.String("{{PRODUCT_ID}}"), UnitAmount: stripe.Int64(2000), Currency: stripe.String(stripe.CurrencyUSD), } result, err := sc.V1Prices.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PriceCreateOptions { Product = "{{PRODUCT_ID}}", UnitAmount = 2000, Currency = "usd", }; var client = new StripeClient("<>"); var service = client.V1.Prices; Price price = service.Create(options); ``` #### Dashboard > Copy products created in a sandbox to live mode so that you don’t need to re-create them. In the Product detail view in the Dashboard, click **Copy to live mode** in the upper right corner. You can only do this once for each product created in a sandbox. Subsequent updates to the test product aren’t reflected for the live product. Make sure you’re in a sandbox by clicking **Sandboxes** within the Dashboard account picker. Next, define the items you want to sell. To create a new product and price: - Navigate to the [Products](https://dashboard.stripe.com/test/products) section in the Dashboard. - Click **Add product**. - Select **One time** when setting the price. Checkout displays the product name, description, and images that you supply. Each price you create has an ID. When you create a Checkout Session, reference the price ID and quantity. If you’re selling in multiple currencies, make your Price *multi-currency* (A single Price object can support multiple currencies. Each purchase uses one of the supported currencies for the Price, depending on how you use the Price in your integration). Checkout automatically [determines the customer’s local currency](https://docs.stripe.com/payments/checkout/localize-prices/manual-currency-prices.md) and presents that currency if the Price supports it. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --data-urlencode success_url="https://example.com/success?session_id={CHECKOUT_SESSION_ID}" ``` ```cli stripe checkout sessions create \ --mode=payment \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --success-url="https://example.com/success?session_id={CHECKOUT_SESSION_ID}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'success_url' => 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setSuccessUrl("https://example.com/success?session_id={CHECKOUT_SESSION_ID}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, SuccessURL: stripe.String("https://example.com/success?session_id={CHECKOUT_SESSION_ID}"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, SuccessUrl = "https://example.com/success?session_id={CHECKOUT_SESSION_ID}", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Optional: Prefill customer data [Server-side] If you’ve already collected your customer’s email and want to prefill it in the Checkout Session for them, pass [customer_email](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_email) when creating a Checkout Session. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ --data-urlencode customer_email="customer@example.com" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" ``` ```cli stripe checkout sessions create \ --customer-email="customer@example.com" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --success-url="https://example.com/success" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer_email: 'customer@example.com', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer_email": "customer@example.com", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "payment", "success_url": "https://example.com/success", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer_email' => 'customer@example.com', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'payment', 'success_url' => 'https://example.com/success', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomerEmail("customer@example.com") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer_email: 'customer@example.com', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ CustomerEmail: stripe.String("customer@example.com"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { CustomerEmail = "customer@example.com", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "payment", SuccessUrl = "https://example.com/success", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Optional: Save payment method details [Server-side] By default, payment methods used to make a one-time payment with Checkout aren’t available for future use. ### Save payment methods to charge them off-session You can set Checkout to save payment methods used to make a one-time payment by passing the [payment_intent_data.setup_future_usage](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_intent_data-setup_future_usage) argument. This is useful if you need to capture a payment method on-file to use for future fees, such as cancellation or no-show fees. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d customer_creation=always \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode success_url="https://example.com/success.html" \ -d "payment_intent_data[setup_future_usage]"=off_session ``` ```cli stripe checkout sessions create \ --customer-creation=always \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --success-url="https://example.com/success.html" \ -d "payment_intent_data[setup_future_usage]"=off_session ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer_creation: 'always', line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success.html', payment_intent_data: {setup_future_usage: 'off_session'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer_creation": "always", "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, }, "quantity": 1, }, ], "mode": "payment", "success_url": "https://example.com/success.html", "payment_intent_data": {"setup_future_usage": "off_session"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer_creation' => 'always', 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, ], 'quantity' => 1, ], ], 'mode' => 'payment', 'success_url' => 'https://example.com/success.html', 'payment_intent_data' => ['setup_future_usage' => 'off_session'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomerCreation(SessionCreateParams.CustomerCreation.ALWAYS) .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success.html") .setPaymentIntentData( SessionCreateParams.PaymentIntentData.builder() .setSetupFutureUsage( SessionCreateParams.PaymentIntentData.SetupFutureUsage.OFF_SESSION ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer_creation: 'always', line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success.html', payment_intent_data: { setup_future_usage: 'off_session', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ CustomerCreation: stripe.String(stripe.CheckoutSessionCustomerCreationAlways), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success.html"), PaymentIntentData: &stripe.CheckoutSessionCreatePaymentIntentDataParams{ SetupFutureUsage: stripe.String("off_session"), }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { CustomerCreation = "always", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, }, Quantity = 1, }, }, Mode = "payment", SuccessUrl = "https://example.com/success.html", PaymentIntentData = new Stripe.Checkout.SessionPaymentIntentDataOptions { SetupFutureUsage = "off_session", }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` If you use Checkout in `subscription` mode, Stripe automatically saves the payment method to charge it for subsequent payments. Card payment methods saved to customers using either `setup_future_usage` or `subscription` mode don’t appear for return purchases in Checkout (more on this below). We recommend using [custom text](https://docs.stripe.com/payments/checkout/customization/policies.md) to link out to any relevant terms regarding the usage of saved payment information. > Global privacy laws are complicated and nuanced. We recommend contacting your legal and privacy team prior to implementing [setup_future_usage](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_intent_data-setup_future_usage) because it might implicate your existing privacy compliance framework. Refer to [the guidance issued by the European Protection Board](https://edpb.europa.eu/system/files/2021-05/recommendations022021_on_storage_of_credit_card_data_en_1.pdf) to learn more about saving payment details. ### Save payment methods to prefill them in Checkout By default, Checkout uses [Link](https://docs.stripe.com/payments/link/checkout-link.md) to provide your customers with the option to securely save and reuse their payment information. If you prefer to manage payment methods yourself, use [saved_payment_method_options.payment_method_save](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-saved_payment_method_options-payment_method_save) when creating a Checkout Session to let your customers save their payment methods for future purchases in Checkout. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d customer_creation=always \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode success_url="https://example.com/success.html" \ -d "saved_payment_method_options[payment_method_save]"=enabled ``` ```cli stripe checkout sessions create \ --customer-creation=always \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --success-url="https://example.com/success.html" \ -d "saved_payment_method_options[payment_method_save]"=enabled ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer_creation: 'always', line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success.html', saved_payment_method_options: {payment_method_save: 'enabled'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer_creation": "always", "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, }, "quantity": 1, }, ], "mode": "payment", "success_url": "https://example.com/success.html", "saved_payment_method_options": {"payment_method_save": "enabled"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer_creation' => 'always', 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, ], 'quantity' => 1, ], ], 'mode' => 'payment', 'success_url' => 'https://example.com/success.html', 'saved_payment_method_options' => ['payment_method_save' => 'enabled'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomerCreation(SessionCreateParams.CustomerCreation.ALWAYS) .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success.html") .setSavedPaymentMethodOptions( SessionCreateParams.SavedPaymentMethodOptions.builder() .setPaymentMethodSave( SessionCreateParams.SavedPaymentMethodOptions.PaymentMethodSave.ENABLED ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer_creation: 'always', line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success.html', saved_payment_method_options: { payment_method_save: 'enabled', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ CustomerCreation: stripe.String(stripe.CheckoutSessionCustomerCreationAlways), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success.html"), SavedPaymentMethodOptions: &stripe.CheckoutSessionCreateSavedPaymentMethodOptionsParams{ PaymentMethodSave: stripe.String(stripe.CheckoutSessionSavedPaymentMethodOptionsPaymentMethodSaveEnabled), }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { CustomerCreation = "always", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, }, Quantity = 1, }, }, Mode = "payment", SuccessUrl = "https://example.com/success.html", SavedPaymentMethodOptions = new Stripe.Checkout.SessionSavedPaymentMethodOptionsOptions { PaymentMethodSave = "enabled", }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` Passing this parameter in either [payment](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-mode) or [subscription](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-mode) mode displays an optional checkbox to let customers explicitly save their payment method for future purchases. When customers check this checkbox, Checkout saves the payment method with [allow_redisplay: always](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-allow_redisplay). Checkout uses this parameter to determine whether a payment method can be prefilled on future purchases. When using `saved_payment_method_options.payment_method_save`, you don’t need to pass in `setup_future_usage` to save the payment method. If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. Using [saved_payment_method_options.payment_method_save](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-saved_payment_method_options-payment_method_save) requires a `Customer`. To save a new customer, set the Checkout Session’s [customer_creation](https://docs.stripe.com/api/checkout/sessions/create.md) to `always`. Otherwise, the session doesn’t save the customer or the payment method. If `payment_method_save` isn’t passed in or if the customer doesn’t agree to save the payment method, Checkout still saves payment methods created in `subscription` mode or using `setup_future_usage`. These payment methods have an `allow_redisplay` value of `limited`, which prevents them from being prefilled for returning purchases and allows you to comply with card network rules and data protection regulations. Learn how to [change the default behavior enabled by these modes](https://support.stripe.com/questions/prefilling-saved-cards-in-checkout) and how to change or override `allow_redisplay` behavior. > You can use Checkout to save cards and other payment methods to charge them off-session, but Checkout only prefills saved cards. Learn how to [prefill saved cards](https://support.stripe.com/questions/prefilling-saved-cards-in-checkout). To save a payment method without an initial payment, [use Checkout in setup mode](https://docs.stripe.com/payments/save-and-reuse.md?platform=checkout). ### Let customers remove saved payment methods To let your customers remove a saved payment method so it doesn’t resurface for future payments, use [saved_payment_method_options.payment_method_remove](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-saved_payment_method_options-payment_method_remove) when creating a Checkout Session. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d customer={{CUSTOMER_ID}} \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode success_url="https://example.com/success.html" \ -d "saved_payment_method_options[payment_method_remove]"=enabled ``` ```cli stripe checkout sessions create \ --customer={{CUSTOMER_ID}} \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --success-url="https://example.com/success.html" \ -d "saved_payment_method_options[payment_method_remove]"=enabled ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer: '{{CUSTOMER_ID}}', line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success.html', saved_payment_method_options: {payment_method_remove: 'enabled'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer": "{{CUSTOMER_ID}}", "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, }, "quantity": 1, }, ], "mode": "payment", "success_url": "https://example.com/success.html", "saved_payment_method_options": {"payment_method_remove": "enabled"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer' => '{{CUSTOMER_ID}}', 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, ], 'quantity' => 1, ], ], 'mode' => 'payment', 'success_url' => 'https://example.com/success.html', 'saved_payment_method_options' => ['payment_method_remove' => 'enabled'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success.html") .setSavedPaymentMethodOptions( SessionCreateParams.SavedPaymentMethodOptions.builder().build() ) .putExtraParam("saved_payment_method_options[payment_method_remove]", "enabled") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer: '{{CUSTOMER_ID}}', line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success.html', saved_payment_method_options: { payment_method_remove: 'enabled', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success.html"), SavedPaymentMethodOptions: &stripe.CheckoutSessionCreateSavedPaymentMethodOptionsParams{}, } params.AddExtra("saved_payment_method_options[payment_method_remove]", "enabled") result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Customer = "{{CUSTOMER_ID}}", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, }, Quantity = 1, }, }, Mode = "payment", SuccessUrl = "https://example.com/success.html", SavedPaymentMethodOptions = new Stripe.Checkout.SessionSavedPaymentMethodOptionsOptions(), }; options.AddExtraParam("saved_payment_method_options[payment_method_remove]", "enabled"); var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` The customer can’t remove a payment method if it’s tied to an active subscription and the customer doesn’t have a default payment method saved for invoice and subscription payments. ## Optional: Separate authorization and capture [Server-side] Stripe supports two-step card payments so you can first authorize a card, then capture funds later. When Stripe authorizes a payment, the card issuer guarantees the funds and places a hold for the payment amount on the customer’s card. You then have a certain amount of time to capture the funds, [depending on the card](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md#auth-capture-limitations)). If you don’t capture the payment before the authorization expires, the payment is cancelled and the issuer releases the held funds. Separating authorization and capture is useful if you need to take additional actions between confirming that a customer is able to pay and collecting their payment. For example, if you’re selling stock-limited items, you may need to confirm that an item purchased by your customer using Checkout is still available before capturing their payment and fulfilling the purchase. Accomplish this using the following workflow: 1. Confirm that Stripe authorized the customer’s payment method. 1. Consult your inventory management system to confirm that the item is still available. 1. Update your inventory management system to indicate that a customer has purchased the item. 1. Capture the customer’s payment. 1. Inform your customer whether their purchase was successful on your confirmation page. To indicate that you want to separate authorization and capture, you must set the value of [payment_intent_data.capture_method](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_intent_data-capture_method) to `manual` when creating the Checkout Session. This instructs Stripe to only authorize the amount on the customer’s card. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d "payment_intent_data[capture_method]"=manual \ --data-urlencode success_url="https://example.com/success.html" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --mode=payment \ -d "payment_intent_data[capture_method]"=manual \ --success-url="https://example.com/success.html" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', payment_intent_data: {capture_method: 'manual'}, success_url: 'https://example.com/success.html', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "payment", "payment_intent_data": {"capture_method": "manual"}, "success_url": "https://example.com/success.html", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'payment', 'payment_intent_data' => ['capture_method' => 'manual'], 'success_url' => 'https://example.com/success.html', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setPaymentIntentData( SessionCreateParams.PaymentIntentData.builder() .setCaptureMethod(SessionCreateParams.PaymentIntentData.CaptureMethod.MANUAL) .build() ) .setSuccessUrl("https://example.com/success.html") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', payment_intent_data: { capture_method: 'manual', }, success_url: 'https://example.com/success.html', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), PaymentIntentData: &stripe.CheckoutSessionCreatePaymentIntentDataParams{ CaptureMethod: stripe.String("manual"), }, SuccessURL: stripe.String("https://example.com/success.html"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "payment", PaymentIntentData = new Stripe.Checkout.SessionPaymentIntentDataOptions { CaptureMethod = "manual", }, SuccessUrl = "https://example.com/success.html", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` To capture an uncaptured payment, you can use either the [Dashboard](https://dashboard.stripe.com/test/payments?status%5B%5D=uncaptured) or the [capture](https://docs.stripe.com/api/payment_intents/capture.md) endpoint. Programmatically capturing payments requires access to the PaymentIntent created during the Checkout Session, which you can get from the [Session](https://docs.stripe.com/api/payment_intents/capture.md) object. ## Optional: Customer account management [No code] Let your customers [manage](https://docs.stripe.com/customer-management.md) their own accounts by sharing a link to your *customer portal* (The customer portal is a secure, Stripe-hosted page that lets your customers manage their subscriptions and billing details). The customer portal lets customers log in with their email to manage subscriptions, update payment methods, and so on. ## See also - [Add discounts](https://docs.stripe.com/payments/checkout/discounts.md) - [Collect taxes](https://docs.stripe.com/payments/checkout/taxes.md) - [Collect tax IDs](https://docs.stripe.com/tax/checkout/tax-ids.md) - [Add shipping](https://docs.stripe.com/payments/collect-addresses.md?payment-ui=checkout) - [Customize your branding](https://docs.stripe.com/payments/checkout/customization.md) # Embedded form > This is a Embedded form for when payment-ui is checkout and ui is embedded-form. View the full page at https://docs.stripe.com/payments/accept-a-payment?payment-ui=checkout&ui=embedded-form. Embed a prebuilt payment form on your site using [Stripe Checkout](https://docs.stripe.com/payments/checkout.md). See how this integration [compares to Stripe’s other integration types](https://docs.stripe.com/payments/online-payments.md#compare-features-and-availability). #### Integration effort Complexity: 2/5 #### Integration type Embed prebuilt payment form on your site #### UI customization Limited customization - 20 preset fonts - 3 preset border radius - Custom background and border color - Custom logo Use the [branding settings](https://dashboard.stripe.com/settings/branding/checkout) in the Stripe Dashboard to match Checkout to your site design. First, [register](https://dashboard.stripe.com/register) for a Stripe account. Use our official libraries to access the Stripe API from your application: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` #### Python ```bash # Install through pip pip3 install --upgrade stripe ``` ```bash # Or find the Stripe package on http://pypi.python.org/pypi/stripe/ ``` ```python # Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=5.0.0 ``` #### PHP ```bash # Install the PHP library with Composer composer require stripe/stripe-php ``` ```bash # Or download the source directly: https://github.com/stripe/stripe-php/releases ``` #### Java ```java /* For Gradle, add the following dependency to your build.gradle and replace with the version number you want to use from: - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:31.3.0" ``` ```xml com.stripe stripe-java 31.3.0 ``` ```bash # For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson ``` #### Node.js ```bash # Install with npm npm install stripe --save ``` #### Go ```bash # Make sure your project is using Go Modules go mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v84 ``` ```go // Then import the package import ( "github.com/stripe/stripe-go/v84" ) ``` #### .NET ```bash # Install with dotnet dotnet add package Stripe.net dotnet restore ``` ```bash # Or install with NuGet Install-Package Stripe.net ``` ## Create a Checkout Session [Server-side] From your server, create a *Checkout Session* (A Checkout Session represents your customer's session as they pay for one-time purchases or subscriptions through Checkout. After a successful payment, the Checkout Session contains a reference to the Customer, and either the successful PaymentIntent or an active Subscription) and set the [ui_mode](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-ui_mode) to `embedded`. You can configure the [Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md) with [line items](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items) to include and options such as [currency](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-currency). You can also create a Checkout Session for an [existing customer](https://docs.stripe.com/payments/existing-customers.md?platform=web&ui=stripe-hosted), allowing you to prefill Checkout fields with known contact information and unify your purchase history for that customer. To return customers to a custom page that you host on your website, specify that page’s URL in the [return_url](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-return_url) parameter. Include the `{CHECKOUT_SESSION_ID}` template variable in the URL to retrieve the session’s status on the return page. Checkout automatically substitutes the variable with the Checkout Session ID before redirecting. Read more about [configuring the return page](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=checkout&ui=embedded-form#return-page) and other options for [customizing redirect behavior](https://docs.stripe.com/payments/checkout/custom-success-page.md?payment-ui=embedded-form). After you create the Checkout Session, use the `client_secret` returned in the response to [mount Checkout](https://docs.stripe.com/payments/accept-a-payment.md#mount-checkout). #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. # To learn more about Sinatra, watch this video: https://youtu.be/8aA9Enb8NVc. require 'json' require 'sinatra' require 'stripe' # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' post '/create-checkout-session' do session = Stripe::Checkout::Session.create({ line_items: [{ price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }], mode: 'payment',ui_mode: 'embedded', return_url: 'https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}' }) {clientSecret: session.client_secret}.to_json end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # To learn more about Flask, watch this video: https://youtu.be/7Ul1vfsmsDck. import os import stripe from flask import Flask, redirect app = Flask(__name__) stripe.api_key = '<>' @app.route('/create-checkout-session', methods=['POST']) def create_checkout_session(): session = stripe.checkout.Session.create( line_items = [{ 'price_data': { 'currency': 'usd', 'product_data': { 'name': 'T-shirt', }, 'unit_amount': 2000, }, 'quantity': 1, }], mode = 'payment',ui_mode = 'embedded', return_url = 'https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}', ) return jsonify(clientSecret=session.client_secret) if __name__ == '__main__': app.run(port=4242) ``` #### PHP ```php '<>' ]); $checkout_session = $stripe->checkout->sessions->create([ 'line_items' => [[ 'price_data' => [ 'currency' => 'usd', 'product_data' => [ 'name' => 'T-shirt', ], 'unit_amount' => 2000, ], 'quantity' => 1, ]], 'mode' => 'payment','ui_mode' => 'embedded', 'return_url' => 'https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}', ]); echo json_encode(array('clientSecret' => $checkout_session->client_secret)); ?> ``` #### Java ```java import java.util.HashMap; import java.util.Map; import static spark.Spark.get; import static spark.Spark.post; import static spark.Spark.port; import static spark.Spark.staticFiles; import com.google.gson.Gson; import com.stripe.Stripe; import com.stripe.model.checkout.Session; import com.stripe.param.checkout.SessionCreateParams; public class Server { public static void main(String[] args) { port(4242); Stripe.apiKey = "<>"; Gson gson = new Gson(); post("/create-checkout-session", (request, response) -> { SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT).setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return?session_id={CHECKOUT_SESSION_ID}") .addLineItem( SessionCreateParams.LineItem.builder() .setQuantity(1L) .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setUnitAmount(2000L) .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build()) .build()) .build()) .build(); Session session = Session.create(params); Map map = new HashMap(); map.put("clientSecret", session.getRawJsonObject().getAsJsonPrimitive("client_secret").getAsString()); return map; }, gson::toJson); } } ``` #### Node.js ```javascript // This example sets up an endpoint using the Express framework. const express = require('express'); const app = express(); const stripe = require('stripe')('<>'); app.post('/create-checkout-session', async (req, res) => { const session = await stripe.checkout.sessions.create({ line_items: [{ price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }], mode: 'payment',ui_mode: 'embedded', return_url: 'https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}' }); res.send({clientSecret: session.client_secret}); }); app.listen(4242, () => console.log(`Listening on port ${4242}!`)); ``` #### Go ```go package main import ( "net/http" "github.com/labstack/echo" "github.com/labstack/echo/middleware" "github.com/stripe/stripe-go/v76.0.0" "github.com/stripe/stripe-go/v76.0.0/checkout/session" ) // This example sets up an endpoint using the Echo framework. // To learn more about Echo, watch this video: https://youtu.be/ePmEVBu8w6Y. func main() { stripe.Key = "<>" e := echo.New() e.Use(middleware.Logger()) e.Use(middleware.Recover()) e.POST("/create-checkout-session", createCheckoutSession) e.Logger.Fatal(e.Start("localhost:4242")) } type CheckoutData struct { ClientSecret string `json:"clientSecret"` } func createCheckoutSession(c echo.Context) (err error) { params := &stripe.CheckoutSessionParams{ Mode: stripe.String(string(stripe.CheckoutSessionModePayment)),UIMode: stripe.String("embedded"), ReturnURL: stripe.String("https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}"), LineItems: []*stripe.CheckoutSessionLineItemParams{ &stripe.CheckoutSessionLineItemParams{ PriceData: &stripe.CheckoutSessionLineItemPriceDataParams{ Currency: stripe.String("usd"), ProductData: &stripe.CheckoutSessionLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, } s, _ := session.New(params) if err != nil { return err } data := CheckoutData{ ClientSecret: s.ClientSecret, } return c.JSON(http.StatusOK, data) } ``` #### .NET ```dotnet // This example sets up an endpoint using the ASP.NET MVC framework. // To learn more about ASP.NET MVC, watch this video: https://youtu.be/2-mMOB8MhmE. using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Stripe; using Stripe.Checkout; namespace server.Controllers { public class PaymentsController : Controller { public PaymentsController() { StripeConfiguration.ApiKey = "<>"; } [HttpPost("create-checkout-session")] public ActionResult CreateCheckoutSession() { var options = new SessionCreateOptions { LineItems = new List { new SessionLineItemOptions { PriceData = new SessionLineItemPriceDataOptions { UnitAmount = 2000, Currency = "usd", ProductData = new SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, }, Quantity = 1, }, }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return?session_id={CHECKOUT_SESSION_ID}", }; var service = new SessionService(); Session session = service.Create(options); return Json(new {clientSecret = session.ClientSecret}); } } } ``` ## Mount Checkout [Client-side] #### HTML + JS Checkout is available as part of [Stripe.js](https://docs.stripe.com/js.md). Include the Stripe.js script on your page by adding it to the head of your HTML file. Next, create an empty DOM node (container) to use for mounting. ```html
``` Initialize Stripe.js with your publishable API key. Create an asynchronous `fetchClientSecret` function that makes a request to your server to create the Checkout Session and retrieve the client secret. Pass this function into `options` when you create the Checkout instance: ```javascript // Initialize Stripe.js const stripe = Stripe('<>'); initialize(); // Fetch Checkout Session and retrieve the client secret async function initialize() { const fetchClientSecret = async () => { const response = await fetch("/create-checkout-session", { method: "POST", }); const { clientSecret } = await response.json(); return clientSecret; }; // Initialize Checkout const checkout = await stripe.initEmbeddedCheckout({ fetchClientSecret, }); // Mount Checkout checkout.mount('#checkout'); } ``` #### React Install [react-stripe-js](https://docs.stripe.com/sdks/stripejs-react.md) and the Stripe.js loader from npm: ```bash npm install --save @stripe/react-stripe-js @stripe/stripe-js ``` To use the Embedded Checkout component, create an `EmbeddedCheckoutProvider`. Call `loadStripe` with your publishable API key and pass the returned `Promise` to the provider. Create an asynchronous `fetchClientSecret` function that makes a request to your server to create the Checkout Session and retrieve the client secret. Pass this function into the `options` prop accepted by the provider. ```jsx import * as React from 'react'; import {loadStripe} from '@stripe/stripe-js'; import { EmbeddedCheckoutProvider, EmbeddedCheckout } from '@stripe/react-stripe-js'; // Make sure to call `loadStripe` outside of a component’s render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe('pk_test_123'); const App = () => { const fetchClientSecret = useCallback(() => { // Create a Checkout Session return fetch("/create-checkout-session", { method: "POST", }) .then((res) => res.json()) .then((data) => data.clientSecret); }, []); const options = {fetchClientSecret}; return (
) } ``` Checkout renders in an iframe that securely sends payment information to Stripe over an HTTPS connection. > Avoid placing Checkout within another iframe because some payment methods require redirecting to another page for payment confirmation. ### Customize appearance Customize Checkout to match the design of your site by setting the background color, button color, border radius, and fonts in your account’s [branding settings](https://dashboard.stripe.com/settings/branding). By default, Checkout renders with no external padding or margin. We recommend using a container element such as a div to apply your desired margin (for example, 16px on all sides). ## Show a return page After your customer attempts payment, Stripe redirects them to a return page that you host on your site. When you created the Checkout Session, you specified the URL of the return page in the [return_url](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-return_url) parameter. Read more about other options for [customizing redirect behavior](https://docs.stripe.com/payments/checkout/custom-success-page.md?payment-ui=embedded-form). When rendering your return page, retrieve the Checkout Session status using the Checkout Session ID in the URL. Handle the result according to the session status as follows: - `complete`: The payment succeeded. Use the information from the Checkout Session to render a success page. - `open`: The payment failed or was canceled. Remount Checkout so that your customer can try again. #### Ruby ```ruby get '/session-status' do session = Stripe::Checkout::Session.retrieve(params[:session_id]) {status: session.status, customer_email: session.customer_details.email}.to_json end ``` #### Python ```python @app.route('/session-status', methods=['GET']) def session_status(): session = stripe.checkout.Session.retrieve(request.args.get('session_id')) return jsonify(status=session.status, customer_email=session.customer_details.email) ``` #### PHP ```php try { // retrieve JSON from POST body $jsonStr = file_get_contents('php://input'); $jsonObj = json_decode($jsonStr); $session = $stripe->checkout->sessions->retrieve($jsonObj->session_id); echo json_encode(['status' => $session->status, 'customer_email' => $session->customer_details->email]); http_response_code(200); } catch (Error $e) { http_response_code(500); echo json_encode(['error' => $e->getMessage()]); } ``` #### Java ```java get("/session-status", (request, response) -> { Session session = Session.retrieve(request.queryParams("session_id")); Map map = new HashMap(); map.put("status", session.getRawJsonObject().getAsJsonPrimitive("status").getAsString()); map.put("customer_email", session.getRawJsonObject().getAsJsonObject("customer_details").getAsJsonPrimitive("email").getAsString()); return map; }, gson::toJson); ``` #### Node.js ```javascript app.get('/session_status', async (req, res) => { const session = await stripe.checkout.sessions.retrieve(req.query.session_id); res.send({ status: session.status, payment_status: session.payment_status, customer_email: session.customer_details.email }); }); ``` #### Go ```go func retrieveCheckoutSession(w http.ResponseWriter, r *http.Request) { s, _ := session.Get(r.URL.Query().Get("session_id"), nil) writeJSON(w, struct { Status string `json:"status"` CustomerEmail string `json:"customer_email"` }{ Status: string(s.Status), CustomerEmail: string(s.CustomerDetails.Email), }) } ``` #### .NET ```dotnet [Route("session-status")] [ApiController] public class SessionStatusController : Controller { [HttpGet] public ActionResult SessionStatus([FromQuery] string session_id) { var sessionService = new SessionService(); Session session = sessionService.Get(session_id); return Json(new {status = session.Status, customer_email = session.CustomerDetails.Email}); } } ``` ```javascript const session = await fetch(`/session_status?session_id=${session_id}`) if (session.status == 'open') { // Remount embedded Checkout } else if (session.status == 'complete') { // Show success page // Optionally use session.payment_status or session.customer_email // to customize the success page } ``` #### Redirect-based payment methods During payment, some payment methods redirect the customer to an intermediate page, such as a bank authorization page. When they complete that page, Stripe redirects them to your return page. Learn more about [redirect-based payment methods and redirect behavior](https://docs.stripe.com/payments/checkout/custom-success-page.md?payment-ui=embedded-form#redirect-based-payment-methods). ## Handle post-payment events Stripe sends a [checkout.session.completed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) event when a customer completes a Checkout Session payment. Use the [Dashboard webhook tool](https://dashboard.stripe.com/webhooks) or follow the [webhook guide](https://docs.stripe.com/webhooks/quickstart.md) to receive and handle these events, which might trigger you to: - Send an order confirmation email to your customer. - Log the sale in a database. - Start a shipping workflow. Listen for these events rather than waiting for your customer to be redirected back to your website. Triggering fulfillment only from your Checkout landing page is unreliable. Setting up your integration to listen for asynchronous events allows you to accept [different types of payment methods](https://stripe.com/payments/payment-methods-guide) with a single integration. Learn more in our [fulfillment guide for Checkout](https://docs.stripe.com/checkout/fulfillment.md). Handle the following events when collecting payments with the Checkout: | Event | Description | Action | | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [checkout.session.completed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) | Sent when a customer successfully completes a Checkout Session. | Send the customer an order confirmation and *fulfill* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) their order. | | [checkout.session.async_payment_succeeded](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.async_payment_succeeded) | Sent when a payment made with a delayed payment method, such as ACH direct debt, succeeds. | Send the customer an order confirmation and *fulfill* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) their order. | | [checkout.session.async_payment_failed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.async_payment_failed) | Sent when a payment made with a delayed payment method, such as ACH direct debt, fails. | Notify the customer of the failure and bring them back on-session to attempt payment again. | ## Test your integration To test your embedded payment form integration: 1. Create an embedded Checkout Session and mount the payment form on your page. 1. Fill out the payment details with a method from the table below. - Enter any future date for card expiry. - Enter any 3-digit number for CVC. - Enter any billing postal code. 1. Click **Pay**. You’re redirected to your `return_url`. 1. Go to the Dashboard and look for the payment on the [Transactions page](https://dashboard.stripe.com/test/payments?status%5B0%5D=successful). If your payment succeeded, you’ll see it in that list. 1. Click your payment to see more details, like a Checkout summary with billing information and the list of purchased items. You can use this information to fulfill the order. Learn more about [testing your integration](https://docs.stripe.com/testing.md). #### Cards | Card number | Scenario | How to test | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | 4242424242424242 | The card payment succeeds and doesn’t require authentication. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000002500003155 | The card payment requires *authentication* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase). | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000000000009995 | The card is declined with a decline code like `insufficient_funds`. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 6205500000000000004 | The UnionPay card has a variable length of 13-19 digits. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | #### Wallets | Payment method | Scenario | How to test | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Alipay | Your customer successfully pays with a redirect-based and [immediate notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | #### Bank redirects | Payment method | Scenario | How to test | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | BECS Direct Debit | Your customer successfully pays with BECS Direct Debit. | Fill out the form using the account number `900123456` and BSB `000000`. The confirmed PaymentIntent initially transitions to `processing`, then transitions to the `succeeded` status 3 minutes later. | | BECS Direct Debit | Your customer’s payment fails with an `account_closed` error code. | Fill out the form using the account number `111111113` and BSB `000000`. | | Bancontact, EPS, iDEAL, and Przelewy24 | Your customer fails to authenticate on the redirect page for a redirect-based and immediate notification payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | Pay by Bank | Your customer successfully pays with a redirect-based and [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | | Pay by Bank | Your customer fails to authenticate on the redirect page for a redirect-based and delayed notification payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | BLIK | BLIK payments fail in a variety of ways—immediate failures (for example, the code is expired or invalid), delayed errors (the bank declines) or timeouts (the customer didn’t respond in time). | Use email patterns to [simulate the different failures.](https://docs.stripe.com/payments/blik/accept-a-payment.md#simulate-failures) | #### Bank debits | Payment method | Scenario | How to test | | ----------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SEPA Direct Debit | Your customer successfully pays with SEPA Direct Debit. | Fill out the form using the account number `AT321904300235473204`. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later. | | SEPA Direct Debit | Your customer’s payment intent status transitions from `processing` to `requires_payment_method`. | Fill out the form using the account number `AT861904300235473202`. | #### Vouchers | Payment method | Scenario | How to test | | -------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | Boleto, OXXO | Your customer pays with a Boleto or OXXO voucher. | Select Boleto or OXXO as the payment method and submit the payment. Close the dialog after it appears. | See [Testing](https://docs.stripe.com/testing.md) for additional information to test your integration. ## Optional: Add more payment methods By default, Checkout [supports many payment methods](https://docs.stripe.com/payments/payment-methods/integration-options.md#choose-how-to-add-payment-methods). You have to take additional steps to enable and display some methods, like Apple Pay, Google Pay, and buy now, pay later methods. ### Apple Pay and Google Pay To accept payments from Apple Pay and Google Pay, you must: - Enable them in your [payment methods settings](https://dashboard.stripe.com/settings/payment_methods). Apple Pay is enabled by default. - Serve your application over HTTPS in development and production. - [Register your domain](https://docs.stripe.com/payments/payment-methods/pmd-registration.md). - Serve your application over HTTPS in development and production. You can use a service like [ngrok](https://ngrok.com/) to serve your application for local testing. In addition, a Checkout Session only displays the Apple Pay button to customers when *all* of the following conditions are true: - The customer’s device is running macOS version 17 or later or iOS version 17 or later. - The customer is using the Safari browser. - The customer has a valid card registered with Apple Pay. A Checkout Session only displays the Google Pay button to customers when *all* of the following conditions are true: - The customer’s device is running Chrome 61 or newer. - The customer has a valid card registered with Google Pay. > #### Regional testing > > Stripe Checkout doesn’t support Apple Pay or Google Pay for Stripe accounts or customers in India. If your IP address is in India, you can’t test your Apple Pay or Google Pay integration, even if the Stripe account is outside India. ## Optional: Create products and prices Before you create a Checkout Session, you can create *Products* (Products represent what your business sells—whether that's a good or a service) and *Prices* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) upfront. Use products to represent different physical goods or levels of service, and *Prices* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) to represent each product’s pricing. You can [set up your Checkout Session](https://docs.stripe.com/payments/checkout/pay-what-you-want.md) to accept tips and donations, or sell pay-what-you-want products and services. For example, you can create a T-shirt as a product with a price of 20 USD. This allows you to update and add prices without needing to change the details of your underlying products. You can either create products and prices with the Stripe Dashboard or API. Learn more about [how products and prices work](https://docs.stripe.com/products-prices/how-products-and-prices-work.md). #### API The API only requires a `name` to create a [Product](https://docs.stripe.com/api/products.md). Checkout displays the product `name`, `description`, and `images` that you supply. ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ -d name=T-shirt ``` ```cli stripe products create \ --name=T-shirt ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") product = client.v1.products.create({name: 'T-shirt'}) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. product = client.v1.products.create({"name": "T-shirt"}) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $product = $stripe->products->create(['name' => 'T-shirt']); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); ProductCreateParams params = ProductCreateParams.builder().setName("T-shirt").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Product product = client.v1().products().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const product = await stripe.products.create({ name: 'T-shirt', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.ProductCreateParams{Name: stripe.String("T-shirt")} result, err := sc.V1Products.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new ProductCreateOptions { Name = "T-shirt" }; var client = new StripeClient("<>"); var service = client.V1.Products; Product product = service.Create(options); ``` Next, create a [Price](https://docs.stripe.com/api/prices.md) to define how much to charge for your product. This includes how much the product costs and what currency to use. ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product="{{PRODUCT_ID}}" \ -d unit_amount=2000 \ -d currency=usd ``` ```cli stripe prices create \ --product="{{PRODUCT_ID}}" \ --unit-amount=2000 \ --currency=usd ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") price = client.v1.prices.create({ product: '{{PRODUCT_ID}}', unit_amount: 2000, currency: 'usd', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. price = client.v1.prices.create({ "product": "{{PRODUCT_ID}}", "unit_amount": 2000, "currency": "usd", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $price = $stripe->prices->create([ 'product' => '{{PRODUCT_ID}}', 'unit_amount' => 2000, 'currency' => 'usd', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PriceCreateParams params = PriceCreateParams.builder() .setProduct("{{PRODUCT_ID}}") .setUnitAmount(2000L) .setCurrency("usd") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Price price = client.v1().prices().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const price = await stripe.prices.create({ product: '{{PRODUCT_ID}}', unit_amount: 2000, currency: 'usd', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PriceCreateParams{ Product: stripe.String("{{PRODUCT_ID}}"), UnitAmount: stripe.Int64(2000), Currency: stripe.String(stripe.CurrencyUSD), } result, err := sc.V1Prices.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PriceCreateOptions { Product = "{{PRODUCT_ID}}", UnitAmount = 2000, Currency = "usd", }; var client = new StripeClient("<>"); var service = client.V1.Prices; Price price = service.Create(options); ``` #### Dashboard > Copy products created in a sandbox to live mode so that you don’t need to re-create them. In the Product detail view in the Dashboard, click **Copy to live mode** in the upper right corner. You can only do this once for each product created in a sandbox. Subsequent updates to the test product aren’t reflected for the live product. Make sure you’re in a sandbox by clicking **Sandboxes** within the Dashboard account picker. Next, define the items you want to sell. To create a new product and price: - Navigate to the [Products](https://dashboard.stripe.com/test/products) section in the Dashboard. - Click **Add product**. - Select **One time** when setting the price. Checkout displays the product name, description, and images that you supply. Each price you create has an ID. When you create a Checkout Session, reference the price ID and quantity. If you’re selling in multiple currencies, make your Price *multi-currency* (A single Price object can support multiple currencies. Each purchase uses one of the supported currencies for the Price, depending on how you use the Price in your integration). Checkout automatically [determines the customer’s local currency](https://docs.stripe.com/payments/checkout/localize-prices/manual-currency-prices.md) and presents that currency if the Price supports it. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" ``` ```cli stripe checkout sessions create \ --mode=payment \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --ui-mode=embedded \ --return-url="https://example.com/return" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], ui_mode: 'embedded', return_url: 'https://example.com/return', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "ui_mode": "embedded", "return_url": "https://example.com/return", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], ui_mode: 'embedded', return_url: 'https://example.com/return', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, UiMode = "embedded", ReturnUrl = "https://example.com/return", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Optional: Prefill customer data [Server-side] If you’ve already collected your customer’s email and want to prefill it in the Checkout Session for them, pass [customer_email](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_email) when creating a Checkout Session. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ --data-urlencode customer_email="customer@example.com" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" ``` ```cli stripe checkout sessions create \ --customer-email="customer@example.com" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer_email: 'customer@example.com', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer_email": "customer@example.com", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer_email' => 'customer@example.com', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomerEmail("customer@example.com") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer_email: 'customer@example.com', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ CustomerEmail: stripe.String("customer@example.com"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { CustomerEmail = "customer@example.com", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Optional: Save payment method details [Server-side] By default, payment methods used to make a one-time payment with Checkout aren’t available for future use. ### Save payment methods to charge them off-session You can set Checkout to save payment methods used to make a one-time payment by passing the [payment_intent_data.setup_future_usage](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_intent_data-setup_future_usage) argument. This is useful if you need to capture a payment method on-file to use for future fees, such as cancellation or no-show fees. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d customer_creation=always \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" \ -d "payment_intent_data[setup_future_usage]"=off_session ``` ```cli stripe checkout sessions create \ --customer-creation=always \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" \ -d "payment_intent_data[setup_future_usage]"=off_session ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer_creation: 'always', line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', payment_intent_data: {setup_future_usage: 'off_session'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer_creation": "always", "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, }, "quantity": 1, }, ], "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", "payment_intent_data": {"setup_future_usage": "off_session"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer_creation' => 'always', 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, ], 'quantity' => 1, ], ], 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', 'payment_intent_data' => ['setup_future_usage' => 'off_session'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomerCreation(SessionCreateParams.CustomerCreation.ALWAYS) .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .setPaymentIntentData( SessionCreateParams.PaymentIntentData.builder() .setSetupFutureUsage( SessionCreateParams.PaymentIntentData.SetupFutureUsage.OFF_SESSION ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer_creation: 'always', line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', payment_intent_data: { setup_future_usage: 'off_session', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ CustomerCreation: stripe.String(stripe.CheckoutSessionCustomerCreationAlways), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), PaymentIntentData: &stripe.CheckoutSessionCreatePaymentIntentDataParams{ SetupFutureUsage: stripe.String("off_session"), }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { CustomerCreation = "always", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, }, Quantity = 1, }, }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", PaymentIntentData = new Stripe.Checkout.SessionPaymentIntentDataOptions { SetupFutureUsage = "off_session", }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` If you use Checkout in `subscription` mode, Stripe automatically saves the payment method to charge it for subsequent payments. Card payment methods saved to customers using either `setup_future_usage` or `subscription` mode don’t appear for return purchases in Checkout (more on this below). We recommend using [custom text](https://docs.stripe.com/payments/checkout/customization/policies.md) to link out to any relevant terms regarding the usage of saved payment information. > Global privacy laws are complicated and nuanced. We recommend contacting your legal and privacy team prior to implementing [setup_future_usage](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_intent_data-setup_future_usage) because it might implicate your existing privacy compliance framework. Refer to [the guidance issued by the European Protection Board](https://edpb.europa.eu/system/files/2021-05/recommendations022021_on_storage_of_credit_card_data_en_1.pdf) to learn more about saving payment details. ### Save payment methods to prefill them in Checkout By default, Checkout uses [Link](https://docs.stripe.com/payments/link/checkout-link.md) to provide your customers with the option to securely save and reuse their payment information. If you prefer to manage payment methods yourself, use [saved_payment_method_options.payment_method_save](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-saved_payment_method_options-payment_method_save) when creating a Checkout Session to let your customers save their payment methods for future purchases in Checkout. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d customer_creation=always \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" \ -d "saved_payment_method_options[payment_method_save]"=enabled ``` ```cli stripe checkout sessions create \ --customer-creation=always \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" \ -d "saved_payment_method_options[payment_method_save]"=enabled ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer_creation: 'always', line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', saved_payment_method_options: {payment_method_save: 'enabled'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer_creation": "always", "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, }, "quantity": 1, }, ], "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", "saved_payment_method_options": {"payment_method_save": "enabled"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer_creation' => 'always', 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, ], 'quantity' => 1, ], ], 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', 'saved_payment_method_options' => ['payment_method_save' => 'enabled'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomerCreation(SessionCreateParams.CustomerCreation.ALWAYS) .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .setSavedPaymentMethodOptions( SessionCreateParams.SavedPaymentMethodOptions.builder() .setPaymentMethodSave( SessionCreateParams.SavedPaymentMethodOptions.PaymentMethodSave.ENABLED ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer_creation: 'always', line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', saved_payment_method_options: { payment_method_save: 'enabled', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ CustomerCreation: stripe.String(stripe.CheckoutSessionCustomerCreationAlways), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), SavedPaymentMethodOptions: &stripe.CheckoutSessionCreateSavedPaymentMethodOptionsParams{ PaymentMethodSave: stripe.String(stripe.CheckoutSessionSavedPaymentMethodOptionsPaymentMethodSaveEnabled), }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { CustomerCreation = "always", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, }, Quantity = 1, }, }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", SavedPaymentMethodOptions = new Stripe.Checkout.SessionSavedPaymentMethodOptionsOptions { PaymentMethodSave = "enabled", }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` Passing this parameter in either [payment](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-mode) or [subscription](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-mode) mode displays an optional checkbox to let customers explicitly save their payment method for future purchases. When customers check this checkbox, Checkout saves the payment method with [allow_redisplay: always](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-allow_redisplay). Checkout uses this parameter to determine whether a payment method can be prefilled on future purchases. When using `saved_payment_method_options.payment_method_save`, you don’t need to pass in `setup_future_usage` to save the payment method. If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. Using [saved_payment_method_options.payment_method_save](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-saved_payment_method_options-payment_method_save) requires a `Customer`. To save a new customer, set the Checkout Session’s [customer_creation](https://docs.stripe.com/api/checkout/sessions/create.md) to `always`. Otherwise, the session doesn’t save the customer or the payment method. If `payment_method_save` isn’t passed in or if the customer doesn’t agree to save the payment method, Checkout still saves payment methods created in `subscription` mode or using `setup_future_usage`. These payment methods have an `allow_redisplay` value of `limited`, which prevents them from being prefilled for returning purchases and allows you to comply with card network rules and data protection regulations. Learn how to [change the default behavior enabled by these modes](https://support.stripe.com/questions/prefilling-saved-cards-in-checkout) and how to change or override `allow_redisplay` behavior. > You can use Checkout to save cards and other payment methods to charge them off-session, but Checkout only prefills saved cards. Learn how to [prefill saved cards](https://support.stripe.com/questions/prefilling-saved-cards-in-checkout). To save a payment method without an initial payment, [use Checkout in setup mode](https://docs.stripe.com/payments/save-and-reuse.md?platform=checkout). ### Let customers remove saved payment methods To let your customers remove a saved payment method so it doesn’t resurface for future payments, use [saved_payment_method_options.payment_method_remove](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-saved_payment_method_options-payment_method_remove) when creating a Checkout Session. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d customer={{CUSTOMER_ID}} \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" \ -d "saved_payment_method_options[payment_method_remove]"=enabled ``` ```cli stripe checkout sessions create \ --customer={{CUSTOMER_ID}} \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" \ -d "saved_payment_method_options[payment_method_remove]"=enabled ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer: '{{CUSTOMER_ID}}', line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', saved_payment_method_options: {payment_method_remove: 'enabled'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer": "{{CUSTOMER_ID}}", "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, }, "quantity": 1, }, ], "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", "saved_payment_method_options": {"payment_method_remove": "enabled"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer' => '{{CUSTOMER_ID}}', 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, ], 'quantity' => 1, ], ], 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', 'saved_payment_method_options' => ['payment_method_remove' => 'enabled'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .setSavedPaymentMethodOptions( SessionCreateParams.SavedPaymentMethodOptions.builder().build() ) .putExtraParam("saved_payment_method_options[payment_method_remove]", "enabled") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer: '{{CUSTOMER_ID}}', line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', saved_payment_method_options: { payment_method_remove: 'enabled', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), SavedPaymentMethodOptions: &stripe.CheckoutSessionCreateSavedPaymentMethodOptionsParams{}, } params.AddExtra("saved_payment_method_options[payment_method_remove]", "enabled") result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Customer = "{{CUSTOMER_ID}}", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, }, Quantity = 1, }, }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", SavedPaymentMethodOptions = new Stripe.Checkout.SessionSavedPaymentMethodOptionsOptions(), }; options.AddExtraParam("saved_payment_method_options[payment_method_remove]", "enabled"); var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` The customer can’t remove a payment method if it’s tied to an active subscription and the customer doesn’t have a default payment method saved for invoice and subscription payments. ## Optional: Customer account management [No code] Let your customers [manage](https://docs.stripe.com/customer-management.md) their own accounts by sharing a link to your *customer portal* (The customer portal is a secure, Stripe-hosted page that lets your customers manage their subscriptions and billing details). The customer portal lets customers log in with their email to manage subscriptions, update payment methods, and so on. ## Optional: Separate authorization and capture [Server-side] Stripe supports two-step card payments so you can first authorize a card, then capture funds later. When Stripe authorizes a payment, the card issuer guarantees the funds and places a hold for the payment amount on the customer’s card. You then have a certain amount of time to capture the funds, [depending on the card](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md#auth-capture-limitations)). If you don’t capture the payment before the authorization expires, the payment is cancelled and the issuer releases the held funds. Separating authorization and capture is useful if you need to take additional actions between confirming that a customer is able to pay and collecting their payment. For example, if you’re selling stock-limited items, you may need to confirm that an item purchased by your customer using Checkout is still available before capturing their payment and fulfilling the purchase. Accomplish this using the following workflow: 1. Confirm that Stripe authorized the customer’s payment method. 1. Consult your inventory management system to confirm that the item is still available. 1. Update your inventory management system to indicate that a customer has purchased the item. 1. Capture the customer’s payment. 1. Inform your customer whether their purchase was successful on your confirmation page. To indicate that you want to separate authorization and capture, you must set the value of [payment_intent_data.capture_method](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_intent_data-capture_method) to `manual` when creating the Checkout Session. This instructs Stripe to only authorize the amount on the customer’s card. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d "payment_intent_data[capture_method]"=manual \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --mode=payment \ -d "payment_intent_data[capture_method]"=manual \ --ui-mode=embedded \ --return-url="https://example.com/return" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', payment_intent_data: {capture_method: 'manual'}, ui_mode: 'embedded', return_url: 'https://example.com/return', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "payment", "payment_intent_data": {"capture_method": "manual"}, "ui_mode": "embedded", "return_url": "https://example.com/return", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'payment', 'payment_intent_data' => ['capture_method' => 'manual'], 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setPaymentIntentData( SessionCreateParams.PaymentIntentData.builder() .setCaptureMethod(SessionCreateParams.PaymentIntentData.CaptureMethod.MANUAL) .build() ) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', payment_intent_data: { capture_method: 'manual', }, ui_mode: 'embedded', return_url: 'https://example.com/return', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), PaymentIntentData: &stripe.CheckoutSessionCreatePaymentIntentDataParams{ CaptureMethod: stripe.String("manual"), }, UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "payment", PaymentIntentData = new Stripe.Checkout.SessionPaymentIntentDataOptions { CaptureMethod = "manual", }, UiMode = "embedded", ReturnUrl = "https://example.com/return", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` To capture an uncaptured payment, you can use either the [Dashboard](https://dashboard.stripe.com/test/payments?status%5B%5D=uncaptured) or the [capture](https://docs.stripe.com/api/payment_intents/capture.md) endpoint. Programmatically capturing payments requires access to the PaymentIntent created during the Checkout Session, which you can get from the [Session](https://docs.stripe.com/api/payment_intents/capture.md) object. ## Optional: Order fulfillment Learn how to [programmatically get a notification](https://docs.stripe.com/checkout/fulfillment.md) whenever a customer pays. ## See also - [Add discounts](https://docs.stripe.com/payments/checkout/discounts.md) - [Collect taxes](https://docs.stripe.com/payments/checkout/taxes.md) - [Collect tax IDs](https://docs.stripe.com/tax/checkout/tax-ids.md) - [Add shipping](https://docs.stripe.com/payments/collect-addresses.md?payment-ui=checkout) - [Customize your branding](https://docs.stripe.com/payments/checkout/customization.md) # Checkout Sessions API > This is a Checkout Sessions API for when payment-ui is elements and api-integration is checkout. View the full page at https://docs.stripe.com/payments/accept-a-payment?payment-ui=elements&api-integration=checkout. Build a custom payment form using [Stripe Elements](https://docs.stripe.com/payments/elements.md) and the [Checkout Sessions API](https://docs.stripe.com/api/checkout/sessions.md). See how this integration [compares to Stripe’s other integration types](https://docs.stripe.com/payments/online-payments.md#compare-features-and-availability). The Checkout Sessions API provides built-in support for tax calculation, discounts, shipping, and currency conversion, reducing the amount of custom code you need to write. This is the recommended approach for most integrations. Learn more about [when to use Checkout Sessions instead of PaymentIntents](https://docs.stripe.com/payments/checkout-sessions-and-payment-intents-comparison.md). The client-side and server-side code builds a checkout form that accepts various payment methods. #### Integration effort Complexity: 3/5 #### Integration type Combine UI components into a custom payment flow #### UI customization CSS-level customization with the [Appearance API](https://docs.stripe.com/elements/appearance-api.md) ## Set up the server [Server-side] Before you begin, you need to [register](https://dashboard.stripe.com/register) for a Stripe account. Use the official Stripe libraries to access the API from your application. #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` #### Python ```bash # Install through pip pip3 install --upgrade stripe ``` ```bash # Or find the Stripe package on http://pypi.python.org/pypi/stripe/ ``` ```python # Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=5.0.0 ``` #### PHP ```bash # Install the PHP library with Composer composer require stripe/stripe-php ``` ```bash # Or download the source directly: https://github.com/stripe/stripe-php/releases ``` #### Java ```java /* For Gradle, add the following dependency to your build.gradle and replace with the version number you want to use from: - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:31.3.0" ``` ```xml com.stripe stripe-java 31.3.0 ``` ```bash # For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson ``` #### Node.js ```bash # Install with npm npm install stripe --save ``` #### Go ```bash # Make sure your project is using Go Modules go mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v84 ``` ```go // Then import the package import ( "github.com/stripe/stripe-go/v84" ) ``` #### .NET ```bash # Install with dotnet dotnet add package Stripe.net dotnet restore ``` ```bash # Or install with NuGet Install-Package Stripe.net ``` ## Create a Checkout Session [Server-side] Add an endpoint on your server that creates a [Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md) and returns its [client secret](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-client_secret) to your front end. A Checkout Session represents your customer’s session as they pay for one-time purchases or subscriptions. Checkout Sessions expire 24 hours after creation. #### TypeScript ```javascript import express, {Express} from 'express'; const app: Express = express(); app.post('/create-checkout-session', async (req: Express.Request, res: Express.Response) => { const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment',ui_mode: 'custom', // The URL of your payment completion page return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}' }); res.json({checkoutSessionClientSecret: session.client_secret}); }); app.listen(3000, () => { console.log('Running on port 3000'); }); ``` #### Node.js ```javascript const express = require('express'); const app = express(); app.post('/create-checkout-session', async (req, res) => { const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment',ui_mode: 'custom', // The URL of your payment completion page return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}' }); res.json({checkoutSessionClientSecret: session.client_secret}); }); app.listen(3000, () => { console.log('Running on port 3000'); }); ``` #### Ruby ```ruby require 'sinatra' require 'stripe' set :static, true set :port, 4242 post '/create-checkout-session' do content_type 'application/json' data = JSON.parse(request.body.read) session = Stripe::Checkout::Session.create({ line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment',ui_mode: 'custom', return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', }) { checkoutSessionClientSecret: session.client_secret, }.to_json end ``` #### PHP ```php $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, ], 'quantity' => 1, ], ], 'mode' => 'payment','ui_mode' => 'custom', 'return_url' => 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', ]); ``` #### Python ```python import json import os from flask import Flask, render_template, jsonify, request app = Flask(__name__, static_folder='public', static_url_path='', template_folder='public') @app.route('/create-checkout-session', methods=['POST']) def checkout(): try: session = stripe.checkout.Session.create( line_items=[ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, }, "quantity": 1, }, ], mode="payment",ui_mode="custom", # The URL of your payment completion page return_url="https://example.com/return?session_id={CHECKOUT_SESSION_ID}", ) return jsonify({ 'checkoutSessionClientSecret': session['client_secret'] }) except Exception as e: return jsonify(error=str(e)), 403 if __name__ == '__main__': app.run(port=4242) ``` #### Go ```go params := &stripe.CheckoutSessionParams{ LineItems: []*stripe.CheckoutSessionLineItemParams{ &stripe.CheckoutSessionLineItemParams{ PriceData: &stripe.CheckoutSessionLineItemPriceDataParams{ Currency: stripe.String(string(stripe.CurrencyUSD)), ProductData: &stripe.CheckoutSessionLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(string(stripe.CheckoutSessionModePayment)),UIMode: stripe.String(string(stripe.CheckoutSessionUIModeCustom)), ReturnURL: stripe.String("https://example.com/return?session_id={CHECKOUT_SESSION_ID}"), }; result, err := session.New(params); ``` #### .NET ```dotnet // This example sets up an endpoint using the ASP.NET MVC framework. // To learn more about ASP.NET MVC, watch this video: https://youtu.be/2-mMOB8MhmE. using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Stripe; using Stripe.Checkout; namespace server.Controllers { public class PaymentsController : Controller { public PaymentsController() { StripeConfiguration.ApiKey = "<>"; } [HttpPost("create-checkout-session")] public ActionResult CreateCheckoutSession() { var options = new SessionCreateOptions { LineItems = new List { new SessionLineItemOptions { PriceData = new SessionLineItemPriceDataOptions { UnitAmount = 2000, Currency = "usd", ProductData = new SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, }, Quantity = 1, }, }, Mode = "payment",UiMode = "custom", ReturnUrl = "https://example.com/return?session_id={CHECKOUT_SESSION_ID}", }; var service = new SessionService(); Session session = service.Create(options); return Json(new {checkoutSessionClientSecret = session.ClientSecret}); } } } ``` #### Java ```java import java.util.HashMap; import java.util.Map; import static spark.Spark.get; import static spark.Spark.post; import static spark.Spark.port; import static spark.Spark.staticFiles; import com.google.gson.Gson; import com.stripe.Stripe; import com.stripe.model.checkout.Session; import com.stripe.param.checkout.SessionCreateParams; public class Server { public static void main(String[] args) { port(4242); Stripe.apiKey = "<>"; Gson gson = new Gson(); post("/create-checkout-session", (request, response) -> { SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT).setUiMode(SessionCreateParams.UiMode.CUSTOM) .setReturnUrl("https://example.com/return?session_id={CHECKOUT_SESSION_ID}") .addLineItem( SessionCreateParams.LineItem.builder() .setQuantity(1L) .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setUnitAmount(2000L) .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build()) .build()) .build()) .build(); Session session = Session.create(params); Map map = new HashMap(); map.put("checkoutSessionClientSecret", session.getRawJsonObject().getAsJsonPrimitive("client_secret").getAsString()); return map; }, gson::toJson); } } ``` ## Set up the front end [Client-side] #### HTML + JS Include the Stripe.js script on your checkout page by adding it to the `head` of your HTML file. Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Don’t include the script in a bundle or host a copy of it yourself. Ensure you’re on the latest Stripe.js version by including the following script tag ``. Learn more about [Stripe.js versioning](https://docs.stripe.com/sdks/stripejs-versioning.md). ```html Checkout ``` > Stripe provides an npm package that you can use to load Stripe.js as a module. See the [project on GitHub](https://github.com/stripe/stripe-js). Version [7.0.0](https://www.npmjs.com/package/%40stripe/stripe-js/v/7.0.0) or later is required. Initialize stripe.js. ```js // Set your publishable key: remember to change this to your live publishable key in production // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe( '<>', ); ``` #### React Install [React Stripe.js](https://www.npmjs.com/package/@stripe/react-stripe-js) and the [Stripe.js loader](https://www.npmjs.com/package/@stripe/stripe-js) from the npm public registry. You need at least version 5.0.0 for React Stripe.js and version 8.0.0 for the Stripe.js loader. ```bash npm install --save @stripe/react-stripe-js@^5.0.0 @stripe/stripe-js@^8.0.0 ``` Initialize a `stripe` instance on your front end with your publishable key. ```javascript import {loadStripe} from '@stripe/stripe-js'; const stripe = loadStripe("<>"); ``` ## Initialize Checkout [Client-side] #### HTML + JS Create either a `clientSecret` promise that resolves with the client secret or set it as the secret directly. Call [initCheckout](https://docs.stripe.com/js/custom_checkout/init), passing in `clientSecret`. `initCheckout` returns a promise that resolves to a [Checkout](https://docs.stripe.com/js/custom_checkout) instance. The [checkout](https://docs.stripe.com/js/custom_checkout) object acts as the foundation of your checkout page, and contains data from the Checkout Session and methods to update the Session. The object returned by [actions.getSession()](https://docs.stripe.com/js/custom_checkout/session) contains your pricing information. We recommend reading and displaying the `total`, and `lineItems` from the session in your UI. This lets you turn on new features with minimal code changes. For example, adding [manual currency prices](https://docs.stripe.com/payments/custom/localize-prices/manual-currency-prices.md) requires no UI changes if you display the `total`. ```html
``` ```javascript const clientSecret = fetch('/create-checkout-session', {method: 'POST'}) .then((response) => response.json()) .then((json) => json.checkoutSessionClientSecret); const checkout = stripe.initCheckout({clientSecret}); const loadActionsResult = await checkout.loadActions(); if (loadActionsResult.type === 'success') { const session = loadActionsResult.actions.getSession(); const checkoutContainer = document.getElementById('checkout-container'); checkoutContainer.append(JSON.stringify(session.lineItems, null, 2)); checkoutContainer.append(document.createElement('br')); checkoutContainer.append(`Total: ${session.total.total.amount}`); } ``` #### React Create `clientSecret` as a `Promise | string` containing the client secret returned by your server. Wrap your application with the [CheckoutProvider](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider) component, passing in `clientSecret` and the `stripe` instance. Use the [useCheckout](https://docs.stripe.com/js/react_stripe_js/checkout/use_checkout) hook in your components to get the [Checkout](https://docs.stripe.com/js/custom_checkout) object, which contains data from the Checkout Session and methods to update the Session. Use the `Checkout` object as the container for your prices. We recommend reading and displaying the `total` and `lineItems` from the `Checkout` object in your UI. This lets you enable features with minimal code changes. For example, adding [manual currency prices](https://docs.stripe.com/payments/custom/localize-prices/manual-currency-prices.md) requires no UI changes if you display the `total`. ```jsx import React from 'react'; import {CheckoutProvider} from '@stripe/react-stripe-js/checkout'; import CheckoutForm from './CheckoutForm'; const clientSecret = fetch('/create-checkout-session', {method: 'POST'}) .then((response) => response.json()) .then((json) => json.checkoutSessionClientSecret); const App = () => { return ( ); }; export default App; ``` ```jsx import React from 'react'; import {useCheckout} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => {const checkoutState = useCheckout(); switch (checkoutState.type) { case "loading": return
Loading ...
; case "error": return
Error: {checkoutState.error.message}
; case "success": return (
{JSON.stringify(checkoutState.checkout.lineItems, null, 2)}
          // A formatted total amount
          Total: {checkoutState.checkout.total.total.amount}
        
); } }; ``` ## Collect customer email [Client-side] #### HTML + JS If you already pass in an existing [customer_email](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_email) or [Customer](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer) with a valid email set when creating the Checkout Session, you can skip this step. If you implement your own email validation, you can pass in the validated email on [checkout.confirm](https://docs.stripe.com/js/custom_checkout/confirm) and skip this step. Create an email input to collect your customer’s email address. Call [updateEmail](https://docs.stripe.com/js/custom_checkout/update_email) when your customer finishes the input to validate and save the email address. Depending on the design of your checkout form, you can call `updateEmail` in the following ways: - Directly before [submitting the payment](https://docs.stripe.com/payments/accept-a-payment.md#submit-payment). You can also call `updateEmail` to validate earlier, such as on input blur. - Before transitioning to the next step, such as clicking a **Save** button, if your form includes multiple steps. ```html
``` ```javascript const checkout = stripe.initCheckout({clientSecret}); const loadActionsResult = await checkout.loadActions(); if (loadActionsResult.type === 'success') { const {actions} = loadActionsResult; const emailInput = document.getElementById('email'); const emailErrors = document.getElementById('email-errors'); emailInput.addEventListener('input', () => { // Clear any validation errors emailErrors.textContent = ''; }); emailInput.addEventListener('blur', () => { const newEmail = emailInput.value;actions.updateEmail(newEmail).then((result) => { if (result.error) { emailErrors.textContent = result.error.message; } }); }); } ``` #### React If you already pass in an existing [customer_email](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_email) or [Customer](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer) with a valid email set when creating the Checkout Session, you can skip this step. If you implement your own email validation, you can pass in the validated email on [confirm](https://docs.stripe.com/js/react_stripe_js/checkout/confirm) and skip this step. Create a component to collect your customer’s email address. Call [updateEmail](https://docs.stripe.com/js/react_stripe_js/checkout/update_email) when your customer finishes the input to validate and save the email address. Depending on the design of your checkout form, you can call `updateEmail` in the following ways: - Directly before [submitting the payment](https://docs.stripe.com/payments/accept-a-payment.md#submit-payment). You can also call `updateEmail` to validate earlier, such as on input blur. - Before transitioning to the next step, such as clicking a **Save** button, if your form includes multiple steps. ```jsx import React from 'react'; import {useCheckout} from '@stripe/react-stripe-js/checkout'; const EmailInput = () => { const checkoutState = useCheckout(); const [email, setEmail] = React.useState(''); const [error, setError] = React.useState(null); if (checkoutState.type === 'loading') { return (
Loading...
); } else if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } const handleBlur = () => {checkoutState.checkout.updateEmail(email).then((result) => { if (result.type === 'error') { setError(result.error); } }) }; const handleChange = (e) => { setError(null); setEmail(e.target.value); }; return (
{error &&
{error.message}
}
); }; export default EmailInput; ``` ## Collect payment details [Client-side] Collect payment details on the client with the [Payment Element](https://docs.stripe.com/payments/payment-element.md). The Payment Element is a prebuilt UI component that simplifies collecting payment details for a variety of payment methods. #### HTML + JS First, create a container DOM element to mount the [Payment Element](https://docs.stripe.com/payments/payment-element.md). Then create an instance of the `Payment Element` using [checkout.createPaymentElement](https://docs.stripe.com/js/custom_checkout/create_payment_element) and mount it by calling [element.mount](https://docs.stripe.com/js/element/mount), providing either a CSS selector or the container DOM element. ```html
``` ```javascript const paymentElement = checkout.createPaymentElement(); paymentElement.mount('#payment-element'); ``` See the [Stripe.js docs](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options) to view the supported options. You can [customize the appearance](https://docs.stripe.com/payments/checkout/customization/appearance.md) of all Elements by passing [elementsOptions.appearance](https://docs.stripe.com/js/custom_checkout/init#custom_checkout_init-options-elementsOptions-appearance) when initializing Checkout on the front end. #### React Mount the [Payment Element](https://docs.stripe.com/payments/payment-element.md) component within the [CheckoutProvider](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider). ```jsx import React from 'react'; import {PaymentElement, useCheckout} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { const checkoutState = useCheckout(); return (
) }; export default CheckoutForm; ``` See the [Stripe.js docs](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options) to view the supported options. You can [customize the appearance](https://docs.stripe.com/payments/checkout/customization/appearance.md) of all Elements by passing [elementsOptions.appearance](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider#react_checkout_provider-options-elementsOptions-appearance) to the [CheckoutProvider](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider). ## Submit the payment [Client-side] #### HTML + JS Render a **Pay** button that calls [confirm](https://docs.stripe.com/js/custom_checkout/confirm) from the `Checkout` instance to submit the payment. ```html
``` ```js const checkout = stripe.initCheckout({clientSecret}); const loadActionsResult = await checkout.loadActions(); if (loadActionsResult.type === 'success') { const {actions} = loadActionsResult; const button = document.getElementById('pay-button'); const errors = document.getElementById('confirm-errors'); button.addEventListener('click', () => { // Clear any validation errors errors.textContent = ''; actions.confirm().then((result) => { if (result.type === 'error') { errors.textContent = result.error.message; } }); }); } ``` #### React Render a **Pay** button that calls [confirm](https://docs.stripe.com/js/custom_checkout/confirm) from [useCheckout](https://docs.stripe.com/js/react_stripe_js/checkout/use_checkout) to submit the payment. ```jsx import React from 'react'; import {useCheckout} from '@stripe/react-stripe-js/checkout'; const PayButton = () => { const checkoutState = useCheckout(); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(null); const handleClick = () => { setLoading(true); checkoutState.checkout.confirm().then((result) => { if (result.type === 'error') { setError(result.error) } setLoading(false); }) }; return (
{error &&
{error.message}
}
) }; export default PayButton; ``` ## Test your integration 1. Navigate to your checkout page. 1. Fill out the payment details with a payment method from the following table. For card payments: - Enter any future date for card expiry. - Enter any 3-digit number for CVC. - Enter any billing postal code. 1. Submit the payment to Stripe. 1. Go to the Dashboard and look for the payment on the [Transactions page](https://dashboard.stripe.com/test/payments?status%5B0%5D=successful). If your payment succeeded, you’ll see it in that list. 1. Click your payment to see more details, like billing information and the list of purchased items. You can use this information to [fulfill the order](https://docs.stripe.com/checkout/fulfillment.md). #### Cards | Card number | Scenario | How to test | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | 4242424242424242 | The card payment succeeds and doesn’t require authentication. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000002500003155 | The card payment requires *authentication* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase). | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000000000009995 | The card is declined with a decline code like `insufficient_funds`. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 6205500000000000004 | The UnionPay card has a variable length of 13-19 digits. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | #### Wallets | Payment method | Scenario | How to test | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Alipay | Your customer successfully pays with a redirect-based and [immediate notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | #### Bank redirects | Payment method | Scenario | How to test | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | BECS Direct Debit | Your customer successfully pays with BECS Direct Debit. | Fill out the form using the account number `900123456` and BSB `000000`. The confirmed PaymentIntent initially transitions to `processing`, then transitions to the `succeeded` status 3 minutes later. | | BECS Direct Debit | Your customer’s payment fails with an `account_closed` error code. | Fill out the form using the account number `111111113` and BSB `000000`. | | Bancontact, EPS, iDEAL, and Przelewy24 | Your customer fails to authenticate on the redirect page for a redirect-based and immediate notification payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | Pay by Bank | Your customer successfully pays with a redirect-based and [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | | Pay by Bank | Your customer fails to authenticate on the redirect page for a redirect-based and delayed notification payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | BLIK | BLIK payments fail in a variety of ways—immediate failures (for example, the code is expired or invalid), delayed errors (the bank declines) or timeouts (the customer didn’t respond in time). | Use email patterns to [simulate the different failures.](https://docs.stripe.com/payments/blik/accept-a-payment.md#simulate-failures) | #### Bank debits | Payment method | Scenario | How to test | | ----------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SEPA Direct Debit | Your customer successfully pays with SEPA Direct Debit. | Fill out the form using the account number `AT321904300235473204`. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later. | | SEPA Direct Debit | Your customer’s payment intent status transitions from `processing` to `requires_payment_method`. | Fill out the form using the account number `AT861904300235473202`. | #### Vouchers | Payment method | Scenario | How to test | | -------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | Boleto, OXXO | Your customer pays with a Boleto or OXXO voucher. | Select Boleto or OXXO as the payment method and submit the payment. Close the dialog after it appears. | See [Testing](https://docs.stripe.com/testing.md) for additional information to test your integration. ## Optional: Create products and prices Before you create a Checkout Session, you can create *Products* (Products represent what your business sells—whether that's a good or a service) and *Prices* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) upfront. Use products to represent different physical goods or levels of service, and *Prices* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) to represent each product’s pricing. You can [set up your Checkout Session](https://docs.stripe.com/payments/checkout/pay-what-you-want.md) to accept tips and donations, or sell pay-what-you-want products and services. For example, you can create a T-shirt as a product with a price of 20 USD. This allows you to update and add prices without needing to change the details of your underlying products. You can either create products and prices with the Stripe Dashboard or API. Learn more about [how products and prices work](https://docs.stripe.com/products-prices/how-products-and-prices-work.md). #### API The API only requires a `name` to create a [Product](https://docs.stripe.com/api/products.md). Checkout displays the product `name`, `description`, and `images` that you supply. ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ -d name=T-shirt ``` ```cli stripe products create \ --name=T-shirt ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") product = client.v1.products.create({name: 'T-shirt'}) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. product = client.v1.products.create({"name": "T-shirt"}) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $product = $stripe->products->create(['name' => 'T-shirt']); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); ProductCreateParams params = ProductCreateParams.builder().setName("T-shirt").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Product product = client.v1().products().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const product = await stripe.products.create({ name: 'T-shirt', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.ProductCreateParams{Name: stripe.String("T-shirt")} result, err := sc.V1Products.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new ProductCreateOptions { Name = "T-shirt" }; var client = new StripeClient("<>"); var service = client.V1.Products; Product product = service.Create(options); ``` Next, create a [Price](https://docs.stripe.com/api/prices.md) to define how much to charge for your product. This includes how much the product costs and what currency to use. ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product="{{PRODUCT_ID}}" \ -d unit_amount=2000 \ -d currency=usd ``` ```cli stripe prices create \ --product="{{PRODUCT_ID}}" \ --unit-amount=2000 \ --currency=usd ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") price = client.v1.prices.create({ product: '{{PRODUCT_ID}}', unit_amount: 2000, currency: 'usd', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. price = client.v1.prices.create({ "product": "{{PRODUCT_ID}}", "unit_amount": 2000, "currency": "usd", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $price = $stripe->prices->create([ 'product' => '{{PRODUCT_ID}}', 'unit_amount' => 2000, 'currency' => 'usd', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PriceCreateParams params = PriceCreateParams.builder() .setProduct("{{PRODUCT_ID}}") .setUnitAmount(2000L) .setCurrency("usd") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Price price = client.v1().prices().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const price = await stripe.prices.create({ product: '{{PRODUCT_ID}}', unit_amount: 2000, currency: 'usd', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PriceCreateParams{ Product: stripe.String("{{PRODUCT_ID}}"), UnitAmount: stripe.Int64(2000), Currency: stripe.String(stripe.CurrencyUSD), } result, err := sc.V1Prices.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PriceCreateOptions { Product = "{{PRODUCT_ID}}", UnitAmount = 2000, Currency = "usd", }; var client = new StripeClient("<>"); var service = client.V1.Prices; Price price = service.Create(options); ``` #### Dashboard > Copy products created in a sandbox to live mode so that you don’t need to re-create them. In the Product detail view in the Dashboard, click **Copy to live mode** in the upper right corner. You can only do this once for each product created in a sandbox. Subsequent updates to the test product aren’t reflected for the live product. Make sure you’re in a sandbox by clicking **Sandboxes** within the Dashboard account picker. Next, define the items you want to sell. To create a new product and price: - Navigate to the [Products](https://dashboard.stripe.com/test/products) section in the Dashboard. - Click **Add product**. - Select **One time** when setting the price. Checkout displays the product name, description, and images that you supply. Each price you create has an ID. When you create a Checkout Session, reference the price ID and quantity. If you’re selling in multiple currencies, make your Price *multi-currency* (A single Price object can support multiple currencies. Each purchase uses one of the supported currencies for the Price, depending on how you use the Price in your integration). Checkout automatically [determines the customer’s local currency](https://docs.stripe.com/payments/checkout/localize-prices/manual-currency-prices.md) and presents that currency if the Price supports it. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d ui_mode=custom \ -d mode=payment \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --data-urlencode return_url="https://example.com/return?session_id={CHECKOUT_SESSION_ID}" ``` ```cli stripe checkout sessions create \ --ui-mode=custom \ --mode=payment \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --return-url="https://example.com/return?session_id={CHECKOUT_SESSION_ID}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ ui_mode: 'custom', mode: 'payment', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "ui_mode": "custom", "mode": "payment", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "return_url": "https://example.com/return?session_id={CHECKOUT_SESSION_ID}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'ui_mode' => 'custom', 'mode' => 'payment', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'return_url' => 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setUiMode(SessionCreateParams.UiMode.CUSTOM) .setMode(SessionCreateParams.Mode.PAYMENT) .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setReturnUrl("https://example.com/return?session_id={CHECKOUT_SESSION_ID}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ ui_mode: 'custom', mode: 'payment', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ UIMode: stripe.String(stripe.CheckoutSessionUIModeCustom), Mode: stripe.String(stripe.CheckoutSessionModePayment), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, ReturnURL: stripe.String("https://example.com/return?session_id={CHECKOUT_SESSION_ID}"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { UiMode = "custom", Mode = "payment", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, ReturnUrl = "https://example.com/return?session_id={CHECKOUT_SESSION_ID}", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Optional: Prefill customer data [Server-side] If you’ve already collected your customer’s email and want to prefill it in the Checkout Session for them, pass [customer_email](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_email) when creating a Checkout Session. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ --data-urlencode customer_email="customer@example.com" \ -d ui_mode=custom \ -d mode=payment \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --data-urlencode return_url="https://example.com/return?session_id={CHECKOUT_SESSION_ID}" ``` ```cli stripe checkout sessions create \ --customer-email="customer@example.com" \ --ui-mode=custom \ --mode=payment \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --return-url="https://example.com/return?session_id={CHECKOUT_SESSION_ID}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer_email: 'customer@example.com', ui_mode: 'custom', mode: 'payment', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer_email": "customer@example.com", "ui_mode": "custom", "mode": "payment", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "return_url": "https://example.com/return?session_id={CHECKOUT_SESSION_ID}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer_email' => 'customer@example.com', 'ui_mode' => 'custom', 'mode' => 'payment', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'return_url' => 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomerEmail("customer@example.com") .setUiMode(SessionCreateParams.UiMode.CUSTOM) .setMode(SessionCreateParams.Mode.PAYMENT) .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setReturnUrl("https://example.com/return?session_id={CHECKOUT_SESSION_ID}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer_email: 'customer@example.com', ui_mode: 'custom', mode: 'payment', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ CustomerEmail: stripe.String("customer@example.com"), UIMode: stripe.String(stripe.CheckoutSessionUIModeCustom), Mode: stripe.String(stripe.CheckoutSessionModePayment), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, ReturnURL: stripe.String("https://example.com/return?session_id={CHECKOUT_SESSION_ID}"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { CustomerEmail = "customer@example.com", UiMode = "custom", Mode = "payment", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, ReturnUrl = "https://example.com/return?session_id={CHECKOUT_SESSION_ID}", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Optional: Save payment method details Learn how to [accept a payment and save your customer’s payment details](https://docs.stripe.com/payments/save-during-payment.md) for future purchases. ## Optional: Listen for Checkout Session changes ### Listen for Checkout Session changes You can listen for changes to the [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) by adding an event listener on the `change` event with [checkout.on](https://docs.stripe.com/js/custom_checkout/change_event). #### HTML + JS ```javascript checkout = stripe.initCheckout({ clientSecret: promise, elementsOptions: { appearance }, }); checkout.on('change', (session) => { // Handle changes to the checkout session }); ``` #### React ```jsx import React from 'react'; import { useCheckout } from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { const checkoutState = useCheckout(); if (checkoutState.type === 'success') { checkoutState.checkout.on('change', (session) => { // Handle changes to the checkout session }); } }; ``` ## Optional: Collect billing and shipping addresses ## Collect a billing address By default, a Checkout Session collects the minimal billing details required for payment through the Payment Element. ### Using the Billing Address Element You can collect complete billing addresses using the Billing Address Element. First, pass [billing_address_collection=required](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-billing_address_collection) when you create the Checkout Session. #### HTML + JS Create a container DOM element to mount the Billing Address Element. Then create an instance of the Billing Address Element using [checkout.createBillingAddressElement](https://docs.stripe.com/js/custom_checkout/create_billing_address_element) and mount it by calling [element.mount](https://docs.stripe.com/js/element/mount), providing either a CSS selector or the container DOM element. ```html
``` ```javascript const billingAddressElement = checkout.createBillingAddressElement(); billingAddressElement.mount('#billing-address'); ``` The Billing Address Element supports the following options: - [contacts](https://docs.stripe.com/js/custom_checkout/create_billing_address_element#custom_checkout_create_billing_address_element-options-contacts) - [display](https://docs.stripe.com/js/custom_checkout/create_billing_address_element#custom_checkout_create_billing_address_element-options-display) #### React Mount the `BillingAddressElement` component within the `CheckoutProvider`. ```jsx import React from 'react'; import {BillingAddressElement} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { return (
) }; ``` The Billing Address Element supports the following props: - [contacts](https://docs.stripe.com/js/custom_checkout/create_billing_address_element#custom_checkout_create_billing_address_element-options-contacts) - [display](https://docs.stripe.com/js/custom_checkout/create_billing_address_element#custom_checkout_create_billing_address_element-options-display) ### Using a custom form You can build your own form to collect billing addresses. - If your checkout page has a distinct address collection step before confirmation, call [updateBillingAddress](https://docs.stripe.com/js/react_stripe_js/checkout/update_billing_address) when your customer submits the address. - Otherwise, you can submit the address when your customer clicks the “pay” button by passing [billingAddress](https://docs.stripe.com/js/custom_checkout/confirm#custom_checkout_session_confirm-options-billingAddress) to [confirm](https://docs.stripe.com/js/custom_checkout/confirm). ### Collect partial billing addresses To collect partial billing addresses, such as only the country and postal code, pass [billing_address_collection=auto](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-billing_address_collection). When collecting partial billing addresses, you must [collect addresses manually](https://docs.stripe.com/payments/accept-a-payment.md#collect-billing-addresses-manually). By default, the Payment Element automatically collects the minimal billing details required for payment. To avoid double collection of billing details, pass [fields.billingDetails=never](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options-fields-billingDetails) when creating the Payment Element. If you only intend to collect a subset of billing details (such as the customer’s name), pass `never` for only the fields you intend to collect yourself. ## Collect a shipping address To collect a customer’s shipping address, pass the [shipping_address_collection](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-shipping_address_collection) parameter when you create the Checkout Session. When you collect a shipping address, you must also specify which countries to allow shipping to. Configure the [allowed_countries](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-shipping_address_collection-allowed_countries) property with an array of [two-letter ISO country codes](https://www.nationsonline.org/oneworld/country_code_list.htm). ### How to use the Shipping Address Element You can collect complete shipping addresses with the Shipping Address Element. #### HTML + JS Create a container DOM element to mount the Shipping Address Element. Then create an instance of the Shipping Address Element using [checkout.createShippingAddressElement](https://docs.stripe.com/js/custom_checkout/create_shipping_address_element) and mount it by calling [element.mount](https://docs.stripe.com/js/element/mount), providing either a CSS selector or the container DOM element. ```html
``` ```javascript const shippingAddressElement = checkout.createShippingAddressElement(); shippingAddressElement.mount('#shipping-address'); ``` The Shipping Address Element supports the following options: - [contacts](https://docs.stripe.com/js/custom_checkout/create_shipping_address_element#custom_checkout_create_shipping_address_element-options-contacts) - [display](https://docs.stripe.com/js/custom_checkout/create_shipping_address_element#custom_checkout_create_shipping_address_element-options-display) #### React Mount the `ShippingAddressElement` component within the `CheckoutProvider`. ```jsx import React from 'react'; import {ShippingAddressElement} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { return (
) }; ``` The Shipping Address Element supports the following props: - [contacts](https://docs.stripe.com/js/custom_checkout/create_shipping_address_element#custom_checkout_create_shipping_address_element-options-contacts) - [display](https://docs.stripe.com/js/custom_checkout/create_shipping_address_element#custom_checkout_create_shipping_address_element-options-display) ### Listen for Checkout Session changes You can listen for changes to the [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) by adding an event listener to handle address-related changes. #### HTML + JS Use the [Session object](https://docs.stripe.com/js/custom_checkout/session_object) to render the shipping amount in your checkout form. ```html

Totals

``` ```javascript const checkout = stripe.initCheckout({clientSecret}); const subtotal = document.getElementById('subtotal'); const shipping = document.getElementById('shipping'); const total = document.getElementById('total'); checkout.on('change', (session) => { subtotal.textContent = `Subtotal: ${session.total.subtotal.amount}`; shipping.textContent = `Shipping: ${session.total.shippingRate.amount}`; total.textContent = `Total: ${session.total.total.amount}`; }); ``` #### React Use [useCheckout](https://docs.stripe.com/js/react_stripe_js/checkout/use_checkout) to render the shipping cost in your checkout form. ```jsx import React from 'react'; import {useCheckout, ShippingAddressElement} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { const checkoutState = useCheckout(); if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } return (

Checkout Summary

{checkoutState.type === 'success' && ( <>
              {JSON.stringify(checkoutState.checkout.lineItems, null, 2)}
            

Totals

              Subtotal: {checkoutState.checkout.total.subtotal.amount}
              Shipping: {checkoutState.checkout.total.shippingRate.amount}
              Total: {checkoutState.checkout.total.total.amount}
            
)}
) }; ``` ### Use a custom form You can build your own form to collect shipping addresses. - If your checkout page has a distinct address collection step before confirmation, call [updateShippingAddress](https://docs.stripe.com/js/react_stripe_js/checkout/update_shipping_address) when your customer submits the address. - Otherwise, you can submit the address when your customer clicks the “pay” button by passing [shippingAddress](https://docs.stripe.com/js/custom_checkout/confirm#custom_checkout_session_confirm-options-shippingAddress) to [confirm](https://docs.stripe.com/js/custom_checkout/confirm). ## Optional: Separate authorization and capture [Server-side] Stripe supports two-step card payments so you can first authorize a card, then capture funds later. When Stripe authorizes a payment, the card issuer guarantees the funds and places a hold for the payment amount on the customer’s card. You then have a certain amount of time to capture the funds, [depending on the card](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md#auth-capture-limitations)). If you don’t capture the payment before the authorization expires, the payment is cancelled and the issuer releases the held funds. Separating authorization and capture is useful if you need to take additional actions between confirming that a customer is able to pay and collecting their payment. For example, if you’re selling stock-limited items, you may need to confirm that an item purchased by your customer using Checkout is still available before capturing their payment and fulfilling the purchase. Accomplish this using the following workflow: 1. Confirm that Stripe authorized the customer’s payment method. 1. Consult your inventory management system to confirm that the item is still available. 1. Update your inventory management system to indicate that a customer has purchased the item. 1. Capture the customer’s payment. 1. Inform your customer whether their purchase was successful on your confirmation page. To indicate that you want to separate authorization and capture, you must set the value of [payment_intent_data.capture_method](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_intent_data-capture_method) to `manual` when creating the Checkout Session. This instructs Stripe to only authorize the amount on the customer’s card. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d "payment_intent_data[capture_method]"=manual \ -d return_url={{RETURN_URL}} \ -d ui_mode=custom ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --mode=payment \ -d "payment_intent_data[capture_method]"=manual \ --return-url={{RETURN_URL}} \ --ui-mode=custom ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', payment_intent_data: {capture_method: 'manual'}, return_url: '{{RETURN_URL}}', ui_mode: 'custom', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "payment", "payment_intent_data": {"capture_method": "manual"}, "return_url": "{{RETURN_URL}}", "ui_mode": "custom", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'payment', 'payment_intent_data' => ['capture_method' => 'manual'], 'return_url' => '{{RETURN_URL}}', 'ui_mode' => 'custom', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setPaymentIntentData( SessionCreateParams.PaymentIntentData.builder() .setCaptureMethod(SessionCreateParams.PaymentIntentData.CaptureMethod.MANUAL) .build() ) .setReturnUrl("{{RETURN_URL}}") .setUiMode(SessionCreateParams.UiMode.CUSTOM) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', payment_intent_data: { capture_method: 'manual', }, return_url: '{{RETURN_URL}}', ui_mode: 'custom', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), PaymentIntentData: &stripe.CheckoutSessionCreatePaymentIntentDataParams{ CaptureMethod: stripe.String("manual"), }, ReturnURL: stripe.String("{{RETURN_URL}}"), UIMode: stripe.String(stripe.CheckoutSessionUIModeCustom), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "payment", PaymentIntentData = new Stripe.Checkout.SessionPaymentIntentDataOptions { CaptureMethod = "manual", }, ReturnUrl = "{{RETURN_URL}}", UiMode = "custom", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` To capture an uncaptured payment, you can use either the [Dashboard](https://dashboard.stripe.com/test/payments?status%5B%5D=uncaptured) or the [capture](https://docs.stripe.com/api/payment_intents/capture.md) endpoint. Programmatically capturing payments requires access to the PaymentIntent created during the Checkout Session, which you can get from the [Session](https://docs.stripe.com/api/payment_intents/capture.md) object. ## Optional: Customer account management [No code] Let your customers [manage](https://docs.stripe.com/customer-management.md) their own accounts by sharing a link to your *customer portal* (The customer portal is a secure, Stripe-hosted page that lets your customers manage their subscriptions and billing details). The customer portal lets customers log in with their email to manage subscriptions, update payment methods, and so on. ## Optional: Order fulfillment Learn how to [programmatically get a notification](https://docs.stripe.com/checkout/fulfillment.md?payment-ui=embedded-components) when a customer pays. ## See also - [Add discounts for one-time payments](https://docs.stripe.com/payments/checkout/discounts.md?payment-ui=embedded-components) - [Collect taxes](https://docs.stripe.com/payments/checkout/taxes.md?payment-ui=embedded-components) - [Enable adjustable line item quantities](https://docs.stripe.com/payments/checkout/adjustable-quantity.md?payment-ui=embedded-components) - [Add one-click buttons](https://docs.stripe.com/elements/express-checkout-element/accept-a-payment.md?payment-ui=embedded-components) # Payment Intents API > This is a Payment Intents API for when payment-ui is elements and api-integration is paymentintents. View the full page at https://docs.stripe.com/payments/accept-a-payment?payment-ui=elements&api-integration=paymentintents. Build a custom payment form using [Stripe Elements](https://docs.stripe.com/payments/elements.md) and the [Payment Intents API](https://docs.stripe.com/api/payment_intents.md). See how this integration [compares to Stripe’s other integration types](https://docs.stripe.com/payments/online-payments.md#compare-features-and-availability). The Payment Intents API provides granular control over your checkout flow, allowing you to customize every aspect of the payment process. This approach requires more integration code but offers maximum flexibility. Learn more about [when to use Checkout Sessions instead of PaymentIntents](https://docs.stripe.com/payments/checkout-sessions-and-payment-intents-comparison.md). The client-side and server-side code builds a checkout form that accepts various payment methods. #### Integration effort Complexity: 4/5 #### Integration type Combine UI components into a custom payment flow #### UI customization CSS-level customization with the [Appearance API](https://docs.stripe.com/elements/appearance-api.md) > #### Interested in using Stripe Tax, discounts, shipping, or currency conversion? > > Stripe has a Payment Element integration that manages tax, discounts, shipping, and currency conversion for you. See [build a checkout page](https://docs.stripe.com/payments/quickstart-checkout-sessions.md) to learn more. ## Set up Stripe [Server-side] First, [create a Stripe account](https://dashboard.stripe.com/register) or [sign in](https://dashboard.stripe.com/login). Use our official libraries to access the Stripe API from your application: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` #### Python ```bash # Install through pip pip3 install --upgrade stripe ``` ```bash # Or find the Stripe package on http://pypi.python.org/pypi/stripe/ ``` ```python # Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=5.0.0 ``` #### PHP ```bash # Install the PHP library with Composer composer require stripe/stripe-php ``` ```bash # Or download the source directly: https://github.com/stripe/stripe-php/releases ``` #### Java ```java /* For Gradle, add the following dependency to your build.gradle and replace with the version number you want to use from: - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:31.3.0" ``` ```xml com.stripe stripe-java 31.3.0 ``` ```bash # For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson ``` #### Node.js ```bash # Install with npm npm install stripe --save ``` #### Go ```bash # Make sure your project is using Go Modules go mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v84 ``` ```go // Then import the package import ( "github.com/stripe/stripe-go/v84" ) ``` #### .NET ```bash # Install with dotnet dotnet add package Stripe.net dotnet restore ``` ```bash # Or install with NuGet Install-Package Stripe.net ``` ## Create a PaymentIntent [Server-side] > If you want to render the Payment Element without first creating a PaymentIntent, see [Collect payment details before creating an Intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=payment). The [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) object represents your intent to collect payment from a customer and tracks charge attempts and state changes throughout the payment process. A high-level overview of the payments integration this document describes. (See full diagram at https://docs.stripe.com/payments/accept-a-payment) ### Create the PaymentIntent Create a PaymentIntent on your server with an [amount](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-amount) and [currency](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-currency). In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. You can manage payment methods from the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow. Stripe uses your [payment methods settings](https://dashboard.stripe.com/settings/payment_methods) to display the payment methods you have enabled. To see how your payment methods appear to customers, enter a transaction ID or set an order amount and currency in the [Dashboard](https://dashboard.stripe.com/settings/payment_methods/review). To override payment methods, manually list any that you want to enable using the [payment_method_types](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-payment_method_types) attribute. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "automatic_payment_methods[enabled]"=true ``` ```cli stripe payment_intents create \ --amount=1099 \ --currency=usd \ -d "automatic_payment_methods[enabled]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 1099, "currency": "usd", "automatic_payment_methods": {"enabled": True}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'usd', 'automatic_payment_methods' => ['enabled' => true], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder().setEnabled(true).build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', automatic_payment_methods: { enabled: true, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(1099), Currency: stripe.String(stripe.CurrencyUSD), AutomaticPaymentMethods: &stripe.PaymentIntentCreateAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` > Always decide how much to charge on the server side, a trusted environment, as opposed to the client. This prevents malicious customers from being able to choose their own prices. ### Retrieve the client secret The PaymentIntent includes a *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)) that the client side uses to securely complete the payment process. You can use different approaches to pass the client secret to the client side. #### Single-page application Retrieve the client secret from an endpoint on your server, using the browser’s `fetch` function. This approach is best if your client side is a single-page application, particularly one built with a modern frontend framework like React. Create the server endpoint that serves the client secret: #### Ruby ```ruby get '/secret' do intent = # ... Create or retrieve the PaymentIntent {client_secret: intent.client_secret}.to_json end ``` #### Python ```python from flask import Flask, jsonify app = Flask(__name__) @app.route('/secret') def secret(): intent = # ... Create or retrieve the PaymentIntent return jsonify(client_secret=intent.client_secret) ``` #### PHP ```php $intent->client_secret)); ?> ``` #### Java ```java import java.util.HashMap; import java.util.Map; import com.stripe.model.PaymentIntent; import com.google.gson.Gson; import static spark.Spark.get; public class StripeJavaQuickStart { public static void main(String[] args) { Gson gson = new Gson(); get("/secret", (request, response) -> { PaymentIntent intent = // ... Fetch or create the PaymentIntent Map map = new HashMap(); map.put("client_secret", intent.getClientSecret()); return map; }, gson::toJson); } } ``` #### Node.js ```javascript const express = require('express'); const app = express(); app.get('/secret', async (req, res) => { const intent = // ... Fetch or create the PaymentIntent res.json({client_secret: intent.client_secret}); }); app.listen(3000, () => { console.log('Running on port 3000'); }); ``` #### Go ```go package main import ( "encoding/json" "net/http" stripe "github.com/stripe/stripe-go/v76.0.0" ) type CheckoutData struct { ClientSecret string `json:"client_secret"` } func main() { http.HandleFunc("/secret", func(w http.ResponseWriter, r *http.Request) { intent := // ... Fetch or create the PaymentIntent data := CheckoutData{ ClientSecret: intent.ClientSecret, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(data) }) http.ListenAndServe(":3000", nil) } ``` #### .NET ```csharp using System; using Microsoft.AspNetCore.Mvc; using Stripe; namespace StripeExampleApi.Controllers { [Route("secret")] [ApiController] public class CheckoutApiController : Controller { [HttpGet] public ActionResult Get() { var intent = // ... Fetch or create the PaymentIntent return Json(new {client_secret = intent.ClientSecret}); } } } ``` And then fetch the client secret with JavaScript on the client side: ```javascript (async () => { const response = await fetch('/secret'); const {client_secret: clientSecret} = await response.json(); // Render the form using the clientSecret })(); ``` #### Server-side rendering Pass the client secret to the client from your server. This approach works best if your application generates static content on the server before sending it to the browser. Add the [client_secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) in your checkout form. In your server-side code, retrieve the client secret from the PaymentIntent: #### Ruby ```erb
``` ```ruby get '/checkout' do @intent = # ... Fetch or create the PaymentIntent erb :checkout end ``` #### Python ```html
``` ```python @app.route('/checkout') def checkout(): intent = # ... Fetch or create the PaymentIntent return render_template('checkout.html', client_secret=intent.client_secret) ``` #### PHP ```php ...
... ``` #### Java ```html
``` ```java import java.util.HashMap; import java.util.Map; import com.stripe.model.PaymentIntent; import spark.ModelAndView; import static spark.Spark.get; public class StripeJavaQuickStart { public static void main(String[] args) { get("/checkout", (request, response) -> { PaymentIntent intent = // ... Fetch or create the PaymentIntent Map map = new HashMap(); map.put("client_secret", intent.getClientSecret()); return new ModelAndView(map, "checkout.hbs"); }, new HandlebarsTemplateEngine()); } } ``` #### Node.js ```html
``` ```javascript const express = require('express'); const expressHandlebars = require('express-handlebars'); const app = express(); app.engine('.hbs', expressHandlebars({ extname: '.hbs' })); app.set('view engine', '.hbs'); app.set('views', './views'); app.get('/checkout', async (req, res) => { const intent = // ... Fetch or create the PaymentIntent res.render('checkout', { client_secret: intent.client_secret }); }); app.listen(3000, () => { console.log('Running on port 3000'); }); ``` #### Go ```html
``` ```go package main import ( "html/template" "net/http" stripe "github.com/stripe/stripe-go/v76.0.0" ) type CheckoutData struct { ClientSecret string } func main() { checkoutTmpl := template.Must(template.ParseFiles("views/checkout.html")) http.HandleFunc("/checkout", func(w http.ResponseWriter, r *http.Request) { intent := // ... Fetch or create the PaymentIntent data := CheckoutData{ ClientSecret: intent.ClientSecret, } checkoutTmpl.Execute(w, data) }) http.ListenAndServe(":3000", nil) } ``` #### .NET ```html
``` ```csharp using System; using Microsoft.AspNetCore.Mvc; using Stripe; namespace StripeExampleApi.Controllers { [Route("/[controller]")] public class CheckoutApiController : Controller { public IActionResult Index() { var intent = // ... Fetch or create the PaymentIntent ViewData["ClientSecret"] = intent.ClientSecret; return View(); } } } ``` ## Collect payment details [Client-side] Collect payment details on the client with the [Payment Element](https://docs.stripe.com/payments/payment-element.md). The Payment Element is a prebuilt UI component that simplifies collecting payment details for a variety of payment methods. The Payment Element contains an iframe that securely sends payment information to Stripe over an HTTPS connection. Avoid placing the Payment Element within another iframe because some payment methods require redirecting to another page for payment confirmation. If you do choose to use an iframe and want to accept Apple Pay or Google Pay, the iframe must have the [allow](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allowpaymentrequest) attribute set to equal `"payment *"`. The checkout page address must start with `https://` rather than `http://` for your integration to work. You can test your integration without using HTTPS, but remember to [enable it](https://docs.stripe.com/security/guide.md#tls) when you’re ready to accept live payments. #### HTML + JS ### Set up Stripe.js The Payment Element is automatically available as a feature of Stripe.js. Include the Stripe.js script on your checkout page by adding it to the `head` of your HTML file. Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Don’t include the script in a bundle or host a copy of it yourself. ```html Checkout ``` Create an instance of Stripe with the following JavaScript on your checkout page: ```javascript // Set your publishable key: remember to change this to your live publishable key in production // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe('<>'); ``` ### Add the Payment Element to your payment page The Payment Element needs a place to live on your payment page. Create an empty DOM node (container) with a unique ID in your payment form: ```html
``` When the previous form loads, create an instance of the Payment Element and mount it to the container DOM node. Pass the [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) from the previous step into `options` when you create the [Elements](https://docs.stripe.com/js/elements_object/create) instance: Handle the client secret carefully because it can complete the charge. Don’t log it, embed it in URLs, or expose it to anyone but the customer. ```javascript const options = { clientSecret: '{{CLIENT_SECRET}}', // Fully customizable with appearance API. appearance: {/*...*/}, }; // Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in a previous stepconst elements = stripe.elements(options); // Create and mount the Payment Element const paymentElementOptions = { layout: 'accordion'}; const paymentElement = elements.create('payment', paymentElementOptions); paymentElement.mount('#payment-element'); ``` #### React ### Set up Stripe.js Install [React Stripe.js](https://www.npmjs.com/package/@stripe/react-stripe-js) and the [Stripe.js loader](https://www.npmjs.com/package/@stripe/stripe-js) from the npm public registry: ```bash npm install --save @stripe/react-stripe-js @stripe/stripe-js ``` ### Add and configure the Elements provider to your payment page To use the Payment Element component, wrap your checkout page component in an [Elements provider](https://docs.stripe.com/sdks/stripejs-react.md#elements-provider). Call `loadStripe` with your publishable key, and pass the returned `Promise` to the `Elements` provider. Also pass the [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) from the previous step as `options` to the `Elements` provider. ```jsx import React from 'react'; import ReactDOM from 'react-dom'; import {Elements} from '@stripe/react-stripe-js'; import {loadStripe} from '@stripe/stripe-js'; import CheckoutForm from './CheckoutForm'; // Make sure to call `loadStripe` outside of a component’s render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe('<>'); function App() { const options = { // passing the client secret obtained in step 3 clientSecret: '{{CLIENT_SECRET}}', // Fully customizable with appearance API. appearance: {/*...*/}, }; return ( ); }; ReactDOM.render(, document.getElementById('root')); ``` ### Add the Payment Element component Use the `PaymentElement` component to build your form: ```jsx import React from 'react'; import {PaymentElement} from '@stripe/react-stripe-js'; const CheckoutForm = () => { return (
); }; export default CheckoutForm; ``` Stripe Elements is a collection of drop-in UI components. To further customize your form or collect different customer information, browse the [Elements docs](https://docs.stripe.com/payments/elements.md). The Payment Element renders a dynamic form that allows your customer to pick a payment method. For each payment method, the form automatically asks the customer to fill in all necessary payment details. ### Customize appearance Customize the Payment Element to match the design of your site by passing the [appearance object](https://docs.stripe.com/js/elements_object/create#stripe_elements-options-appearance) into `options` when creating the `Elements` provider. ### Collect addresses By default, the Payment Element only collects the necessary billing address details. Some behavior, such as [calculating tax](https://docs.stripe.com/api/tax/calculations/create.md) or entering shipping details, requires your customer’s full address. You can: - Use the [Address Element](https://docs.stripe.com/elements/address-element.md) to take advantage of autocomplete and localization features to collect your customer’s full address. This helps ensure the most accurate tax calculation. - Collect address details using your own custom form. ### Request Apple Pay merchant token If you’ve configured your integration to [accept Apple Pay payments](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=paymentintents#apple-pay-and-google-pay), we recommend configuring the Apple Pay interface to return a merchant token to enable merchant initiated transactions (MIT). [Request the relevant merchant token type](https://docs.stripe.com/apple-pay/merchant-tokens.md?pay-element=web-pe) in the Payment Element. ## Optional: Save and retrieve customer payment methods You can configure the Payment Element to save your customer’s payment methods for future use. This section shows you how to integrate the [saved payment methods feature](https://docs.stripe.com/payments/save-customer-payment-methods.md), which enables the Payment Element to: - Prompt buyers for consent to save a payment method - Save payment methods when buyers provide consent - Display saved payment methods to buyers for future purchases - [Automatically update lost or expired cards](https://docs.stripe.com/payments/cards/overview.md#automatic-card-updates) when buyers replace them ![The Payment Element and a saved payment method checkbox](https://b.stripecdn.com/docs-statics-srv/assets/spm-save.fe0b24afd0f0a06e0cf4eecb0ce2403a.png) Save payment methods. ![The Payment Element with a Saved payment method selected](https://b.stripecdn.com/docs-statics-srv/assets/spm-saved.5dba5a8a190a9a0e9f1a99271bed3f4b.png) Reuse a previously saved payment method. ### Enable saving the payment method in the Payment Element When creating a [PaymentIntent](https://docs.stripe.com/api/payment_intents/.md) on your server, also create a [CustomerSession](https://docs.stripe.com/api/customer_sessions/.md) providing the [Customer ID](https://docs.stripe.com/api/customers/object.md#customer_object-id) and enabling the [payment_element](https://docs.stripe.com/api/customer_sessions/object.md#customer_session_object-components-payment_element) component for your session. Configure which saved payment method [features](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components-payment_element-features) you want to enable. For instance, enabling [payment_method_save](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components-payment_element-features-payment_method_save) displays a checkbox offering customers to save their payment details for future use. You can specify `setup_future_usage` on a PaymentIntent or Checkout Session to override the default behavior for saving payment methods. This ensures that you automatically save the payment method for future use, even if the customer doesn’t explicitly choose to save it. > Allowing buyers to remove their saved payment methods by enabling [payment_method_remove](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components-payment_element-features-payment_method_remove) impacts subscriptions that depend on that payment method. Removing the payment method detaches the [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) from that [Customer](https://docs.stripe.com/api/customers.md). #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' post '/create-intent-and-customer-session' do intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods: {enabled: true}, customer: {{CUSTOMER_ID}}, }) customer_session = Stripe::CustomerSession.create({ customer: {{CUSTOMER_ID}}, components: { payment_element: { enabled: true, features: { payment_method_redisplay: 'enabled', payment_method_save: 'enabled', payment_method_save_usage: 'off_session', payment_method_remove: 'enabled', }, }, }, }) { client_secret: intent.client_secret, customer_session_client_secret: customer_session.client_secret }.to_json end ``` #### Python ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' @app.route('/create-intent-and-customer-session', methods=['POST']) def createIntentAndCustomerSession(): intent = stripe.PaymentIntent.create( amount=1099, currency='usd', # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods={ 'enabled': True, }, customer={{CUSTOMER_ID}}, ) customer_session = stripe.CustomerSession.create( customer={{CUSTOMER_ID}}, components={ "payment_element": { "enabled": True, "features": { "payment_method_redisplay": "enabled", "payment_method_save": "enabled", "payment_method_save_usage": "off_session", "payment_method_remove": "enabled", }, }, }, ) return jsonify( client_secret=intent.client_secret, customer_session_client_secret=customer_session.client_secret ) ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $intent = $stripe->paymentIntents->create( [ 'amount' => 1099, 'currency' => 'usd', // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. 'automatic_payment_methods' => ['enabled' => true], 'customer' => {{CUSTOMER_ID}}, ] ); $customer_session = $stripe->customerSessions->create([ 'customer' => {{CUSTOMER_ID}}, 'components' => [ 'payment_element' => [ 'enabled' => true, 'features' => [ 'payment_method_redisplay' => 'enabled', 'payment_method_save' => 'enabled', 'payment_method_save_usage' => 'off_session', 'payment_method_remove' => 'enabled', ], ], ], ]); echo json_encode(array( 'client_secret' => $intent->client_secret, 'customer_session_client_secret' => $customer_session->client_secret )); ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); app.post('/create-intent-and-customer-session', async (req, res) => { const intent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. automatic_payment_methods: {enabled: true}, customer: {{CUSTOMER_ID}}, }); const customerSession = await stripe.customerSessions.create({ customer: {{CUSTOMER_ID}}, components: { payment_element: { enabled: true, features: { payment_method_redisplay: 'enabled', payment_method_save: 'enabled', payment_method_save_usage: 'off_session', payment_method_remove: 'enabled', }, }, }, }); res.json({ client_secret: intent.client_secret, customer_session_client_secret: customerSession.client_secret }); }); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; post( "/create-intent-and-customer-session", (request, response) -> { response.type("application/json"); PaymentIntentCreateParams intentParams = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder().setEnabled(true).build() ) .setCustomer({{CUSTOMER_ID}}) .build(); PaymentIntent paymentIntent = PaymentIntent.create(intentParams); CustomerSessionCreateParams csParams = CustomerSessionCreateParams.builder() .setCustomer({{CUSTOMER_ID}}) .setComponents(CustomerSessionCreateParams.Components.builder().build()) .putExtraParam("components[payment_element][enabled]", true) .putExtraParam( "components[payment_element][features][payment_method_redisplay]", "enabled" ) .putExtraParam( "components[payment_element][features][payment_method_save]", "enabled" ) .putExtraParam( "components[payment_element][features][payment_method_save_usage]", "off_session" ) .putExtraParam( "components[payment_element][features][payment_method_remove]", "enabled" ) .build(); CustomerSession customerSession = CustomerSession.create(csParams); Map responseData = new HashMap<>(); responseData.put("clientSecret", paymentIntent.getClientSecret()); responseData.put("customerSessionClientSecret", customerSession.getClientSecret()); return StripeObject.PRETTY_PRINT_GSON.toJson(responseData); } ); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" type CheckoutData struct { ClientSecret string `json:"client_secret"` CustomerSessionClientSecret string `json:"customer_session_client_secret"` } func main() { http.HandleFunc("/create-intent-and-customer-session", func(w http.ResponseWriter, r *http.Request) { intentParams := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods: &stripe.PaymentIntentAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, Customer: stripe.String({{CUSTOMER_ID}}), }; intent, _ := .New(intentParams); csParams := &stripe.CustomerSessionParams{ Customer: stripe.String({{CUSTOMER_ID}}), Components: &stripe.CustomerSessionComponentsParams{}, } csParam.AddExtra("components[payment_element][enabled]", true) csParam.AddExtra( "components[payment_element][features][payment_method_redisplay]", "enabled", ) csParam.AddExtra( "components[payment_element][features][payment_method_save]", "enabled", ) csParam.AddExtra( "components[payment_element][features][payment_method_save_usage]", "off_session", ) csParam.AddExtra( "components[payment_element][features][payment_method_remove]", "enabled", ) customerSession, _ := customersession.New(csParams) data := CheckoutData{ ClientSecret: intent.ClientSecret, CustomerSessionClientSecret: customerSession.ClientSecret } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(data) }) } ``` #### .NET ```csharp // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; namespace StripeExampleApi.Controllers { [Route("create-intent-and-customer-session")] [ApiController] public class CheckoutApiController : Controller { [HttpPost] public ActionResult Post() { var intentOptions = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, Customer = {{CUSTOMER_ID}}, }; var intentService = new PaymentIntentService(); var intent = intentService.Create(intentOptions); var customerSessionOptions = new CustomerSessionCreateOptions { Customer = {{CUSTOMER_ID}}, Components = new CustomerSessionComponentsOptions(), } customerSessionOptions.AddExtraParam("components[payment_element][enabled]", true); customerSessionOptions.AddExtraParam( "components[payment_element][features][payment_method_redisplay]", "enabled"); customerSessionOptions.AddExtraParam( "components[payment_element][features][payment_method_save]", "enabled"); customerSessionOptions.AddExtraParam( "components[payment_element][features][payment_method_save_usage]", "off_session"); customerSessionOptions.AddExtraParam( "components[payment_element][features][payment_method_remove]", "enabled"); var customerSessionService = new CustomerSessionService(); var customerSession = customerSessionService.Create(customerSessionOptions); return Json(new { client_secret = intent.ClientSecret, customerSessionClientSecret = customerSession.ClientSecret }); } } } ``` Your Elements instance uses the CustomerSession’s *client secret* (A client secret is used with your publishable key to authenticate a request for a single object. Each client secret is unique to the object it's associated with) to access that customer’s saved payment methods. [Handle errors](https://docs.stripe.com/error-handling.md) properly when you create the CustomerSession. If an error occurs, you don’t need to provide the CustomerSession client secret to the Elements instance, as it’s optional. Create the Elements instance using the client secrets for both the PaymentIntent and the CustomerSession. Then, use this Elements instance to create a Payment Element. ```javascript // Create the CustomerSession and obtain its clientSecret const res = await fetch("/create-intent-and-customer-session", { method: "POST" }); const { customer_session_client_secret: customerSessionClientSecret } = await res.json(); const elementsOptions = { clientSecret: '{{CLIENT_SECRET}}',customerSessionClientSecret, // Fully customizable with appearance API. appearance: {/*...*/}, }; // Set up Stripe.js and Elements to use in checkout form, passing the client secret // and CustomerSession's client secret obtained in a previous step const elements = stripe.elements(elementsOptions); // Create and mount the Payment Element const paymentElementOptions = { layout: 'accordion'}; const paymentElement = elements.create('payment', paymentElementOptions); paymentElement.mount('#payment-element'); ``` When confirming the PaymentIntent, Stripe.js automatically controls setting [setup_future_usage](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-setup_future_usage) on the PaymentIntent and [allow_redisplay](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-allow_redisplay) on the PaymentMethod, depending on whether the customer checked the box to save their payment details. ### Enforce CVC recollection Optionally, specify `require_cvc_recollection` [when creating the PaymentIntent](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-payment_method_options-card-require_cvc_recollection) to enforce CVC recollection when a customer is paying with a card. ### Detect the selection of a saved payment method To control dynamic content when a saved payment method is selected, listen to the Payment Element `change` event, which is populated with the selected payment method. ```javascript paymentElement.on('change', function(event) { if (event.value.payment_method) { // Control dynamic content if a saved payment method is selected } }) ``` ## Optional: Link in your checkout page [Client-side] Let your customer check out faster by using [Link](https://docs.stripe.com/payments/link.md) in the [Payment Element](https://docs.stripe.com/payments/payment-element.md). You can autofill information for any logged-in customer already using Link, regardless of whether they initially saved their information in Link with another business. The default Payment Element integration includes a Link prompt in the card form. To manage Link in the Payment Element, go to your [payment method settings](https://dashboard.stripe.com/settings/payment_methods). ![Authenticate or enroll with Link directly in the Payment Element during checkout](https://b.stripecdn.com/docs-statics-srv/assets/link-in-pe.2efb5138a4708b781b8a913ebddd9aba.png) Collect a customer email address for Link authentication or enrollment ### Integration options There are two ways you can integrate Link with the Payment Element. Of these, Stripe recommends passing a customer email address to the Payment Element if available. Remember to consider how your checkout flow works when deciding between these options: | Integration option | Checkout flow | Description | | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Pass a customer email address to the Payment Element (Recommended) | - Your customer enters their email address before landing on the checkout page (in a previous account creation step, for example). - You prefer to use your own email input field. | Programmatically pass a customer email address to the Payment Element. In this scenario, a customer authenticates to Link directly in the payment form instead of a separate UI component. | | Collect a customer email address in the Payment Element | - Your customers can choose to enter their email and authenticate or enroll with Link directly in the Payment Element during checkout. - No code change is required. | If a customer hasn’t enrolled with Link and they choose a supported payment method in the Payment Element, they’re prompted to save their details using Link. For those who have already enrolled, Link automatically populates their payment information. | Use [defaultValues](https://docs.stripe.com/js/elements_object/create_payment_element#payment_element_create-options-defaultValues) to pass a customer email address to the Payment Element. ```javascript const paymentElement = elements.create('payment', { defaultValues: { billingDetails: { email: 'foo@bar.com', } }, // Other options }); ``` For more information, read how to [build a custom checkout page that includes Link](https://docs.stripe.com/payments/link/add-link-elements-integration.md). ## Optional: Fetch updates from the server [Client-side] You might want to update attributes on the PaymentIntent after the Payment Element renders, such as the [amount](https://docs.stripe.com/api/payment_intents/update.md#update_payment_intent-amount) (for example, discount codes or shipping costs). You can [update the PaymentIntent](https://docs.stripe.com/api/payment_intents/update.md) on your server, then call [elements.fetchUpdates](https://docs.stripe.com/js/elements_object/fetch_updates) to see the new amount reflected in the Payment Element. This example shows you how to create the server endpoint that updates the amount on the PaymentIntent: #### Ruby ```ruby get '/update' do intent = Stripe::PaymentIntent.update( '{{PAYMENT_INTENT_ID}}', {amount: 1499}, ) {status: intent.status}.to_json end ``` #### Python ```python @app.route('/update') def secret(): intent = stripe.PaymentIntent.modify( "{{PAYMENT_INTENT_ID}}", amount=1499, ) return jsonify(status=intent.status) ``` #### PHP ```php paymentIntents->update( '{{PAYMENT_INTENT_ID}}', ['amount' => 1499] ); echo json_encode(array('status' => $intent->status)); ?> ``` #### Java ```java import java.util.HashMap; import java.util.Map; import com.stripe.model.PaymentIntent; import com.google.gson.Gson; import static spark.Spark.get; public class StripeJavaQuickStart { public static void main(String[] args) { Gson gson = new Gson(); get("/update", (request, response) -> { PaymentIntent paymentIntent = PaymentIntent.retrieve( "{{PAYMENT_INTENT_ID}}" ); Map params = new HashMap<>(); params.put("amount", 1499); PaymentIntent updatedPaymentIntent = paymentIntent.update(params); Map response = new HashMap(); response.put("status", updatedPaymentIntent.getStatus()); return map; }, gson::toJson); } } ``` #### Node.js ```javascript app.get('/update', async (req, res) => { const intent = await stripe.paymentIntents.update( '{{PAYMENT_INTENT_ID}}', {amount: 1499} ); res.json({status: intent.status}); }); ``` #### Go ```go package main import ( "encoding/json" "net/http" stripe "github.com/stripe/stripe-go/v76.0.0" ) type UpdateData struct { Status string `json:"status"` } func main() { http.HandleFunc("/update", func(w http.ResponseWriter, r *http.Request) { params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1499), } pi, _ := paymentintent.Update( "{{PAYMENT_INTENT_ID}}", params, ) data := UpdateData{ Status: pi.Status, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(data) }) http.ListenAndServe(":3000", nil) } ``` #### .NET ```csharp using System; using Microsoft.AspNetCore.Mvc; using Stripe; namespace StripeExampleApi.Controllers { [Route("update")] [ApiController] public class CheckoutApiController : Controller { [HttpPost] public ActionResult Post() { var options = new PaymentIntentUpdateOptions { Amount = 1499, }; var service = new PaymentIntentService(); var intent = service.Update( "{{PAYMENT_INTENT_ID}}", options); return Json(new {status = intent.Status}); } } } ``` This example demonstrates how to update the UI to reflect these changes on the client side: ```javascript (async () => { const response = await fetch('/update'); if (response.status === 'requires_payment_method') { const {error} = await elements.fetchUpdates(); } })(); ``` ## Submit the payment to Stripe [Client-side] Use [stripe.confirmPayment](https://docs.stripe.com/js/payment_intents/confirm_payment) to complete the payment using details from the Payment Element. Provide a [return_url](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-return_url) to this function to indicate where Stripe should redirect the user after they complete the payment. Your user may be first redirected to an intermediate site, like a bank authorization page, before being redirected to the `return_url`. Card payments immediately redirect to the `return_url` when a payment is successful. If you don’t want to redirect for card payments after payment completion, you can set [redirect](https://docs.stripe.com/js/payment_intents/confirm_payment#confirm_payment_intent-options-redirect) to `if_required`. This only redirects customers that check out with redirect-based payment methods. #### HTML + JS ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', async (event) => { event.preventDefault(); const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // This point will only be reached if there is an immediate error when // confirming the payment. Show error to your customer (for example, payment // details incomplete) const messageContainer = document.querySelector('#error-message'); messageContainer.textContent = error.message; } else { // Your customer will be redirected to your `return_url`. For some payment // methods like iDEAL, your customer will be redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } }); ``` #### React To call [stripe.confirmPayment](https://docs.stripe.com/js/payment_intents/confirm_payment) from your payment form component, use the [useStripe](https://docs.stripe.com/sdks/stripejs-react.md#usestripe-hook) and [useElements](https://docs.stripe.com/sdks/stripejs-react.md#useelements-hook) hooks. If you prefer traditional class components over hooks, you can instead use an [ElementsConsumer](https://docs.stripe.com/sdks/stripejs-react.md#elements-consumer). ```jsx import React, {useState} from 'react'; import {useStripe, useElements, PaymentElement} from '@stripe/react-stripe-js'; const CheckoutForm = () => { const stripe = useStripe(); const elements = useElements(); const [errorMessage, setErrorMessage] = useState(null); const handleSubmit = async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); if (!stripe || !elements) { // Stripe.js hasn't yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; } const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // This point will only be reached if there is an immediate error when // confirming the payment. Show error to your customer (for example, payment // details incomplete) setErrorMessage(error.message); } else { // Your customer will be redirected to your `return_url`. For some payment // methods like iDEAL, your customer will be redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } }; return (
{/* Show error message to your customers */} {errorMessage &&
{errorMessage}
} ) }; export default CheckoutForm; ``` Make sure the `return_url` corresponds to a page on your website that provides the status of the payment. When Stripe redirects the customer to the `return_url`, we provide the following URL query parameters: | Parameter | Description | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | `payment_intent` | The unique identifier for the `PaymentIntent`. | | `payment_intent_client_secret` | The [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) of the `PaymentIntent` object. | > If you have tooling that tracks the customer’s browser session, you might need to add the `stripe.com` domain to the referrer exclude list. Redirects cause some tools to create new sessions, which prevents you from tracking the complete session. Use one of the query parameters to retrieve the PaymentIntent. Inspect the [status of the PaymentIntent](https://docs.stripe.com/payments/paymentintents/lifecycle.md) to decide what to show your customers. You can also append your own query parameters when providing the `return_url`, which persist through the redirect process. #### HTML + JS ```javascript // Initialize Stripe.js using your publishable key const stripe = Stripe('<>'); // Retrieve the "payment_intent_client_secret" query parameter appended to // your return_url by Stripe.js const clientSecret = new URLSearchParams(window.location.search).get( 'payment_intent_client_secret' ); // Retrieve the PaymentIntent stripe.retrievePaymentIntent(clientSecret).then(({paymentIntent}) => { const message = document.querySelector('#message') // Inspect the PaymentIntent `status` to indicate the status of the payment // to your customer. // // Some payment methods will [immediately succeed or fail][0] upon // confirmation, while others will first enter a `processing` state. // // [0]: https://stripe.com/docs/payments/payment-methods#payment-notification switch (paymentIntent.status) { case 'succeeded': message.innerText = 'Success! Payment received.'; break; case 'processing': message.innerText = "Payment processing. We'll update you when payment is received."; break; case 'requires_payment_method': message.innerText = 'Payment failed. Please try another payment method.'; // Redirect your user back to your payment page to attempt collecting // payment again break; default: message.innerText = 'Something went wrong.'; break; } }); ``` #### React ```jsx import React, {useState, useEffect} from 'react'; import {useStripe} from '@stripe/react-stripe-js'; const PaymentStatus = () => { const stripe = useStripe(); const [message, setMessage] = useState(null); useEffect(() => { if (!stripe) { return; } // Retrieve the "payment_intent_client_secret" query parameter appended to // your return_url by Stripe.js const clientSecret = new URLSearchParams(window.location.search).get( 'payment_intent_client_secret' ); // Retrieve the PaymentIntent stripe .retrievePaymentIntent(clientSecret) .then(({paymentIntent}) => { // Inspect the PaymentIntent `status` to indicate the status of the payment // to your customer. // // Some payment methods will [immediately succeed or fail][0] upon // confirmation, while others will first enter a `processing` state. // // [0]: https://stripe.com/docs/payments/payment-methods#payment-notification switch (paymentIntent.status) { case 'succeeded': setMessage('Success! Payment received.'); break; case 'processing': setMessage("Payment processing. We'll update you when payment is received."); break; case 'requires_payment_method': // Redirect your user back to your payment page to attempt collecting // payment again setMessage('Payment failed. Please try another payment method.'); break; default: setMessage('Something went wrong.'); break; } }); }, [stripe]); return message; }; export default PaymentStatus; ``` ## Handle post-payment events [Server-side] Stripe sends a [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) event when the payment completes. Use the [Dashboard webhook tool](https://dashboard.stripe.com/webhooks) or follow the [webhook guide](https://docs.stripe.com/webhooks/quickstart.md) to receive these events and run actions, such as sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow. Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events is what enables you to accept [different types of payment methods](https://stripe.com/payments/payment-methods-guide) with a single integration. In addition to handling the `payment_intent.succeeded` event, we recommend handling these other events when collecting payments with the Payment Element: | Event | Description | Action | | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.succeeded) | Sent when a customer successfully completes a payment. | Send the customer an order confirmation and *fulfill* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) their order. | | [payment_intent.processing](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.processing) | Sent when a customer successfully initiates a payment, but the payment has yet to complete. This event is most commonly sent when the customer initiates a bank debit. It’s followed by either a `payment_intent.succeeded` or `payment_intent.payment_failed` event in the future. | Send the customer an order confirmation that indicates their payment is pending. For digital goods, you might want to fulfill the order before waiting for payment to complete. | | [payment_intent.payment_failed](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.payment_failed) | Sent when a customer attempts a payment, but the payment fails. | If a payment transitions from `processing` to `payment_failed`, offer the customer another attempt to pay. | ## Test your integration To test your custom payments integration: 1. Create a Payment Intent and retrieve the client secret. 1. Fill out the payment details with a method from the following table. - Enter any future date for card expiry. - Enter any 3-digit number for CVC. - Enter any billing postal code. 1. Submit the payment to Stripe. You’re redirected to your `return_url`. 1. Go to the Dashboard and look for the payment on the [Transactions page](https://dashboard.stripe.com/test/payments?status%5B0%5D=successful). If your payment succeeded, you’ll see it in that list. 1. Click your payment to see more details, like billing information and the list of purchased items. You can use this information to fulfill the order. Learn more about [testing your integration](https://docs.stripe.com/testing.md). #### Cards | Card number | Scenario | How to test | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | 4242424242424242 | The card payment succeeds and doesn’t require authentication. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000002500003155 | The card payment requires *authentication* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase). | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000000000009995 | The card is declined with a decline code like `insufficient_funds`. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 6205500000000000004 | The UnionPay card has a variable length of 13-19 digits. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | #### Wallets | Payment method | Scenario | How to test | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Alipay | Your customer successfully pays with a redirect-based and [immediate notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | #### Bank redirects | Payment method | Scenario | How to test | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | BECS Direct Debit | Your customer successfully pays with BECS Direct Debit. | Fill out the form using the account number `900123456` and BSB `000000`. The confirmed PaymentIntent initially transitions to `processing`, then transitions to the `succeeded` status 3 minutes later. | | BECS Direct Debit | Your customer’s payment fails with an `account_closed` error code. | Fill out the form using the account number `111111113` and BSB `000000`. | | Bancontact, EPS, iDEAL, and Przelewy24 | Your customer fails to authenticate on the redirect page for a redirect-based and immediate notification payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | Pay by Bank | Your customer successfully pays with a redirect-based and [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | | Pay by Bank | Your customer fails to authenticate on the redirect page for a redirect-based and delayed notification payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | BLIK | BLIK payments fail in a variety of ways—immediate failures (for example, the code is expired or invalid), delayed errors (the bank declines) or timeouts (the customer didn’t respond in time). | Use email patterns to [simulate the different failures.](https://docs.stripe.com/payments/blik/accept-a-payment.md#simulate-failures) | #### Bank debits | Payment method | Scenario | How to test | | ----------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SEPA Direct Debit | Your customer successfully pays with SEPA Direct Debit. | Fill out the form using the account number `AT321904300235473204`. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later. | | SEPA Direct Debit | Your customer’s payment intent status transitions from `processing` to `requires_payment_method`. | Fill out the form using the account number `AT861904300235473202`. | #### Vouchers | Payment method | Scenario | How to test | | -------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | Boleto, OXXO | Your customer pays with a Boleto or OXXO voucher. | Select Boleto or OXXO as the payment method and submit the payment. Close the dialog after it appears. | See [Testing](https://docs.stripe.com/testing.md) for additional information to test your integration. ## Optional: Add more payment methods The Payment Element [supports many payment methods](https://docs.stripe.com/payments/payment-methods/integration-options.md#choose-how-to-add-payment-methods) by default. You have to take additional steps to enable and display some payment methods. ### Affirm To begin using Affirm, you must enable it in the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). When you create a PaymentIntent with the Affirm payment method, you need to include a [shipping address](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-shipping). This example suggests passing the shipping information on the client after the customer [selects their payment method](https://docs.stripe.com/payments/accept-a-payment.md#web-create-intent). Learn more about using [Affirm](https://docs.stripe.com/payments/affirm.md) with Stripe. #### HTML + JS ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', async (event) => { event.preventDefault(); const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, confirmParams: { return_url: 'https://my-site.com/order/123/complete',shipping: { name: 'Jenny Rosen', address: { line1: '1 Street', city: 'Seattle', state: 'WA', postal_code: '95123', country: 'US' } }, } }); if (error) { // This point is reached if there's an immediate error when // confirming the payment. Show error to your customer (for example, // payment details incomplete) const messageContainer = document.querySelector('#error-message'); messageContainer.textContent = error.message; } else { // Your customer is redirected to your `return_url`. For some payment // methods like iDEAL, your customer is redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } }); ``` #### React ```jsx import React, {useState} from 'react'; import {useStripe, useElements, PaymentElement} from '@stripe/react-stripe-js'; const CheckoutForm = () => { const stripe = useStripe(); const elements = useElements(); const [errorMessage, setErrorMessage] = useState(null); const handleSubmit = async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); if (!stripe || !elements) { // Stripe.js hasn't yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; } const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, confirmParams: { return_url: 'https://my-site.com/order/123/complete',shipping: { name: 'Jenny Rosen', address: { line1: '1 Street', city: 'Seattle', state: 'WA', postal_code: '95123', country: 'US' } }, } }); if (error) { // This point will only be reached if there is an immediate error when // confirming the payment. Show error to your customer (for example, // payment details incomplete) setErrorMessage(error.message); } else { // Your customer will be redirected to your `return_url`. For some payment // methods like iDEAL, your customer will be redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } }; return (
{/* Show error message to your customers */} {errorMessage &&
{errorMessage}
} ) }; export default CheckoutForm; ``` #### Test Affirm Learn how to test different scenarios using the following table: | Scenario | How to test | | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | Your customer successfully pays with Affirm. | Fill out the form (make sure to include a shipping address) and authenticate the payment. | | Your customer fails to authenticate on the Affirm redirect page. | Fill out the form and click **Fail test payment** on the redirect page. | ### Afterpay (Clearpay) When you create a PaymentIntent with the Afterpay payment method, you need to include a [shipping address](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-shipping). Learn more about using [Afterpay](https://docs.stripe.com/payments/afterpay-clearpay.md) with Stripe. You can manage payment methods from the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow. The example below uses the [automatic_payment_methods](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-automatic_payment_methods-enabled) attribute but you can list `afterpay_clearpay` with [payment method types](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-payment_method_types). In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. Regardless of which option you choose, make sure that you enable Afterpay Clearpay in the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "automatic_payment_methods[enabled]"=true \ -d "shipping[name]"="Jenny Rosen" \ -d "shipping[address][line1]"="1234 Main Street" \ -d "shipping[address][city]"="San Francisco" \ -d "shipping[address][state]"=CA \ -d "shipping[address][country]"=US \ -d "shipping[address][postal_code]"=94111 ``` ```cli stripe payment_intents create \ --amount=1099 \ --currency=usd \ -d "automatic_payment_methods[enabled]"=true \ -d "shipping[name]"="Jenny Rosen" \ -d "shipping[address][line1]"="1234 Main Street" \ -d "shipping[address][city]"="San Francisco" \ -d "shipping[address][state]"=CA \ -d "shipping[address][country]"=US \ -d "shipping[address][postal_code]"=94111 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, shipping: { name: 'Jenny Rosen', address: { line1: '1234 Main Street', city: 'San Francisco', state: 'CA', country: 'US', postal_code: '94111', }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 1099, "currency": "usd", "automatic_payment_methods": {"enabled": True}, "shipping": { "name": "Jenny Rosen", "address": { "line1": "1234 Main Street", "city": "San Francisco", "state": "CA", "country": "US", "postal_code": "94111", }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'usd', 'automatic_payment_methods' => ['enabled' => true], 'shipping' => [ 'name' => 'Jenny Rosen', 'address' => [ 'line1' => '1234 Main Street', 'city' => 'San Francisco', 'state' => 'CA', 'country' => 'US', 'postal_code' => '94111', ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder().setEnabled(true).build() ) .setShipping( PaymentIntentCreateParams.Shipping.builder() .setName("Jenny Rosen") .setAddress( PaymentIntentCreateParams.Shipping.Address.builder() .setLine1("1234 Main Street") .setCity("San Francisco") .setState("CA") .setCountry("US") .setPostalCode("94111") .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', automatic_payment_methods: { enabled: true, }, shipping: { name: 'Jenny Rosen', address: { line1: '1234 Main Street', city: 'San Francisco', state: 'CA', country: 'US', postal_code: '94111', }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(1099), Currency: stripe.String(stripe.CurrencyUSD), AutomaticPaymentMethods: &stripe.PaymentIntentCreateAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, Shipping: &stripe.ShippingDetailsParams{ Name: stripe.String("Jenny Rosen"), Address: &stripe.AddressParams{ Line1: stripe.String("1234 Main Street"), City: stripe.String("San Francisco"), State: stripe.String("CA"), Country: stripe.String("US"), PostalCode: stripe.String("94111"), }, }, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, Shipping = new ChargeShippingOptions { Name = "Jenny Rosen", Address = new AddressOptions { Line1 = "1234 Main Street", City = "San Francisco", State = "CA", Country = "US", PostalCode = "94111", }, }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` #### Test Afterpay (Clearpay) Learn how to test different scenarios using the following table: | Scenario | How to test | | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- | | Your customer successfully pays with Afterpay. | Fill out the form (make sure to include a shipping address) and authenticate the payment. | | Your customer fails to authenticate on the Afterpay redirect page. | Fill out the form and click **Fail test payment** on the redirect page. | ### Apple Pay and Google Pay When you [enable card payments](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=paymentintents#create-the-paymentintent), we display Apple Pay and Google Pay for customers whose environment meets the [wallet display conditions](https://docs.stripe.com/testing/wallets.md). To accept payments from these wallets, you must also: - Enable them in your [payment methods settings](https://dashboard.stripe.com/settings/payment_methods). Apple Pay is enabled by default. - Serve your application over HTTPS in development and production. - [Register your domain](https://docs.stripe.com/payments/payment-methods/pmd-registration.md). - [Fetch updates from the server](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=paymentintents#fetch-updates) if you update the amount of a [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) to keep the wallet’s payment modal in sync. > #### Regional Testing > > Stripe Elements doesn’t support Google Pay or Apple Pay for Stripe accounts and customers in India. Therefore, you can’t test your Google Pay or Apple Pay integration if the tester’s IP address is in India, even if the Stripe account is based outside India. Learn more about using [Apple Pay](https://docs.stripe.com/apple-pay.md) and [Google Pay](https://docs.stripe.com/google-pay.md) with Stripe. ### ACH Direct Debit When using the Payment Element with the ACH Direct Debit payment method, follow these steps: 1. Create a [Customer object](https://docs.stripe.com/api/customers.md). ```curl curl -X POST https://api.stripe.com/v1/customers \ -u "<>:" ``` ```cli stripe customers create ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer = client.v1.customers.create() ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer = client.v1.customers.create() ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $customer = $stripe->customers->create([]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CustomerCreateParams params = CustomerCreateParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Customer customer = client.v1().customers().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const customer = await stripe.customers.create(); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerCreateParams{} result, err := sc.V1Customers.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CustomerCreateOptions(); var client = new StripeClient("<>"); var service = client.V1.Customers; Customer customer = service.Create(options); ``` 1. Specify the customer ID when creating the `PaymentIntent`. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d setup_future_usage=off_session \ -d customer={{CUSTOMER_ID}} \ -d "payment_method_types[]"=us_bank_account ``` ```cli stripe payment_intents create \ --amount=1099 \ --currency=usd \ --setup-future-usage=off_session \ --customer={{CUSTOMER_ID}} \ -d "payment_method_types[0]"=us_bank_account ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', setup_future_usage: 'off_session', customer: '{{CUSTOMER_ID}}', payment_method_types: ['us_bank_account'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 1099, "currency": "usd", "setup_future_usage": "off_session", "customer": "{{CUSTOMER_ID}}", "payment_method_types": ["us_bank_account"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'usd', 'setup_future_usage' => 'off_session', 'customer' => '{{CUSTOMER_ID}}', 'payment_method_types' => ['us_bank_account'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") .setSetupFutureUsage(PaymentIntentCreateParams.SetupFutureUsage.OFF_SESSION) .setCustomer("{{CUSTOMER_ID}}") .addPaymentMethodType("us_bank_account") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', setup_future_usage: 'off_session', customer: '{{CUSTOMER_ID}}', payment_method_types: ['us_bank_account'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(1099), Currency: stripe.String(stripe.CurrencyUSD), SetupFutureUsage: stripe.String(stripe.PaymentIntentSetupFutureUsageOffSession), Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentMethodTypes: []*string{stripe.String("us_bank_account")}, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", SetupFutureUsage = "off_session", Customer = "{{CUSTOMER_ID}}", PaymentMethodTypes = new List { "us_bank_account" }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` 1. Select a [verification method](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-payment_method_options-us_bank_account-verification_method). When using the ACH Direct Debit payment method with the Payment Element, you can only select `automatic` or `instant`. Learn more about using [ACH Direct Debit](https://docs.stripe.com/payments/ach-direct-debit.md) with Stripe. #### Test ACH Direct Debit | Scenario | How to test | | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Your customer successfully pays with a US bank account using instant verification. | Select **US bank account** and fill out the form. Click the test institution. Follow the instructions on the modal to link your bank account. Click your payment button. | | Your customer successfully pays with a US bank account using microdeposits. | Select **US bank account** and fill out the form. Click **Enter bank details manually instead**. Follow the instructions on the modal to link your bank account. You may use these [test account numbers](https://docs.stripe.com/payments/ach-direct-debit/accept-a-payment.md?platform=web#test-account-numbers). Click your payment button. | | Your customer fails to complete the bank account linking process. | Select **US bank account** and click the test institution or **Enter bank details manually instead**. Close the modal without completing it. | ### BLIK When using the Payment Element with BLIK, the user can close the modal prompting them to authorize the payment in their banking app. This triggers a redirect to your `return_url` and doesn’t return the user to the checkout page. Learn more about using [BLIK](https://docs.stripe.com/payments/blik.md) with Stripe. To handle users closing the modal, in the server-side handler for your `return_url`, inspect the Payment Intent’s `status` to see if it’s `succeeded` or still `requires_action` (meaning the user has closed the modal without authorizing), dealing with each case as needed. ### QR code payment methods When using the Payment Element with a QR code based payment method (WeChat Pay, PayNow, Pix, PromptPay, Cash App Pay), the user can close the QR code modal. This triggers a redirect to your `return_url` and doesn’t return the user to the checkout page. To handle users closing QR code modals, at the server-side handler for your `return_url`, inspect the Payment Intent’s `status` to see if it’s `succeeded` or still `requires_action` (meaning the user has closed the modal without paying), dealing with each case as needed. Alternatively, prevent the automatic redirect to your `return_url` by passing the advanced optional parameter [`redirect=if_required`](https://docs.stripe.com/js/payment_intents/confirm_payment#confirm_payment_intent-options-redirect), which prevents the redirect when closing a QR code modal. ### Cash App Pay The Payment Element renders a dynamic form differently in desktop web or mobile web since it uses different customer authentication methods. Learn more about using [Cash App Pay](https://docs.stripe.com/payments/cash-app-pay.md) with Stripe. #### Mobile web app element Cash App Pay is a redirect based payment method in mobile web. It redirects your customer to Cash App in live mode or a test payment page in a test environment. After the payment is complete, they’re redirected to the `return_url`, regardless of whether you set `redirect=if_required` or not. #### Desktop web app element Cash App Pay is a QR code payment method in desktop web, where the Payment Element renders a QR code modal. Your customer needs to scan the QR code with a QR code scanning application or the Cash App mobile application. In live mode, it redirects the customer to the `return_url` as soon as they’re redirected to the Cash App. In test environments, they can approve or decline the payment before being redirected to the `return_url`. Customers can also close the QR code modal before completing the payment, which triggers a redirect to your `return_url`. Make sure the `return_url` corresponds to a page on your website to inspect the Payment Intent’s `status`. The Payment Intent’s `status` can be `succeeded`, `failed`, or `requires_action` (for example, the customer has closed the modal without scanning the QR code). Alternatively, prevent the automatic redirect to your `return_url` by passing the advanced optional parameter `redirect=if_required`, which prevents the redirect when closing a QR code modal. ### PayPal To use PayPal, make sure you’re on a [registered domain](https://docs.stripe.com/payments/payment-methods/pmd-registration.md). ## Disclose Stripe to your customers Stripe collects information on customer interactions with Elements to provide services to you, prevent fraud, and improve its services. This includes using cookies and IP addresses to identify which Elements a customer saw during a single checkout session. You’re responsible for disclosing and obtaining all rights and consents necessary for Stripe to use data in these ways. For more information, visit our [privacy center](https://stripe.com/legal/privacy-center#as-a-business-user-what-notice-do-i-provide-to-my-end-customers-about-stripe). ## See also - [Stripe Elements](https://docs.stripe.com/payments/elements.md) - [Set up future payments](https://docs.stripe.com/payments/save-and-reuse.md) - [Save payment details during payment](https://docs.stripe.com/payments/save-during-payment.md) - [Calculate sales tax, GST and VAT in your payment flow](https://docs.stripe.com/tax/custom.md) # In-app integration for iOS > This is a In-app integration for iOS for when payment-ui is mobile and platform is ios. View the full page at https://docs.stripe.com/payments/accept-a-payment?payment-ui=mobile&platform=ios. ![](https://b.stripecdn.com/docs-statics-srv/assets/ios-overview.9e0d68d009dc005f73a6f5df69e00458.png) Integrate Stripe’s prebuilt payment UI into the checkout of your iOS app with the [PaymentSheet](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet.html) class. See our sample integration [on GitHub](https://github.com/stripe/stripe-ios/tree/master/Example/PaymentSheet%20Example). ## Set up Stripe [Server-side] [Client-side] First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register). ### Server-side This integration requires endpoints on your server that talk to the Stripe API. Use our official libraries for access to the Stripe API from your server: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` #### Python ```bash # Install through pip pip3 install --upgrade stripe ``` ```bash # Or find the Stripe package on http://pypi.python.org/pypi/stripe/ ``` ```python # Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=5.0.0 ``` #### PHP ```bash # Install the PHP library with Composer composer require stripe/stripe-php ``` ```bash # Or download the source directly: https://github.com/stripe/stripe-php/releases ``` #### Java ```java /* For Gradle, add the following dependency to your build.gradle and replace with the version number you want to use from: - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:31.3.0" ``` ```xml com.stripe stripe-java 31.3.0 ``` ```bash # For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson ``` #### Node.js ```bash # Install with npm npm install stripe --save ``` #### Go ```bash # Make sure your project is using Go Modules go mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v84 ``` ```go // Then import the package import ( "github.com/stripe/stripe-go/v84" ) ``` #### .NET ```bash # Install with dotnet dotnet add package Stripe.net dotnet restore ``` ```bash # Or install with NuGet Install-Package Stripe.net ``` ### Client-side The [Stripe iOS SDK](https://github.com/stripe/stripe-ios) is open source, [fully documented](https://stripe.dev/stripe-ios/index.html), and compatible with apps supporting iOS 13 or above. #### Swift Package Manager To install the SDK, follow these steps: 1. In Xcode, select **File** > **Add Package Dependencies…** and enter `https://github.com/stripe/stripe-ios-spm` as the repository URL. 1. Select the latest version number from our [releases page](https://github.com/stripe/stripe-ios/releases). 1. Add the **StripePaymentSheet** product to the [target of your app](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app). #### CocoaPods 1. If you haven’t already, install the latest version of [CocoaPods](https://guides.cocoapods.org/using/getting-started.html). 1. If you don’t have an existing [Podfile](https://guides.cocoapods.org/syntax/podfile.html), run the following command to create one: ```bash pod init ``` 1. Add this line to your `Podfile`: ```podfile pod 'StripePaymentSheet' ``` 1. Run the following command: ```bash pod install ``` 1. Don’t forget to use the `.xcworkspace` file to open your project in Xcode, instead of the `.xcodeproj` file, from here on out. 1. In the future, to update to the latest version of the SDK, run: ```bash pod update StripePaymentSheet ``` #### Carthage 1. If you haven’t already, install the latest version of [Carthage](https://github.com/Carthage/Carthage#installing-carthage). 1. Add this line to your `Cartfile`: ```cartfile github "stripe/stripe-ios" ``` 1. Follow the [Carthage installation instructions](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos). Make sure to embed all of the required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripePaymentSheet/README.md#manual-linking). 1. In the future, to update to the latest version of the SDK, run the following command: ```bash carthage update stripe-ios --platform ios ``` #### Manual Framework 1. Head to our [GitHub releases page](https://github.com/stripe/stripe-ios/releases/latest) and download and unzip **Stripe.xcframework.zip**. 1. Drag **StripePaymentSheet.xcframework** to the **Embedded Binaries** section of the **General** settings in your Xcode project. Make sure to select **Copy items if needed**. 1. Repeat step 2 for all required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripePaymentSheet/README.md#manual-linking). 1. In the future, to update to the latest version of our SDK, repeat steps 1–3. > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-ios/releases) page on GitHub. To receive notifications when a new release is published, [watch releases](https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository#watching-releases-for-a-repository) for the repository. ## Enable payment methods View your [payment methods settings](https://dashboard.stripe.com/settings/payment_methods) and enable the payment methods you want to support. You need at least one payment method enabled to create a *PaymentIntent* (The Payment Intents API tracks the lifecycle of a customer checkout flow and triggers additional authentication steps when required by regulatory mandates, custom Radar fraud rules, or redirect-based payment methods). By default, Stripe enables cards and other prevalent payment methods that can help you reach more customers, but we recommend turning on additional payment methods that are relevant for your business and customers. See [Payment method support](https://docs.stripe.com/payments/payment-methods/payment-method-support.md) for product and payment method support, and our [pricing page](https://stripe.com/pricing/local-payment-methods) for fees. ## Add an endpoint [Server-side] > #### Note > > To display the PaymentSheet before you create a PaymentIntent, see [Collect payment details before creating an Intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=payment). If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. This integration uses three Stripe API objects: 1. [PaymentIntent](https://docs.stripe.com/api/payment_intents.md): Stripe uses this to represent your intent to collect payment from a customer, tracking your charge attempts and payment state changes throughout the process. 1. (Optional) [Customer](https://docs.stripe.com/api/customers.md): To set up a payment method for future payments, you must attach it to a *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments). Create a Customer object when your customer creates an account with your business. If your customer is making a payment as a guest, you can create a Customer object before payment and associate it with your own internal representation of the customer’s account later. 1. (Optional) [CustomerSession](https://docs.stripe.com/api/customer_sessions.md): Information on the Customer object is sensitive, and can’t be retrieved directly from an app. A CustomerSession grants the SDK temporary scoped access to the Customer and provides additional configuration options. See a complete list of [configuration options](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components). > If you never save cards to a Customer and don’t allow returning Customers to reuse saved cards, you can omit the Customer and CustomerSession objects from your integration. For security reasons, your app can’t create these objects. Instead, add an endpoint on your server that: 1. Retrieves the Customer, or creates a new one. 1. Creates a [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) for the Customer. 1. Creates a PaymentIntent with the [amount](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-amount), [currency](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-currency), and [customer](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer). 1. Returns the Payment Intent’s *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)), the CustomerSession’s `client_secret`, the Customer’s [id](https://docs.stripe.com/api/customers/object.md#customer_object-id), and your [publishable key](https://dashboard.stripe.com/apikeys) to your app. The payment methods shown to customers during the checkout process are also included on the PaymentIntent. You can let Stripe pull payment methods from your Dashboard settings or you can list them manually. Regardless of the option you choose, know that the currency passed in the PaymentIntent filters the payment methods shown to the customer. For example, if you pass `eur` on the PaymentIntent and have OXXO enabled in the Dashboard, OXXO won’t be shown to the customer because OXXO doesn’t support `eur` payments. Unless your integration requires a code-based option for offering payment methods, Stripe recommends the automated option. This is because Stripe evaluates the currency, payment method restrictions, and other parameters to determine the list of supported payment methods. Payment methods that increase conversion and that are most relevant to the currency and customer’s location are prioritized. #### Manage payment methods from the Dashboard You can manage payment methods from the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow. The PaymentIntent is created using the payment methods you configured in the Dashboard. If you don’t want to use the Dashboard or if you want to specify payment methods manually, you can list them using the `payment_method_types` attribute. #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. -d "automatic_payment_methods[enabled]"=true \ ``` #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' post '/payment-sheet' do # Use an existing Customer ID if this is a returning customer customer = Stripe::Customer.create({stripe_account: '{{CONNECTED_ACCOUNT_ID}}'}) customerSession = Stripe::CustomerSession.create({ customer: customer['id'], components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled', }, }, }, }) paymentIntent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'eur', customer: customer['id'], # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods: { enabled: true, }, }) { paymentIntent: paymentIntent['client_secret'], customerSessionClientSecret: customerSession['client_secret'], customer: customer['id'], publishableKey: '<>' }.to_json end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' @app.route('/payment-sheet', methods=['POST']) def payment_sheet(): # Use an existing Customer ID if this is a returning customer customer = stripe.Customer.create(stripe_account="{{CONNECTED_ACCOUNT_ID}}") customerSession = stripe.CustomerSession.create( customer=customer['id'], components={"mobile_payment_element": { "enabled": True "features": { "payment_method_save": "enabled", "payment_method_redisplay": "enabled", "payment_method_remove": "enabled" } }, ) paymentIntent = stripe.PaymentIntent.create( amount=1099, currency='eur', customer=customer['id'], # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods={ 'enabled': True, }, ) return jsonify(paymentIntent=paymentIntent.client_secret, customerSessionClientSecret=customerSession.client_secret, customer=customer.id, publishableKey='<>') ``` #### PHP ```php >'); // Use an existing Customer ID if this is a returning customer. $customer = $stripe->customers->create(['stripe_account => '{{CONNECTED_ACCOUNT_ID}}']); $customerSession = $stripe->customerSessions->create([ 'customer' => $customer->id, 'components' => ['mobile_payment_element' => [ 'enabled' => true, 'features' => [ 'payment_method_save' => 'enabled', 'payment_method_redisplay' => 'enabled', 'payment_method_remove' => 'enabled', ], ], ], ]); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'eur', 'customer' => $customer->id, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. 'automatic_payment_methods' => [ 'enabled' => 'true', ], ]); echo json_encode( [ 'paymentIntent' => $paymentIntent->client_secret, 'customerSessionClientSecret' => $customerSession->client_secret, 'customer' => $customer->id, 'publishableKey' => '<>' ] ); http_response_code(200); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; post( "/payment-sheet", (request, response) -> { response.type("application/json"); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); Customer customer = Customer.create(customerParams); // Set the connected account ID String connectedAccountId = "{{CONNECTED_ACCOUNT_ID}}"; // Create RequestOptions with the Stripe-Account header RequestOptions requestOptions = RequestOptions.builder() .setStripeAccount(connectedAccountId) .build(); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); // Pass the requestOptions when creating the customer Customer customer = Customer.create(customerParams, requestOptions); }); CustomerSessionCreateParams params = CustomerSessionCreateParams.builder() .setCustomer(customer.getId()) .setComponents(CustomerSessionCreateParams.Components.builder().build()) .putExtraParam("components[mobile_payment_element][enabled]", true) .putExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled" ) .build(); CustomerSession customerSession = CustomerSession.create(params); PaymentIntentCreateParams paymentIntentParams = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("eur") .setCustomer(customer.getId()) // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder() .setEnabled(true) .build() ) .build(); PaymentIntent paymentIntent = PaymentIntent.create(paymentIntentParams); Map responseData = new HashMap(); responseData.put("paymentIntent", paymentIntent.getClientSecret()); responseData.put("customerSessionClientSecret", customerSession.getClientSecret()); responseData.put("customer", customer.getId()); responseData.put("publishableKey", "<>"); return gson.toJson(responseData); }); ``` #### Node.js ```javascript const stripe = require('stripe')('<>'); // This example sets up an endpoint using the Express framework. app.post('/payment-sheet', async (req, res) => { // Use an existing Customer ID if this is a returning customer. const customer = await stripe.customers.create(stripeAccount:'{{CONNECTED_ACCOUNT_ID}}'); const customerSession = await stripe.customerSessions.create({ customer: customer.id, components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled' } }, }, }); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'eur', customer: customer.id, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. automatic_payment_methods: { enabled: true, }, }); res.json({ paymentIntent: paymentIntent.client_secret, customerSessionClientSecret: customerSession.client_secret, customer: customer.id, publishableKey: '<>' }); }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func handlePaymentSheet(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) return } // Use an existing Customer ID if this is a returning customer. cparams := &stripe.CustomerParams{} stripe.SetStripeAccount(cparams.ExtraParams, "{{CONNECTED_ACCOUNT_ID}}") c, _ := customer.New(cparams) csParams := &stripe.CustomerSessionParams{ Customer: stripe.String(c.ID), Components: &stripe.CustomerSessionComponentsParams{}, } csParam.AddExtra("components[mobile_payment_element][enabled]", true) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_save]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_remove]", "enabled", ) cs, _ := customersession.New(csParams); piparams := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyEUR)), Customer: stripe.String(c.ID), // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods: &stripe.PaymentIntentAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, } pi, _ := paymentintent.New(piparams) writeJSON(w, struct { PaymentIntent string `json:"paymentIntent"` CustomerSessionClientKey string `json:"customerSessionClientSecret"` Customer string `json:"customer"` PublishableKey string `json:"publishableKey"` }{ PaymentIntent: pi.ClientSecret, CustomerSessionClientKey: cs.ClientSecret, Customer: c.ID, PublishableKey: "<>", }) } ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; [HttpPost("payment-sheet")] public ActionResult CreatePaymentSheet([FromBody] CreatePaymentSheetRequest req) { // Use an existing Customer ID if this is a returning customer. var customerOptions = new CustomerCreateOptions(); var customerService = new CustomerService(); var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTED_ACCOUNT_ID}}" }; var customer = customerService.Create(customerOptions, requestOptions); var customerSessionOptions = new CustomerSessionCreateOptions { Customer = customer.Id, Components = new CustomerSessionComponentsOptions() } customerSessionOptions.AddExtraParam("components[mobile_payment_element][enabled]", true); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled"); var service = new CustomerSessionService(); var customerSession = service.Create(options); var paymentIntentOptions = new PaymentIntentCreateOptions { Amount = 1099, Currency = "eur", Customer = customer.Id, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, }; var paymentIntentService = new PaymentIntentService(); PaymentIntent paymentIntent = paymentIntentService.Create(paymentIntentOptions); return new PaymentSheetCreateResponse { PaymentIntent = paymentIntent.ClientSecret, CustomerSessionClientSecret = customerSession.ClientSecret Customer = customer.Id, PublishableKey = "<>", }; } ``` #### Listing payment methods manually #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ -d "payment_method_types[]"="bancontact" \ -d "payment_method_types[]"="card" \ -d "payment_method_types[]"="ideal" \ -d "payment_method_types[]"="klarna" \ -d "payment_method_types[]"="sepa_debit" \ ``` #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. post '/payment-sheet' do # Use an existing Customer ID if this is a returning customer customer = Stripe::Customer.create({stripe_account: '{{CONNECTED_ACCOUNT_ID}}'}) customerSession = Stripe::CustomerSession.create({ customer: customer['id'], components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled', }, }, }, }) paymentIntent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'eur', customer: customer['id'], payment_method_types: ['bancontact', 'card', 'ideal', 'klarna', 'sepa_debit'], }) { paymentIntent: paymentIntent['client_secret'], customerSessionClientSecret: customerSession['client_secret'], customer: customer['id'], publishableKey: '<>' }.to_json end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck. @app.route('/payment-sheet', methods=['POST']) def payment_sheet(): # Use an existing Customer ID if this is a returning customer customer = stripe.Customer.create(stripe_account="{{CONNECTED_ACCOUNT_ID}}") customerSession = stripe.CustomerSession.create( customer=customer['id'], components={"mobile_payment_element": { "enabled": True "features": { "payment_method_save": "enabled", "payment_method_redisplay": "enabled", "payment_method_remove": "enabled" } }, ) paymentIntent = stripe.PaymentIntent.create( amount=1099, currency='eur', customer=customer['id'], payment_method_types=["bancontact", "card", "ideal", "klarna", "sepa_debit"], ) return jsonify(paymentIntent=paymentIntent.client_secret, customerSessionClientSecret=customerSession.client_secret, customer=customer.id, publishableKey='<>') ``` #### PHP ```php >'); // Use an existing Customer ID if this is a returning customer. $customer = $stripe->customers->create(['stripe_account => '{{CONNECTED_ACCOUNT_ID}}']); $customerSession = $stripe->customerSessions->create([ 'customer' => $customer->id, 'components' => ['mobile_payment_element' => [ 'enabled' => true, 'features' => [ 'payment_method_save' => 'enabled', 'payment_method_redisplay' => 'enabled', 'payment_method_remove' => 'enabled', ], ], ], ]); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'eur', 'customer' => $customer->id, 'payment_method_types' => ['bancontact', 'card', 'ideal', 'klarna', 'sepa_debit'], ]); echo json_encode( [ 'paymentIntent' => $paymentIntent->client_secret, 'customerSessionClientSecret' => $customerSession->client_secret, 'customer' => $customer->id, 'publishableKey' => '<>' ] ); http_response_code(200); ``` #### Java ```java // This example sets up an endpoint using the Spark framework. post("/payment-sheet", (request, response) -> { response.type("application/json"); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); Customer customer = Customer.create(customerParams); CustomerSessionCreateParams params = CustomerSessionCreateParams.builder() .setCustomer(customer.getId()) .setComponents(CustomerSessionCreateParams.Components.builder().build()) .putExtraParam("components[mobile_payment_element][enabled]", true) .putExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled" ) .build(); CustomerSession customerSession = CustomerSession.create(params); List paymentMethodTypes = new ArrayList(); paymentMethodTypes.add("bancontact"); paymentMethodTypes.add("card"); paymentMethodTypes.add("ideal"); paymentMethodTypes.add("klarna"); paymentMethodTypes.add("sepa_debit"); PaymentIntentCreateParams paymentIntentParams = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("eur") .setCustomer(customer.getId()) .addAllPaymentMethodType(paymentMethodTypes) .build(); PaymentIntent paymentIntent = PaymentIntent.create(paymentIntentParams); Map responseData = new HashMap(); responseData.put("paymentIntent", paymentIntent.getClientSecret()); responseData.put("ephemeralKey", ephemeralKey.getSecret()); responseData.put("customer", customer.getId()); responseData.put("publishableKey", "<>"); return gson.toJson(responseData); }); ``` #### Node.js ```javascript // This example sets up an endpoint using the Express framework. app.post('/payment-sheet', async (req, res) => { // Use an existing Customer ID if this is a returning customer. const customer = await stripe.customers.create(stripeAccount:'{{CONNECTED_ACCOUNT_ID}}'); const customerSession = await stripe.customerSessions.create({ customer: customer.id, components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled' } }, }, }); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'eur', customer: customer.id, payment_method_types: ['bancontact', 'card', 'ideal', 'klarna', 'sepa_debit'], }); res.json({ paymentIntent: paymentIntent.client_secret, customerSessionClientSecret: customerSession.client_secret, customer: customer.id, publishableKey: '<>' }); }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func handlePaymentSheet(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) return } // Use an existing Customer ID if this is a returning customer. cparams := &stripe.CustomerParams{} stripe.SetStripeAccount(cparams.ExtraParams, "{{CONNECTED_ACCOUNT_ID}}") c, _ := customer.New(cparams) csParams := &stripe.CustomerSessionParams{ Customer: stripe.String(c.ID), Components: &stripe.CustomerSessionComponentsParams{}, } csParam.AddExtra("components[mobile_payment_element][enabled]", true) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_save]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_remove]", "enabled", ) cs, _ := customersession.New(csParams); piparams := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyEUR)), Customer: stripe.String(c.ID), PaymentMethodTypes: []*string{ stripe.String("bancontact"), stripe.String("card"), stripe.String("ideal"), stripe.String("klarna"), stripe.String("sepa_debit"), }, } pi, _ := paymentintent.New(piparams) writeJSON(w, struct { PaymentIntent string `json:"paymentIntent"` CustomerSessionClientKey string `json:"customerSessionClientSecret"` Customer string `json:"customer"` PublishableKey string `json:"publishableKey"` }{ PaymentIntent: pi.ClientSecret, CustomerSessionClientKey: cs.ClientSecret, Customer: c.ID, PublishableKey: "<>", }) } ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; [HttpPost("payment-sheet")] public ActionResult CreatePaymentSheet([FromBody] CreatePaymentSheetRequest req) { // Use an existing Customer ID if this is a returning customer. var customerOptions = new CustomerCreateOptions(); var customerService = new CustomerService(); var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTED_ACCOUNT_ID}}" }; var customer = customerService.Create(customerOptions, requestOptions); var customerSessionOptions = new CustomerSessionCreateOptions { Customer = customer.Id, Components = new CustomerSessionComponentsOptions() } customerSessionOptions.AddExtraParam("components[mobile_payment_element][enabled]", true); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled"); var service = new CustomerSessionService(); var customerSession = service.Create(options); var paymentIntentOptions = new PaymentIntentCreateOptions { Amount = 1099, Currency = "eur", Customer = customer.Id, PaymentMethodTypes = new List { "bancontact", "card", "ideal", "klarna", "sepa_debit", }, }; var paymentIntentService = new PaymentIntentService(); PaymentIntent paymentIntent = paymentIntentService.Create(paymentIntentOptions); return new PaymentSheetCreateResponse { PaymentIntent = paymentIntent.ClientSecret, CustomerSessionClientSecret = customerSession.ClientSecret Customer = customer.Id, PublishableKey = "<>", }; } ``` > Each payment method needs to support the currency passed in the PaymentIntent and your business needs to be based in one of the countries each payment method supports. See the [Payment method integration options](https://docs.stripe.com/payments/payment-methods/integration-options.md) page for more details about what’s supported. ## Collect payment details [Client-side] To display the mobile Payment Element on your checkout screen, make sure you: - Display the products the customer is purchasing along with the total amount - Use the [Address Element](https://docs.stripe.com/elements/address-element.md?platform=ios) to collect any required shipping information from the customer - Add a checkout button to display Stripe’s UI #### UIKit In your app’s checkout screen, fetch the PaymentIntent client secret, CustomerSession client secret, Customer ID, and publishable key from the endpoint you created in the previous step. Use `STPAPIClient.shared` to set your publishable key and initialize the [PaymentSheet](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet.html). #### iOS (Swift) ```swift import UIKit@_spi(CustomerSessionBetaAccess) import StripePaymentSheet class CheckoutViewController: UIViewController { @IBOutlet weak var checkoutButton: UIButton! var paymentSheet: PaymentSheet? let backendCheckoutUrl = URL(string: "Your backend endpoint/payment-sheet")! // Your backend endpoint override func viewDidLoad() { super.viewDidLoad() checkoutButton.addTarget(self, action: #selector(didTapCheckoutButton), for: .touchUpInside) checkoutButton.isEnabled = false // MARK: Fetch the PaymentIntent client secret, CustomerSession client secret, Customer ID, and publishable key var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerId = json["customer"] as? String, let customerSessionClientSecret = json["customerSessionClientSecret"] as? String, let paymentIntentClientSecret = json["paymentIntent"] as? String, let publishableKey = json["publishableKey"] as? String, let self = self else { // Handle error return } STPAPIClient.shared.publishableKey = publishableKey// MARK: Create a PaymentSheet instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customer = .init(id: customerId, customerSessionClientSecret: customerSessionClientSecret) // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. configuration.allowsDelayedPaymentMethods = true self.paymentSheet = PaymentSheet(paymentIntentClientSecret:paymentIntentClientSecret, configuration: configuration) DispatchQueue.main.async { self.checkoutButton.isEnabled = true } }) task.resume() } } ``` When the customer taps the **Checkout** button, call `present` to present the PaymentSheet. After the customer completes the payment, Stripe dismisses the PaymentSheet and calls the completion block with [PaymentSheetResult](https://stripe.dev/stripe-ios/stripe-paymentsheet/Enums/PaymentSheetResult.html). #### iOS (Swift) ```swift @objc func didTapCheckoutButton() { // MARK: Start the checkout process paymentSheet?.present(from: self) { paymentResult in // MARK: Handle the payment result switch paymentResult { case .completed: print("Your order is confirmed") case .canceled: print("Canceled!") case .failed(let error): print("Payment failed: \(error)") } } } ``` #### SwiftUI Create an `ObservableObject` model for your checkout screen. This model publishes a [PaymentSheet](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet.html) and a [PaymentSheetResult](https://stripe.dev/stripe-ios/stripe-paymentsheet/Enums/PaymentSheetResult.html). ```swift import StripePaymentSheet import SwiftUI class CheckoutViewModel: ObservableObject { let backendCheckoutUrl = URL(string: "Your backend endpoint/payment-sheet")! // Your backend endpoint @Published var paymentSheet: PaymentSheet? @Published var paymentResult: PaymentSheetResult? } ``` Fetch the PaymentIntent client secret, CustomerSession client secret, Customer ID, and publishable key from the endpoint you created in the previous step. Use `STPAPIClient.shared` to set your publishable key and initialize the [PaymentSheet](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet.html). ```swift @_spi(CustomerSessionBetaAccess) import StripePaymentSheet import SwiftUI class CheckoutViewModel: ObservableObject { let backendCheckoutUrl = URL(string: "Your backend endpoint/payment-sheet")! // Your backend endpoint @Published var paymentSheet: PaymentSheet? @Published var paymentResult: PaymentSheetResult? func preparePaymentSheet() { // MARK: Fetch thePaymentIntent and Customer information from the backend var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerId = json["customer"] as? String, let customerSessionClientSecret = json["customerSessionClientSecret"] as? String, letpaymentIntentClientSecret = json["paymentIntent"] as? String, let publishableKey = json["publishableKey"] as? String, let self = self else { // Handle error return } STPAPIClient.shared.publishableKey = publishableKey// MARK: Create a PaymentSheet instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customer = .init(id: customerId, customerSessionClientSecret: customerSessionClientSecret) // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. configuration.allowsDelayedPaymentMethods = true DispatchQueue.main.async { self.paymentSheet = PaymentSheet(paymentIntentClientSecret:paymentIntentClientSecret, configuration: configuration) } }) task.resume() } } struct CheckoutView: View { @ObservedObject var model = CheckoutViewModel() var body: some View { VStack { if model.paymentSheet != nil { Text("Ready to pay.") } else { Text("Loading…") } }.onAppear { model.preparePaymentSheet() } } } ``` Add a [PaymentSheet.PaymentButton](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/PaymentButton.html) to your `View`. This behaves similarly to a SwiftUI `Button`, which allows you to customize it by adding a `View`. When you tap the button, it displays the PaymentSheet. After you complete the payment, Stripe dismisses the PaymentSheet and calls the `onCompletion` handler with a [PaymentSheetResult](https://stripe.dev/stripe-ios/stripe-paymentsheet/Enums/PaymentSheetResult.html) object. ```swift @_spi(CustomerSessionBetaAccess) import StripePaymentSheet import SwiftUI class CheckoutViewModel: ObservableObject { let backendCheckoutUrl = URL(string: "Your backend endpoint/payment-sheet")! // Your backend endpoint @Published var paymentSheet: PaymentSheet? @Published var paymentResult: PaymentSheetResult? func preparePaymentSheet() { // MARK: Fetch the PaymentIntent and Customer information from the backend var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerId = json["customer"] as? String, let customerSessionClientSecret = json["customerSessionClientSecret"] as? String, let paymentIntentClientSecret = json["paymentIntent"] as? String, let publishableKey = json["publishableKey"] as? String, let self = self else { // Handle error return } STPAPIClient.shared.publishableKey = publishableKey // MARK: Create a PaymentSheet instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customer = .init(id: customerId, customerSessionClientSecret: customerSessionClientSecret) // Set `allowsDelayedPaymentMethods` to true if your business can handle payment methods // that complete payment after a delay, like SEPA Debit and Sofort. configuration.allowsDelayedPaymentMethods = true DispatchQueue.main.async { self.paymentSheet = PaymentSheet(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) } }) task.resume() } func onPaymentCompletion(result: PaymentSheetResult) { self.paymentResult = result } } struct CheckoutView: View { @ObservedObject var model = CheckoutViewModel() var body: some View { VStack {if let paymentSheet = model.paymentSheet { PaymentSheet.PaymentButton( paymentSheet: paymentSheet, onCompletion: model.onPaymentCompletion ) { Text("Buy") } } else { Text("Loading…") }if let result = model.paymentResult { switch result { case .completed: Text("Payment complete") case .failed(let error): Text("Payment failed: \(error.localizedDescription)") case .canceled: Text("Payment canceled.") } } }.onAppear { model.preparePaymentSheet() } } } ``` If `PaymentSheetResult` is `.completed`, inform the user (for example, by displaying an order confirmation screen). Setting `allowsDelayedPaymentMethods` to true allows [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment methods like US bank accounts. For these payment methods, the final payment status isn’t known when the `PaymentSheet` completes, and instead succeeds or fails later. If you support these types of payment methods, inform the customer their order is confirmed and only fulfill their order (for example, ship their product) when the payment is successful. ## Set up a return URL [Client-side] The customer might navigate away from your app to authenticate (for example, in Safari or their banking app). To allow them to automatically return to your app after authenticating, [configure a custom URL scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) and set up your app delegate to forward the URL to the SDK. Stripe doesn’t support [universal links](https://developer.apple.com/documentation/xcode/allowing-apps-and-websites-to-link-to-your-content). #### SceneDelegate #### Swift ```swift // This method handles opening custom URL schemes (for example, "your-app://stripe-redirect") func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { guard let url = URLContexts.first?.url else { return } let stripeHandled = StripeAPI.handleURLCallback(with: url) if (!stripeHandled) { // This was not a Stripe url – handle the URL normally as you would } } ``` #### AppDelegate #### Swift ```swift // This method handles opening custom URL schemes (for example, "your-app://stripe-redirect") func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { let stripeHandled = StripeAPI.handleURLCallback(with: url) if (stripeHandled) { return true } else { // This was not a Stripe url – handle the URL normally as you would } return false } ``` #### SwiftUI #### Swift ```swift @main struct MyApp: App { var body: some Scene { WindowGroup { Text("Hello, world!").onOpenURL { incomingURL in let stripeHandled = StripeAPI.handleURLCallback(with: incomingURL) if (!stripeHandled) { // This was not a Stripe url – handle the URL normally as you would } } } } } ``` Additionally, set the [returnURL](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:6Stripe12PaymentSheetC13ConfigurationV9returnURLSSSgvp) on your [PaymentSheet.Configuration](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html) object to the URL for your app. ```swift var configuration = PaymentSheet.Configuration() configuration.returnURL = "your-app://stripe-redirect" ``` ## Handle post-payment events [Server-side] Stripe sends a [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) event when the payment completes. Use the [Dashboard webhook tool](https://dashboard.stripe.com/webhooks) or follow the [webhook guide](https://docs.stripe.com/webhooks/quickstart.md) to receive these events and run actions, such as sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow. Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events is what enables you to accept [different types of payment methods](https://stripe.com/payments/payment-methods-guide) with a single integration. In addition to handling the `payment_intent.succeeded` event, we recommend handling these other events when collecting payments with the Payment Element: | Event | Description | Action | | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.succeeded) | Sent when a customer successfully completes a payment. | Send the customer an order confirmation and *fulfill* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) their order. | | [payment_intent.processing](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.processing) | Sent when a customer successfully initiates a payment, but the payment has yet to complete. This event is most commonly sent when the customer initiates a bank debit. It’s followed by either a `payment_intent.succeeded` or `payment_intent.payment_failed` event in the future. | Send the customer an order confirmation that indicates their payment is pending. For digital goods, you might want to fulfill the order before waiting for payment to complete. | | [payment_intent.payment_failed](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.payment_failed) | Sent when a customer attempts a payment, but the payment fails. | If a payment transitions from `processing` to `payment_failed`, offer the customer another attempt to pay. | ## Test the integration #### Cards | Card number | Scenario | How to test | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | 4242424242424242 | The card payment succeeds and doesn’t require authentication. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000002500003155 | The card payment requires *authentication* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase). | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000000000009995 | The card is declined with a decline code like `insufficient_funds`. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 6205500000000000004 | The UnionPay card has a variable length of 13-19 digits. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | #### Bank redirects | Payment method | Scenario | How to test | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | Bancontact, iDEAL | Your customer fails to authenticate on the redirect page for a redirect-based and immediate notification payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | Pay by Bank | Your customer successfully pays with a redirect-based and [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | | Pay by Bank | Your customer fails to authenticate on the redirect page for a redirect-based and delayed notification payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | BLIK | BLIK payments fail in a variety of ways—immediate failures (for example, the code is expired or invalid), delayed errors (the bank declines) or timeouts (the customer didn’t respond in time). | Use email patterns to [simulate the different failures.](https://docs.stripe.com/payments/blik/accept-a-payment.md#simulate-failures) | #### Bank debits | Payment method | Scenario | How to test | | ----------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SEPA Direct Debit | Your customer successfully pays with SEPA Direct Debit. | Fill out the form using the account number `AT321904300235473204`. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later. | | SEPA Direct Debit | Your customer’s payment intent status transitions from `processing` to `requires_payment_method`. | Fill out the form using the account number `AT861904300235473202`. | See [Testing](https://docs.stripe.com/testing.md) for additional information to test your integration. ## Optional: Enable Link Enable Link in your [Payment Method settings](https://dashboard.stripe.com/settings/payment_methods) to allow your customers to securely save and reuse their payment information using Link’s one-click express checkout button. ### Pass your customer’s email to the Mobile Payment Element Link authenticates a customer using their email address. Stripe recommends prefilling as much information as possible to streamline the checkout process. To prefill the customer’s name, email address, and phone number, supply `defaultBillingDetails` with your customer information after initializing `PaymentSheet.Configuration`. ```swift var configuration = PaymentSheet.Configuration() configuration.defaultBillingDetails.name = "Jenny Rosen" configuration.defaultBillingDetails.email = "jenny.rosen@example.com" configuration.defaultBillingDetails.phone = "888-888-8888" ``` ## Optional: Enable Apple Pay > If your checkout screen has a dedicated **Apple Pay button**, follow the [Apple Pay guide](https://docs.stripe.com/apple-pay.md#present-payment-sheet) and use `ApplePayContext` to collect payment from your Apple Pay button. You can use `PaymentSheet` to handle other payment method types. ### Register for an Apple Merchant ID Obtain an Apple Merchant ID by [registering for a new identifier](https://developer.apple.com/account/resources/identifiers/add/merchant) on the Apple Developer website. Fill out the form with a description and identifier. Your description is for your own records and you can modify it in the future. Stripe recommends using the name of your app as the identifier (for example, `merchant.com.{{YOUR_APP_NAME}}`). ### Create a new Apple Pay certificate Create a certificate for your app to encrypt payment data. Go to the [iOS Certificate Settings](https://dashboard.stripe.com/settings/ios_certificates) in the Dashboard, click **Add new application**, and follow the guide. Download a Certificate Signing Request (CSR) file to get a secure certificate from Apple that allows you to use Apple Pay. One CSR file must be used to issue exactly one certificate. If you switch your Apple Merchant ID, you must go to the [iOS Certificate Settings](https://dashboard.stripe.com/settings/ios_certificates) in the Dashboard to obtain a new CSR and certificate. ### Integrate with Xcode Add the Apple Pay capability to your app. In Xcode, open your project settings, click the **Signing & Capabilities** tab, and add the **Apple Pay** capability. You might be prompted to log in to your developer account at this point. Select the merchant ID you created earlier, and your app is ready to accept Apple Pay. ![](https://b.stripecdn.com/docs-statics-srv/assets/xcode.a701d4c1922d19985e9c614a6f105bf1.png) Enable the Apple Pay capability in Xcode ### Add Apple Pay #### One-time payment To add Apple Pay to PaymentSheet, set [applePay](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:6Stripe12PaymentSheetC13ConfigurationV8applePayAC05ApplefD0VSgvp) after initializing `PaymentSheet.Configuration` with your Apple merchant ID and the [country code of your business](https://dashboard.stripe.com/settings/account). #### iOS (Swift) ```swift var configuration = PaymentSheet.Configuration() configuration.applePay = .init( merchantId: "merchant.com.your_app_name", merchantCountryCode: "US" ) ``` #### Recurring payments To add Apple Pay to PaymentSheet, set [applePay](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:6Stripe12PaymentSheetC13ConfigurationV8applePayAC05ApplefD0VSgvp) after initializing `PaymentSheet.Configuration` with your Apple merchant ID and the [country code of your business](https://dashboard.stripe.com/settings/account). Per [Apple’s guidelines](https://developer.apple.com/design/human-interface-guidelines/apple-pay#Supporting-subscriptions) for recurring payments, you must also set additional attributes on the `PKPaymentRequest`. Add a handler in [ApplePayConfiguration.paymentRequestHandlers](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/applepayconfiguration/handlers/paymentrequesthandler) to configure the [PKPaymentRequest.paymentSummaryItems](https://developer.apple.com/documentation/passkit/pkpaymentrequest/1619231-paymentsummaryitems) with the amount you intend to charge (for example, 9.95 USD a month). You can also adopt [merchant tokens](https://developer.apple.com/apple-pay/merchant-tokens/) by setting the `recurringPaymentRequest` or `automaticReloadPaymentRequest` properties on the `PKPaymentRequest`. To learn more about how to use recurring payments with Apple Pay, see [Apple’s PassKit documentation](https://developer.apple.com/documentation/passkit/pkpaymentrequest). #### iOS (Swift) ```swift let customHandlers = PaymentSheet.ApplePayConfiguration.Handlers( paymentRequestHandler: { request in // PKRecurringPaymentSummaryItem is available on iOS 15 or later if #available(iOS 15.0, *) { let billing = PKRecurringPaymentSummaryItem(label: "My Subscription", amount: NSDecimalNumber(string: "59.99")) // Payment starts today billing.startDate = Date() // Payment ends in one year billing.endDate = Date().addingTimeInterval(60 * 60 * 24 * 365) // Pay once a month. billing.intervalUnit = .month billing.intervalCount = 1 // recurringPaymentRequest is only available on iOS 16 or later if #available(iOS 16.0, *) { request.recurringPaymentRequest = PKRecurringPaymentRequest(paymentDescription: "Recurring", regularBilling: billing, managementURL: URL(string: "https://my-backend.example.com/customer-portal")!) request.recurringPaymentRequest?.billingAgreement = "You'll be billed $59.99 every month for the next 12 months. To cancel at any time, go to Account and click 'Cancel Membership.'" } request.paymentSummaryItems = [billing] request.currencyCode = "USD" } else { // On older iOS versions, set alternative summary items. request.paymentSummaryItems = [PKPaymentSummaryItem(label: "Monthly plan starting July 1, 2022", amount: NSDecimalNumber(string: "59.99"), type: .final)] } return request } ) var configuration = PaymentSheet.Configuration() configuration.applePay = .init(merchantId: "merchant.com.your_app_name", merchantCountryCode: "US", customHandlers: customHandlers) ``` ### Order tracking To add [order tracking](https://developer.apple.com/design/human-interface-guidelines/technologies/wallet/designing-order-tracking) information in iOS 16 or later, configure an [authorizationResultHandler](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/applepayconfiguration/handlers/authorizationresulthandler) in your `PaymentSheet.ApplePayConfiguration.Handlers`. Stripe calls your implementation after the payment is complete, but before iOS dismisses the Apple Pay sheet. In your `authorizationResultHandler` implementation, fetch the order details from your server for the completed order. Add the details to the provided [PKPaymentAuthorizationResult](https://developer.apple.com/documentation/passkit/pkpaymentauthorizationresult) and return the modified result. To learn more about order tracking, see [Apple’s Wallet Orders documentation](https://developer.apple.com/documentation/walletorders). #### iOS (Swift) ```swift let customHandlers = PaymentSheet.ApplePayConfiguration.Handlers( authorizationResultHandler: { result in do { // Fetch the order details from your service let myOrderDetails = try await MyAPIClient.shared.fetchOrderDetails(orderID: orderID) result.orderDetails = PKPaymentOrderDetails( orderTypeIdentifier: myOrderDetails.orderTypeIdentifier, // "com.myapp.order" orderIdentifier: myOrderDetails.orderIdentifier, // "ABC123-AAAA-1111" webServiceURL: myOrderDetails.webServiceURL, // "https://my-backend.example.com/apple-order-tracking-backend" authenticationToken: myOrderDetails.authenticationToken) // "abc123" // Return your modified PKPaymentAuthorizationResult return result } catch { return PKPaymentAuthorizationResult(status: .failure, errors: [error]) } } ) var configuration = PaymentSheet.Configuration() configuration.applePay = .init(merchantId: "merchant.com.your_app_name", merchantCountryCode: "US", customHandlers: customHandlers) ``` ## Optional: Enable card scanning #### iOS To enable card scanning support, set the `NSCameraUsageDescription` (**Privacy - Camera Usage Description**) in the Info.plist of your application, and provide a reason for accessing the camera (for example, “To scan cards”). Devices with iOS 13 or higher support card scanning. #### Android To enable card scanning support, [request production access](https://developers.google.com/pay/api/android/guides/test-and-deploy/request-prod-access) to the Google Pay API from the [Google Pay and Wallet Console](https://pay.google.com/business/console?utm_source=devsite&utm_medium=devsite&utm_campaign=devsite). - If you’ve enabled Google Pay, the card scanning feature is automatically available in our UI on eligible devices. To learn more about eligible devices, see the [Google Pay API constraints](https://developers.google.com/pay/payment-card-recognition/debit-credit-card-recognition) - **Important:** The card scanning feature only appears in builds signed with the same signing key registered in the [Google Pay & Wallet Console](https://pay.google.com/business/console). Test or debug builds using different signing keys (for example, builds distributed through Firebase App Tester) won’t show the **Scan card** option. To test card scanning in pre-release builds, you must either: - Sign your test builds with your production signing key - Add your test signing key fingerprint to the Google Pay and Wallet Console ## Optional: Enable ACH payments To enable ACH debit payments include `StripeFinancialConnections` as a dependency for your app. The [Stripe iOS SDK](https://github.com/stripe/stripe-ios) is open source, [fully documented](https://stripe.dev/stripe-ios/index.html), and compatible with apps supporting iOS 13 or above. #### Swift Package Manager To install the SDK, follow these steps: 1. In Xcode, select **File** > **Add Package Dependencies…** and enter `https://github.com/stripe/stripe-ios-spm` as the repository URL. 1. Select the latest version number from our [releases page](https://github.com/stripe/stripe-ios/releases). 1. Add the **StripeFinancialConnections** product to the [target of your app](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app). #### CocoaPods 1. If you haven’t already, install the latest version of [CocoaPods](https://guides.cocoapods.org/using/getting-started.html). 1. If you don’t have an existing [Podfile](https://guides.cocoapods.org/syntax/podfile.html), run the following command to create one: ```bash pod init ``` 1. Add this line to your `Podfile`: ```podfile pod 'StripeFinancialConnections' ``` 1. Run the following command: ```bash pod install ``` 1. Don’t forget to use the `.xcworkspace` file to open your project in Xcode, instead of the `.xcodeproj` file, from here on out. 1. In the future, to update to the latest version of the SDK, run: ```bash pod update StripeFinancialConnections ``` #### Carthage 1. If you haven’t already, install the latest version of [Carthage](https://github.com/Carthage/Carthage#installing-carthage). 1. Add this line to your `Cartfile`: ```cartfile github "stripe/stripe-ios" ``` 1. Follow the [Carthage installation instructions](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos). Make sure to embed all of the required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripeFinancialConnections/README.md#manual-linking). 1. In the future, to update to the latest version of the SDK, run the following command: ```bash carthage update stripe-ios --platform ios ``` #### Manual Framework 1. Head to our [GitHub releases page](https://github.com/stripe/stripe-ios/releases/latest) and download and unzip **Stripe.xcframework.zip**. 1. Drag **StripeFinancialConnections.xcframework** to the **Embedded Binaries** section of the **General** settings in your Xcode project. Make sure to select **Copy items if needed**. 1. Repeat step 2 for all required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripeFinancialConnections/README.md#manual-linking). 1. In the future, to update to the latest version of our SDK, repeat steps 1–3. > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-ios/releases) page on GitHub. To receive notifications when a new release is published, [watch releases](https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository#watching-releases-for-a-repository) for the repository. ## Optional: Customize the sheet All customization is configured through the [PaymentSheet.Configuration](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html) object. ### Appearance Customize colors, fonts, and so on to match the look and feel of your app by using the [appearance API](https://docs.stripe.com/elements/appearance-api.md?platform=ios). ### Payment method layout Configure the layout of payment methods in the sheet using [paymentMethodLayout](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/configuration-swift.struct/paymentmethodlayout). You can display them horizontally, vertically, or let Stripe optimize the layout automatically. ![](https://b.stripecdn.com/docs-statics-srv/assets/ios-mpe-payment-method-layouts.9d0513e2fcec5660378ba1824d952054.png) #### Swift ```swift var configuration = PaymentSheet.Configuration() configuration.paymentMethodLayout = .automatic ``` ### Collect users addresses Collect local and international shipping or billing addresses from your customers using the [Address Element](https://docs.stripe.com/elements/address-element.md?platform=ios). ### Merchant display name Specify a customer-facing business name by setting [merchantDisplayName](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:18StripePaymentSheet0bC0C13ConfigurationV19merchantDisplayNameSSvp). By default, this is your app’s name. #### Swift ```swift var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "My app, Inc." ``` ### Dark mode `PaymentSheet` automatically adapts to the user’s system-wide appearance settings (light and dark mode). If your app doesn’t support dark mode, you can set [style](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:18StripePaymentSheet0bC0C13ConfigurationV5styleAC18UserInterfaceStyleOvp) to `alwaysLight` or `alwaysDark` mode. ```swift var configuration = PaymentSheet.Configuration() configuration.style = .alwaysLight ``` ### Default billing details To set default values for billing details collected in the payment sheet, configure the `defaultBillingDetails` property. The `PaymentSheet` pre-populates its fields with the values that you provide. ```swift var configuration = PaymentSheet.Configuration() configuration.defaultBillingDetails.address.country = "US" configuration.defaultBillingDetails.email = "foo@bar.com" ``` ### Billing details collection Use `billingDetailsCollectionConfiguration` to specify how you want to collect billing details in the payment sheet. You can collect your customer’s name, email, phone number, and address. If you only want to billing details required by the payment method, set `billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod` to true. In that case, the `PaymentSheet.Configuration.defaultBillingDetails` are set as the payment method’s [billing details](https://docs.stripe.com/api/payment_methods/object.md?lang=node#payment_method_object-billing_details). If you want to collect additional billing details that aren’t necessarily required by the payment method, set `billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod` to false. In that case, the billing details collected through the `PaymentSheet` are set as the payment method’s billing details. ```swift var configuration = PaymentSheet.Configuration() configuration.defaultBillingDetails.email = "foo@bar.com" configuration.billingDetailsCollectionConfiguration.name = .always configuration.billingDetailsCollectionConfiguration.email = .never configuration.billingDetailsCollectionConfiguration.address = .full configuration.billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod = true ``` > Consult with your legal counsel regarding laws that apply to collecting information. Only collect phone numbers if you need them for the transaction. ## Optional: Handle user logout `PaymentSheet` stores some information locally to remember whether a user has used Link within an app. To clear the internal state of `PaymentSheet`, call the `PaymentSheet.resetCustomer()` method when your user logs out. ```swift import UIKit import StripePaymentSheet class MyViewController: UIViewController { @objc func didTapLogoutButton() { PaymentSheet.resetCustomer() // Other logout logic required by your app } } ``` ## Optional: Complete payment in your UI You can present the Payment Sheet to only collect payment method details and then later call a `confirm` method to complete payment in your app’s UI. This is useful if you have a custom buy button or require additional steps after you collect payment details. ![](https://b.stripecdn.com/docs-statics-srv/assets/ios-multi-step.cd631ea4f1cd8cf3f39b6b9e1e92b6c5.png) Complete the payment in your app’s UI #### UIKit The following steps walk you through how to complete payment in your app’s UI. See our sample integration out on [GitHub](https://github.com/stripe/stripe-ios/blob/master/Example/PaymentSheet%20Example/PaymentSheet%20Example/ExampleCustomCheckoutViewController.swift). 1. First, initialize [PaymentSheet.FlowController](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/flowcontroller) instead of `PaymentSheet` and update your UI with its `paymentOption` property. This property contains an image and label representing the customer’s initially selected, default payment method. ```swift PaymentSheet.FlowController.create(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) { [weak self] result in switch result { case .failure(let error): print(error) case .success(let paymentSheetFlowController): self?.paymentSheetFlowController = paymentSheetFlowController // Update your UI using paymentSheetFlowController.paymentOption } } ``` 1. Next, call `presentPaymentOptions` to collect payment details. When completed, update your UI again with the `paymentOption` property. ```swift paymentSheetFlowController.presentPaymentOptions(from: self) { // Update your UI using paymentSheetFlowController.paymentOption } ``` 1. Finally, call `confirm`. ```swift paymentSheetFlowController.confirm(from: self) { paymentResult in // MARK: Handle the payment result switch paymentResult { case .completed: print("Payment complete!") case .canceled: print("Canceled!") case .failed(let error): print(error) } } ``` #### SwiftUI The following steps walk you through how to complete payment in your app’s UI. See our sample integration out on [GitHub](https://github.com/stripe/stripe-ios/blob/master/Example/PaymentSheet%20Example/PaymentSheet%20Example/ExampleSwiftUICustomPaymentFlow.swift). 1. First, initialize [PaymentSheet.FlowController](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/flowcontroller) instead of `PaymentSheet`. Its `paymentOption` property contains an image and label representing the customer’s currently selected payment method, which you can use in your UI. ```swift PaymentSheet.FlowController.create(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) { [weak self] result in switch result { case .failure(let error): print(error) case .success(let paymentSheetFlowController): self?.paymentSheetFlowController = paymentSheetFlowController // Use the paymentSheetFlowController.paymentOption properties in your UI myPaymentMethodLabel = paymentSheetFlowController.paymentOption?.label ?? "Select a payment method" myPaymentMethodImage = paymentSheetFlowController.paymentOption?.image ?? UIImage(systemName: "square.and.pencil")! } } ``` 1. Use [PaymentSheet.FlowController.PaymentOptionsButton](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/flowcontroller/paymentoptionsbutton) to wrap the button that presents the sheet to collect payment details. When `PaymentSheet.FlowController` calls the `onSheetDismissed` argument, the `paymentOption` for the `PaymentSheet.FlowController` instance reflects the currently selected payment method. ```swift PaymentSheet.FlowController.PaymentOptionsButton( paymentSheetFlowController: paymentSheetFlowController, onSheetDismissed: { myPaymentMethodLabel = paymentSheetFlowController.paymentOption?.label ?? "Select a payment method" myPaymentMethodImage = paymentSheetFlowController.paymentOption?.image ?? UIImage(systemName: "square.and.pencil")! }, content: { /* An example button */ HStack { Text(myPaymentMethodLabel) Image(uiImage: myPaymentMethodImage) } } ) ``` 1. Use [PaymentSheet.FlowController.PaymentOptionsButton](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/flowcontroller/paymentoptionsbutton) to wrap the button that confirms the payment. ```swift PaymentSheet.FlowController.ConfirmButton( paymentSheetFlowController: paymentSheetFlowController, onCompletion: { result in // MARK: Handle the payment result switch result { case .completed: print("Payment complete!") case .canceled: print("Canceled!") case .failed(let error): print(error) } }, content: { /* An example button */ Text("Pay") } ) ``` Setting `allowsDelayedPaymentMethods` to true allows [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment methods like US bank accounts. For these payment methods, the final payment status isn’t known when the `PaymentSheet` completes, and instead succeeds or fails later. If you support these types of payment methods, inform the customer their order is confirmed and only fulfill their order (for example, ship their product) when the payment is successful. ## Optional: Enable CVC recollection on confirmation The following instructions for re-collecting the CVC of a saved card during PaymentIntent confirmation assume that your integration includes the following: - Creation of PaymentIntents before collecting payment details ### Update parameters of the intent creation To re-collect the CVC when confirming payment, include `require_cvc_recollection` during the creation of the PaymentIntent. #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an Ephemeral Key for the Customer curl https://api.stripe.com/v1/ephemeral_keys \ -u <>: \ -H "Stripe-Version: 2026-01-28.clover" \ -H "Stripe-Account: 2026-01-28.clover" \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \-d "payment_method_options[card][require_cvc_recollection]"=true \ # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. -d "automatic_payment_methods[enabled]"=true \ ``` #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' post '/payment-sheet' do # Use an existing Customer ID if this is a returning customer customer = Stripe::Customer.create({stripe_account: '{{CONNECTED_ACCOUNT_ID}}'}) ephemeralKey = Stripe::EphemeralKey.create({ customer: customer['id'], }, {stripe_version: '2026-01-28.clover', stripe_account: '{{CONNECTED_ACCOUNT_ID}}'}) paymentIntent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'eur', customer: customer['id'],payment_method_options: { card: {require_cvc_recollection: true} } # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods: { enabled: true, }, }) { paymentIntent: paymentIntent['client_secret'], ephemeralKey: ephemeralKey['secret'], customer: customer['id'], publishableKey: '<>' }.to_json end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' @app.route('/payment-sheet', methods=['POST']) def payment_sheet(): # Use an existing Customer ID if this is a returning customer customer = stripe.Customer.create(stripe_account="{{CONNECTED_ACCOUNT_ID}}") ephemeralKey = stripe.EphemeralKey.create( customer=customer['id'], stripe_account="{{CONNECTED_ACCOUNT_ID}}", stripe_version='2026-01-28.clover', ) paymentIntent = stripe.PaymentIntent.create( amount=1099, currency='eur', customer=customer['id'],payment_method_options={ 'card': { 'require_cvc_recollection': True } }, # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods={ 'enabled': True, }, ) return jsonify(paymentIntent=paymentIntent.client_secret, ephemeralKey=ephemeralKey.secret, customer=customer.id, publishableKey='<>') ``` #### PHP ```php >'); // Use an existing Customer ID if this is a returning customer. $customer = $stripe->customers->create(['stripe_account => '{{CONNECTED_ACCOUNT_ID}}']); $ephemeralKey = $stripe->ephemeralKeys->create([ 'customer' => $customer->id, ], [ 'stripe_account' => '{{CONNECTED_ACCOUNT_ID}}', 'stripe_version' => '2026-01-28.clover', ]); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'eur', 'customer' => $customer->id,'payment_method_options' => [ 'card' => ['require_cvc_recollection' => true] ], // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. 'automatic_payment_methods' => [ 'enabled' => 'true', ], ]); echo json_encode( [ 'paymentIntent' => $paymentIntent->client_secret, 'ephemeralKey' => $ephemeralKey->secret, 'customer' => $customer->id, 'publishableKey' => '<>' ] ); http_response_code(200); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; post( "/payment-sheet", (request, response) -> { response.type("application/json"); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); Customer customer = Customer.create(customerParams); // Set the connected account ID String connectedAccountId = "{{CONNECTED_ACCOUNT_ID}}"; // Create RequestOptions with the Stripe-Account header RequestOptions requestOptions = RequestOptions.builder() .setStripeAccount(connectedAccountId) .build(); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); // Pass the requestOptions when creating the customer Customer customer = Customer.create(customerParams, requestOptions); }); EphemeralKeyCreateParams ephemeralKeyParams = EphemeralKeyCreateParams.builder() .setStripeAccount("{{CONNECTED_ACCOUNT_ID}}") .setStripeVersion("2026-01-28.clover") .setCustomer(customer.getId()) .build(); EphemeralKey ephemeralKey = EphemeralKey.create(ephemeralKeyParams); PaymentIntentCreateParams paymentIntentParams = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("eur") .setCustomer(customer.getId()).setPaymentMethodOptions( PaymentIntentCreateParams.PaymentMethodOptions.builder() .setCard( PaymentIntentCreateParams.PaymentMethodOptions.Card.builder() .setRequireCvcRecollection(true) .build() ) .build() ) // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder() .setEnabled(true) .build() ) .build(); PaymentIntent paymentIntent = PaymentIntent.create(paymentIntentParams); Map responseData = new HashMap(); responseData.put("paymentIntent", paymentIntent.getClientSecret()); responseData.put("ephemeralKey", ephemeralKey.getSecret()); responseData.put("customer", customer.getId()); responseData.put("publishableKey", "<>"); return gson.toJson(responseData); }); ``` #### Node.js ```javascript const stripe = require('stripe')('<>'); // This example sets up an endpoint using the Express framework. app.post('/payment-sheet', async (req, res) => { // Use an existing Customer ID if this is a returning customer. const customer = await stripe.customers.create(stripeAccount:'{{CONNECTED_ACCOUNT_ID}}'); const ephemeralKey = await stripe.ephemeralKeys.create( {customer: customer.id}, { stripeAccount: '{{CONNECTED_ACCOUNT_ID}}', apiVersion: '2026-01-28.clover' } ); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'eur', customer: customer.id,payment_method_options: { card: { require_cvc_recollection: true, }, }, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. automatic_payment_methods: { enabled: true, }, }); res.json({ paymentIntent: paymentIntent.client_secret, ephemeralKey: ephemeralKey.secret, customer: customer.id, publishableKey: '<>' }); }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func handlePaymentSheet(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) return } // Use an existing Customer ID if this is a returning customer. cparams := &stripe.CustomerParams{} stripe.SetStripeAccount(cparams.ExtraParams, "{{CONNECTED_ACCOUNT_ID}}") c, _ := customer.New(cparams) ekparams := &stripe.EphemeralKeyParams{ Customer: stripe.String(c.ID), StripeAccount: stripe.String("{{CONNECTED_ACCOUNT_ID}}") StripeVersion: stripe.String("2026-01-28.clover"), } ek, _ := ephemeralKey.New(ekparams) piparams := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyEUR)), Customer: stripe.String(c.ID),PaymentMethodOptions: stripe.PaymentIntentPaymentMethodOptionsParams{ Card: stripe.PaymentIntentPaymentMethodOptionsCardParams{ RequireCvcRecollection: stripe.Bool(true), } }, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods: &stripe.PaymentIntentAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, } pi, _ := paymentintent.New(piparams) writeJSON(w, struct { PaymentIntent string `json:"paymentIntent"` EphemeralKey string `json:"ephemeralKey"` Customer string `json:"customer"` PublishableKey string `json:"publishableKey"` }{ PaymentIntent: pi.ClientSecret, EphemeralKey: ek.Secret, Customer: c.ID, PublishableKey: "<>", }) } ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; [HttpPost("payment-sheet")] public ActionResult CreatePaymentSheet([FromBody] CreatePaymentSheetRequest req) { // Use an existing Customer ID if this is a returning customer. var customerOptions = new CustomerCreateOptions(); var customerService = new CustomerService(); var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTED_ACCOUNT_ID}}" }; var customer = customerService.Create(customerOptions, requestOptions); var ephemeralKeyOptions = new EphemeralKeyCreateOptions { Customer = customer.Id, StipeAccount = "{{CONNECTED_ACCOUNT_ID}}", StripeVersion = "2026-01-28.clover", }; var ephemeralKeyService = new EphemeralKeyService(); var ephemeralKey = ephemeralKeyService.Create(ephemeralKeyOptions); var paymentIntentOptions = new PaymentIntentCreateOptions { Amount = 1099, Currency = "eur", Customer = customer.Id,PaymentMethodOptions = new PaymentIntentPaymentMethodOptionsOptions { Card = new PaymentIntentPaymentMethodOptionsCardOptions { RequireCvcRecollection = true, }, }, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, }; var paymentIntentService = new PaymentIntentService(); PaymentIntent paymentIntent = paymentIntentService.Create(paymentIntentOptions); return new PaymentSheetCreateResponse { PaymentIntent = paymentIntent.ClientSecret, EphemeralKey = ephemeralKey.Secret, Customer = customer.Id, PublishableKey = "<>", }; } ``` # In-app integration for Android > This is a In-app integration for Android for when payment-ui is mobile and platform is android. View the full page at https://docs.stripe.com/payments/accept-a-payment?payment-ui=mobile&platform=android. ![](https://b.stripecdn.com/docs-statics-srv/assets/android-overview.471eaf89a760f5b6a757fd96b6bb9b60.png) Integrate Stripe’s prebuilt payment UI into the checkout of your Android app with the [PaymentSheet](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/index.html) class. ## Set up Stripe [Server-side] [Client-side] First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register). ### Server-side This integration requires endpoints on your server that talk to the Stripe API. Use the official libraries for access to the Stripe API from your server: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` #### Python ```bash # Install through pip pip3 install --upgrade stripe ``` ```bash # Or find the Stripe package on http://pypi.python.org/pypi/stripe/ ``` ```python # Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=5.0.0 ``` #### PHP ```bash # Install the PHP library with Composer composer require stripe/stripe-php ``` ```bash # Or download the source directly: https://github.com/stripe/stripe-php/releases ``` #### Java ```java /* For Gradle, add the following dependency to your build.gradle and replace with the version number you want to use from: - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:31.3.0" ``` ```xml com.stripe stripe-java 31.3.0 ``` ```bash # For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson ``` #### Node.js ```bash # Install with npm npm install stripe --save ``` #### Go ```bash # Make sure your project is using Go Modules go mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v84 ``` ```go // Then import the package import ( "github.com/stripe/stripe-go/v84" ) ``` #### .NET ```bash # Install with dotnet dotnet add package Stripe.net dotnet restore ``` ```bash # Or install with NuGet Install-Package Stripe.net ``` ### Client-side The [Stripe Android SDK](https://github.com/stripe/stripe-android) is open source and [fully documented](https://stripe.dev/stripe-android/). To install the SDK, add `stripe-android` to the `dependencies` block of your [app/build.gradle](https://developer.android.com/studio/build/dependencies) file: #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Stripe Android SDK implementation("com.stripe:stripe-android:22.6.1") // Include the financial connections SDK to support US bank account as a payment method implementation("com.stripe:financial-connections:22.6.1") } ``` #### Groovy ```groovy apply plugin: 'com.android.application' android { ... } dependencies { // ... // Stripe Android SDK implementation 'com.stripe:stripe-android:22.6.1' // Include the financial connections SDK to support US bank account as a payment method implementation 'com.stripe:financial-connections:22.6.1' } ``` > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-android/releases) page on GitHub. To receive notifications when a new release is published, [watch releases for the repository](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository). ## Enable payment methods View your [payment methods settings](https://dashboard.stripe.com/settings/payment_methods) and enable the payment methods you want to support. You need at least one payment method enabled to create a *PaymentIntent* (The Payment Intents API tracks the lifecycle of a customer checkout flow and triggers additional authentication steps when required by regulatory mandates, custom Radar fraud rules, or redirect-based payment methods). By default, Stripe enables cards and other prevalent payment methods that can help you reach more customers, but we recommend turning on additional payment methods that are relevant for your business and customers. See [Payment method support](https://docs.stripe.com/payments/payment-methods/payment-method-support.md) for product and payment method support, and our [pricing page](https://stripe.com/pricing/local-payment-methods) for fees. ## Add an endpoint [Server-side] > #### Note > > To display the PaymentSheet before you create a PaymentIntent, see [Collect payment details before creating an Intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=payment). If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. This integration uses three Stripe API objects: 1. [PaymentIntent](https://docs.stripe.com/api/payment_intents.md): Stripe uses this to represent your intent to collect payment from a customer, tracking your charge attempts and payment state changes throughout the process. 1. (Optional) [Customer](https://docs.stripe.com/api/customers.md): To set up a payment method for future payments, you must attach it to a *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments). Create a Customer object when your customer creates an account with your business. If your customer is making a payment as a guest, you can create a Customer object before payment and associate it with your own internal representation of the customer’s account later. 1. (Optional) [CustomerSession](https://docs.stripe.com/api/customer_sessions.md): Information on the Customer object is sensitive, and can’t be retrieved directly from an app. A CustomerSession grants the SDK temporary scoped access to the Customer and provides additional configuration options. See a complete list of [configuration options](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components). > If you never save cards to a Customer and don’t allow returning Customers to reuse saved cards, you can omit the Customer and CustomerSession objects from your integration. For security reasons, your app can’t create these objects. Instead, add an endpoint on your server that: 1. Retrieves the Customer, or creates a new one. 1. Creates a [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) for the Customer. 1. Creates a PaymentIntent with the [amount](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-amount), [currency](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-currency), and [customer](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer). 1. Returns the Payment Intent’s *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)), the CustomerSession’s `client_secret`, the Customer’s [id](https://docs.stripe.com/api/customers/object.md#customer_object-id), and your [publishable key](https://dashboard.stripe.com/apikeys) to your app. The payment methods shown to customers during the checkout process are also included on the PaymentIntent. You can let Stripe pull payment methods from your Dashboard settings or you can list them manually. Regardless of the option you choose, know that the currency passed in the PaymentIntent filters the payment methods shown to the customer. For example, if you pass `eur` on the PaymentIntent and have OXXO enabled in the Dashboard, OXXO won’t be shown to the customer because OXXO doesn’t support `eur` payments. Unless your integration requires a code-based option for offering payment methods, Stripe recommends the automated option. This is because Stripe evaluates the currency, payment method restrictions, and other parameters to determine the list of supported payment methods. Payment methods that increase conversion and that are most relevant to the currency and customer’s location are prioritized. #### Manage payment methods from the Dashboard You can manage payment methods from the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow. The PaymentIntent is created using the payment methods you configured in the Dashboard. If you don’t want to use the Dashboard or if you want to specify payment methods manually, you can list them using the `payment_method_types` attribute. #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. -d "automatic_payment_methods[enabled]"=true \ ``` #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' post '/payment-sheet' do # Use an existing Customer ID if this is a returning customer customer = Stripe::Customer.create({stripe_account: '{{CONNECTED_ACCOUNT_ID}}'}) customerSession = Stripe::CustomerSession.create({ customer: customer['id'], components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled', }, }, }, }) paymentIntent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'eur', customer: customer['id'], # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods: { enabled: true, }, }) { paymentIntent: paymentIntent['client_secret'], customerSessionClientSecret: customerSession['client_secret'], customer: customer['id'], publishableKey: '<>' }.to_json end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' @app.route('/payment-sheet', methods=['POST']) def payment_sheet(): # Use an existing Customer ID if this is a returning customer customer = stripe.Customer.create(stripe_account="{{CONNECTED_ACCOUNT_ID}}") customerSession = stripe.CustomerSession.create( customer=customer['id'], components={"mobile_payment_element": { "enabled": True "features": { "payment_method_save": "enabled", "payment_method_redisplay": "enabled", "payment_method_remove": "enabled" } }, ) paymentIntent = stripe.PaymentIntent.create( amount=1099, currency='eur', customer=customer['id'], # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods={ 'enabled': True, }, ) return jsonify(paymentIntent=paymentIntent.client_secret, customerSessionClientSecret=customerSession.client_secret, customer=customer.id, publishableKey='<>') ``` #### PHP ```php >'); // Use an existing Customer ID if this is a returning customer. $customer = $stripe->customers->create(['stripe_account => '{{CONNECTED_ACCOUNT_ID}}']); $customerSession = $stripe->customerSessions->create([ 'customer' => $customer->id, 'components' => ['mobile_payment_element' => [ 'enabled' => true, 'features' => [ 'payment_method_save' => 'enabled', 'payment_method_redisplay' => 'enabled', 'payment_method_remove' => 'enabled', ], ], ], ]); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'eur', 'customer' => $customer->id, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. 'automatic_payment_methods' => [ 'enabled' => 'true', ], ]); echo json_encode( [ 'paymentIntent' => $paymentIntent->client_secret, 'customerSessionClientSecret' => $customerSession->client_secret, 'customer' => $customer->id, 'publishableKey' => '<>' ] ); http_response_code(200); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; post( "/payment-sheet", (request, response) -> { response.type("application/json"); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); Customer customer = Customer.create(customerParams); // Set the connected account ID String connectedAccountId = "{{CONNECTED_ACCOUNT_ID}}"; // Create RequestOptions with the Stripe-Account header RequestOptions requestOptions = RequestOptions.builder() .setStripeAccount(connectedAccountId) .build(); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); // Pass the requestOptions when creating the customer Customer customer = Customer.create(customerParams, requestOptions); }); CustomerSessionCreateParams params = CustomerSessionCreateParams.builder() .setCustomer(customer.getId()) .setComponents(CustomerSessionCreateParams.Components.builder().build()) .putExtraParam("components[mobile_payment_element][enabled]", true) .putExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled" ) .build(); CustomerSession customerSession = CustomerSession.create(params); PaymentIntentCreateParams paymentIntentParams = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("eur") .setCustomer(customer.getId()) // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder() .setEnabled(true) .build() ) .build(); PaymentIntent paymentIntent = PaymentIntent.create(paymentIntentParams); Map responseData = new HashMap(); responseData.put("paymentIntent", paymentIntent.getClientSecret()); responseData.put("customerSessionClientSecret", customerSession.getClientSecret()); responseData.put("customer", customer.getId()); responseData.put("publishableKey", "<>"); return gson.toJson(responseData); }); ``` #### Node.js ```javascript const stripe = require('stripe')('<>'); // This example sets up an endpoint using the Express framework. app.post('/payment-sheet', async (req, res) => { // Use an existing Customer ID if this is a returning customer. const customer = await stripe.customers.create(stripeAccount:'{{CONNECTED_ACCOUNT_ID}}'); const customerSession = await stripe.customerSessions.create({ customer: customer.id, components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled' } }, }, }); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'eur', customer: customer.id, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. automatic_payment_methods: { enabled: true, }, }); res.json({ paymentIntent: paymentIntent.client_secret, customerSessionClientSecret: customerSession.client_secret, customer: customer.id, publishableKey: '<>' }); }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func handlePaymentSheet(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) return } // Use an existing Customer ID if this is a returning customer. cparams := &stripe.CustomerParams{} stripe.SetStripeAccount(cparams.ExtraParams, "{{CONNECTED_ACCOUNT_ID}}") c, _ := customer.New(cparams) csParams := &stripe.CustomerSessionParams{ Customer: stripe.String(c.ID), Components: &stripe.CustomerSessionComponentsParams{}, } csParam.AddExtra("components[mobile_payment_element][enabled]", true) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_save]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_remove]", "enabled", ) cs, _ := customersession.New(csParams); piparams := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyEUR)), Customer: stripe.String(c.ID), // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods: &stripe.PaymentIntentAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, } pi, _ := paymentintent.New(piparams) writeJSON(w, struct { PaymentIntent string `json:"paymentIntent"` CustomerSessionClientKey string `json:"customerSessionClientSecret"` Customer string `json:"customer"` PublishableKey string `json:"publishableKey"` }{ PaymentIntent: pi.ClientSecret, CustomerSessionClientKey: cs.ClientSecret, Customer: c.ID, PublishableKey: "<>", }) } ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; [HttpPost("payment-sheet")] public ActionResult CreatePaymentSheet([FromBody] CreatePaymentSheetRequest req) { // Use an existing Customer ID if this is a returning customer. var customerOptions = new CustomerCreateOptions(); var customerService = new CustomerService(); var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTED_ACCOUNT_ID}}" }; var customer = customerService.Create(customerOptions, requestOptions); var customerSessionOptions = new CustomerSessionCreateOptions { Customer = customer.Id, Components = new CustomerSessionComponentsOptions() } customerSessionOptions.AddExtraParam("components[mobile_payment_element][enabled]", true); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled"); var service = new CustomerSessionService(); var customerSession = service.Create(options); var paymentIntentOptions = new PaymentIntentCreateOptions { Amount = 1099, Currency = "eur", Customer = customer.Id, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, }; var paymentIntentService = new PaymentIntentService(); PaymentIntent paymentIntent = paymentIntentService.Create(paymentIntentOptions); return new PaymentSheetCreateResponse { PaymentIntent = paymentIntent.ClientSecret, CustomerSessionClientSecret = customerSession.ClientSecret Customer = customer.Id, PublishableKey = "<>", }; } ``` #### Listing payment methods manually #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ -d "payment_method_types[]"="bancontact" \ -d "payment_method_types[]"="card" \ -d "payment_method_types[]"="ideal" \ -d "payment_method_types[]"="klarna" \ -d "payment_method_types[]"="sepa_debit" \ ``` #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. post '/payment-sheet' do # Use an existing Customer ID if this is a returning customer customer = Stripe::Customer.create({stripe_account: '{{CONNECTED_ACCOUNT_ID}}'}) customerSession = Stripe::CustomerSession.create({ customer: customer['id'], components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled', }, }, }, }) paymentIntent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'eur', customer: customer['id'], payment_method_types: ['bancontact', 'card', 'ideal', 'klarna', 'sepa_debit'], }) { paymentIntent: paymentIntent['client_secret'], customerSessionClientSecret: customerSession['client_secret'], customer: customer['id'], publishableKey: '<>' }.to_json end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck. @app.route('/payment-sheet', methods=['POST']) def payment_sheet(): # Use an existing Customer ID if this is a returning customer customer = stripe.Customer.create(stripe_account="{{CONNECTED_ACCOUNT_ID}}") customerSession = stripe.CustomerSession.create( customer=customer['id'], components={"mobile_payment_element": { "enabled": True "features": { "payment_method_save": "enabled", "payment_method_redisplay": "enabled", "payment_method_remove": "enabled" } }, ) paymentIntent = stripe.PaymentIntent.create( amount=1099, currency='eur', customer=customer['id'], payment_method_types=["bancontact", "card", "ideal", "klarna", "sepa_debit"], ) return jsonify(paymentIntent=paymentIntent.client_secret, customerSessionClientSecret=customerSession.client_secret, customer=customer.id, publishableKey='<>') ``` #### PHP ```php >'); // Use an existing Customer ID if this is a returning customer. $customer = $stripe->customers->create(['stripe_account => '{{CONNECTED_ACCOUNT_ID}}']); $customerSession = $stripe->customerSessions->create([ 'customer' => $customer->id, 'components' => ['mobile_payment_element' => [ 'enabled' => true, 'features' => [ 'payment_method_save' => 'enabled', 'payment_method_redisplay' => 'enabled', 'payment_method_remove' => 'enabled', ], ], ], ]); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'eur', 'customer' => $customer->id, 'payment_method_types' => ['bancontact', 'card', 'ideal', 'klarna', 'sepa_debit'], ]); echo json_encode( [ 'paymentIntent' => $paymentIntent->client_secret, 'customerSessionClientSecret' => $customerSession->client_secret, 'customer' => $customer->id, 'publishableKey' => '<>' ] ); http_response_code(200); ``` #### Java ```java // This example sets up an endpoint using the Spark framework. post("/payment-sheet", (request, response) -> { response.type("application/json"); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); Customer customer = Customer.create(customerParams); CustomerSessionCreateParams params = CustomerSessionCreateParams.builder() .setCustomer(customer.getId()) .setComponents(CustomerSessionCreateParams.Components.builder().build()) .putExtraParam("components[mobile_payment_element][enabled]", true) .putExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled" ) .build(); CustomerSession customerSession = CustomerSession.create(params); List paymentMethodTypes = new ArrayList(); paymentMethodTypes.add("bancontact"); paymentMethodTypes.add("card"); paymentMethodTypes.add("ideal"); paymentMethodTypes.add("klarna"); paymentMethodTypes.add("sepa_debit"); PaymentIntentCreateParams paymentIntentParams = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("eur") .setCustomer(customer.getId()) .addAllPaymentMethodType(paymentMethodTypes) .build(); PaymentIntent paymentIntent = PaymentIntent.create(paymentIntentParams); Map responseData = new HashMap(); responseData.put("paymentIntent", paymentIntent.getClientSecret()); responseData.put("ephemeralKey", ephemeralKey.getSecret()); responseData.put("customer", customer.getId()); responseData.put("publishableKey", "<>"); return gson.toJson(responseData); }); ``` #### Node.js ```javascript // This example sets up an endpoint using the Express framework. app.post('/payment-sheet', async (req, res) => { // Use an existing Customer ID if this is a returning customer. const customer = await stripe.customers.create(stripeAccount:'{{CONNECTED_ACCOUNT_ID}}'); const customerSession = await stripe.customerSessions.create({ customer: customer.id, components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled' } }, }, }); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'eur', customer: customer.id, payment_method_types: ['bancontact', 'card', 'ideal', 'klarna', 'sepa_debit'], }); res.json({ paymentIntent: paymentIntent.client_secret, customerSessionClientSecret: customerSession.client_secret, customer: customer.id, publishableKey: '<>' }); }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func handlePaymentSheet(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) return } // Use an existing Customer ID if this is a returning customer. cparams := &stripe.CustomerParams{} stripe.SetStripeAccount(cparams.ExtraParams, "{{CONNECTED_ACCOUNT_ID}}") c, _ := customer.New(cparams) csParams := &stripe.CustomerSessionParams{ Customer: stripe.String(c.ID), Components: &stripe.CustomerSessionComponentsParams{}, } csParam.AddExtra("components[mobile_payment_element][enabled]", true) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_save]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_remove]", "enabled", ) cs, _ := customersession.New(csParams); piparams := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyEUR)), Customer: stripe.String(c.ID), PaymentMethodTypes: []*string{ stripe.String("bancontact"), stripe.String("card"), stripe.String("ideal"), stripe.String("klarna"), stripe.String("sepa_debit"), }, } pi, _ := paymentintent.New(piparams) writeJSON(w, struct { PaymentIntent string `json:"paymentIntent"` CustomerSessionClientKey string `json:"customerSessionClientSecret"` Customer string `json:"customer"` PublishableKey string `json:"publishableKey"` }{ PaymentIntent: pi.ClientSecret, CustomerSessionClientKey: cs.ClientSecret, Customer: c.ID, PublishableKey: "<>", }) } ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; [HttpPost("payment-sheet")] public ActionResult CreatePaymentSheet([FromBody] CreatePaymentSheetRequest req) { // Use an existing Customer ID if this is a returning customer. var customerOptions = new CustomerCreateOptions(); var customerService = new CustomerService(); var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTED_ACCOUNT_ID}}" }; var customer = customerService.Create(customerOptions, requestOptions); var customerSessionOptions = new CustomerSessionCreateOptions { Customer = customer.Id, Components = new CustomerSessionComponentsOptions() } customerSessionOptions.AddExtraParam("components[mobile_payment_element][enabled]", true); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled"); var service = new CustomerSessionService(); var customerSession = service.Create(options); var paymentIntentOptions = new PaymentIntentCreateOptions { Amount = 1099, Currency = "eur", Customer = customer.Id, PaymentMethodTypes = new List { "bancontact", "card", "ideal", "klarna", "sepa_debit", }, }; var paymentIntentService = new PaymentIntentService(); PaymentIntent paymentIntent = paymentIntentService.Create(paymentIntentOptions); return new PaymentSheetCreateResponse { PaymentIntent = paymentIntent.ClientSecret, CustomerSessionClientSecret = customerSession.ClientSecret Customer = customer.Id, PublishableKey = "<>", }; } ``` > Each payment method needs to support the currency passed in the PaymentIntent and your business needs to be based in one of the countries each payment method supports. See the [Payment method integration options](https://docs.stripe.com/payments/payment-methods/integration-options.md) page for more details about what’s supported. ## Collect payment details [Client-side] Before displaying the mobile Payment Element, your checkout page should: - Show the products being purchased and the total amount - Collect any required shipping information using the [Address Element](https://docs.stripe.com/elements/address-element.md?platform=android) - Include a checkout button to present Stripe’s UI #### Jetpack Compose [Initialize](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-builder/index.html) a `PaymentSheet` instance inside `onCreate` of your checkout Activity, passing a method to handle the result. ```kotlin import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.stripe.android.paymentsheet.PaymentSheet import com.stripe.android.paymentsheet.PaymentSheetResult @Composable fun App() { val paymentSheet = remember { PaymentSheet.Builder(::onPaymentSheetResult) }.build() } private fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) { // implemented in the next steps } ``` Next, fetch the PaymentIntent client secret, Customer Session client secret, Customer ID, and publishable key from the endpoint you created in the previous step. Set the publishable key using `PaymentConfiguration` and store the others for use when you present the PaymentSheet. ```kotlin import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberimport androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import com.stripe.android.PaymentConfiguration import com.stripe.android.paymentsheet.PaymentSheet import com.stripe.android.paymentsheet.PaymentSheetResult @Composable fun App() { val paymentSheet = remember { PaymentSheet.Builder(::onPaymentSheetResult) }.build()val context = LocalContext.current var customerConfig by remember { mutableStateOf(null) } varpaymentIntentClientSecret by remember { mutableStateOf(null) } LaunchedEffect(context) { // Make a request to your own server and retrieve payment configurations val networkResult = ... if (networkResult.isSuccess) {paymentIntentClientSecret = networkResult.paymentIntent customerConfig = PaymentSheet.CustomerConfiguration.createWithCustomerSession( id = networkResult.customer, clientSecret = networkResult.customerSessionClientSecret )PaymentConfiguration.init(context, networkResult.publishableKey)} } } private fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) { // implemented in the next steps } ``` When the customer taps your checkout button, call [presentWithPaymentIntent](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/index.html#1814490530%2FFunctions%2F2002900378) to present the payment sheet. After the customer completes the payment, the sheet dismisses and the [PaymentSheetResultCallback](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet-result-callback/index.html) is called with a [PaymentSheetResult](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet-result/index.html). ```kotlin import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import com.stripe.android.PaymentConfiguration import com.stripe.android.paymentsheet.PaymentSheet import com.stripe.android.paymentsheet.PaymentSheetResult @Composable fun App() { val paymentSheet = remember { PaymentSheet.Builder(::onPaymentSheetResult) }.build() val context = LocalContext.current var customerConfig by remember { mutableStateOf(null) } var paymentIntentClientSecret by remember { mutableStateOf(null) } LaunchedEffect(context) { // Make a request to your own server and retrieve payment configurations val networkResult = ... if (networkResult.isSuccess) { paymentIntentClientSecret = networkResult.paymentIntent customerConfig = PaymentSheet.CustomerConfiguration.createWithCustomerSession( id = networkResult.customer, clientSecret = networkResult.customerSessionClientSecret ) PaymentConfiguration.init(context, networkResult.publishableKey) } }Button( onClick = { val currentConfig = customerConfig val currentClientSecret =paymentIntentClientSecret if (currentConfig != null && currentClientSecret != null) { presentPaymentSheet(paymentSheet, currentConfig, currentClientSecret) } } ) { Text("Checkout") } }private fun presentPaymentSheet( paymentSheet: PaymentSheet, customerConfig: PaymentSheet.CustomerConfiguration,paymentIntentClientSecret: String ) { paymentSheet.presentWithPaymentIntent(paymentIntentClientSecret, PaymentSheet.Configuration.Builder(merchantDisplayName = "My merchant name") .customer(customerConfig) // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. .allowsDelayedPaymentMethods(true) .build() ) } private fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) {when(paymentSheetResult) { is PaymentSheetResult.Canceled -> { print("Canceled") } is PaymentSheetResult.Failed -> { print("Error: ${paymentSheetResult.error}") } is PaymentSheetResult.Completed -> { // Display for example, an order confirmation screen print("Completed") } } } ``` #### Views (Classic) [Initialize](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/index.html#-394860221%2FConstructors%2F2002900378) a `PaymentSheet` instance inside `onCreate` of your checkout Activity, passing a method to handle the result. #### Kotlin ```kotlin import com.stripe.android.paymentsheet.PaymentSheet class CheckoutActivity : AppCompatActivity() { lateinit var paymentSheet: PaymentSheet override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) paymentSheet = PaymentSheet.Builder(::onPaymentSheetResult).build(this) } fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) { // implemented in the next steps } } ``` #### Java ```java import com.stripe.android.paymentsheet.*; class CheckoutActivity extends AppCompatActivity { PaymentSheet paymentSheet; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); paymentSheet = new PaymentSheet.Builder(this::onPaymentSheetResult).build(this); } void onPaymentSheetResult(final PaymentSheetResult paymentSheetResult) { // implemented in the next steps } } ``` Next, fetch the PaymentIntent client secret, Customer Session client secret, Customer ID, and publishable key from the endpoint you created in the previous step. Set the publishable key using `PaymentConfiguration` and store the others for use when you present the PaymentSheet. #### Kotlin ```kotlin import com.stripe.android.paymentsheet.PaymentSheet class CheckoutActivity : AppCompatActivity() { lateinit var paymentSheet: PaymentSheetlateinit var customerConfig: PaymentSheet.CustomerConfiguration lateinit varpaymentIntentClientSecret: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) paymentSheet = PaymentSheet.Builder(::onPaymentSheetResult).build(this)lifecycleScope.launch { // Make a request to your own server and retrieve payment configurations val networkResult = MyBackend.getPaymentConfig() if (networkResult.isSuccess) {paymentIntentClientSecret = networkResult.paymentIntent customerConfig = PaymentSheet.CustomerConfiguration.createWithCustomerSession( id = networkResult.customer, clientSecret = networkResult.customerSessionClientSecret )PaymentConfiguration.init(context, networkResult.publishableKey)} } } fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) { // implemented in the next steps } } ``` #### Java ```java import com.stripe.android.paymentsheet.*;import com.stripe.android.PaymentConfiguration; class CheckoutActivity extends AppCompatActivity { PaymentSheet paymentSheet;StringpaymentIntentClientSecret; PaymentSheet.CustomerConfiguration customerConfig; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); paymentSheet = new PaymentSheet.Builder(this::onPaymentSheetResult).build(this); // Make async request to your own server MyBackend.getPaymentConfig(new NetworkCallback() { @Override public void onSuccess(NetworkResult networkResult) { if (networkResult.isSuccess()) { customerConfig = new PaymentSheet.CustomerConfiguration.createWithCustomerSession( networkResult.getCustomer(), networkResult.getCustomerSessionClientSecret() );paymentIntentClientSecret = networkResult.getpaymentIntent();PaymentConfiguration.init(getApplicationContext(), networkResult.getPublishableKey());} } @Override public void onError(Exception error) { // Handle error } }); } void onPaymentSheetResult(final PaymentSheetResult paymentSheetResult) { // implemented in the next steps } } ``` When the customer taps your checkout button, call [presentWithPaymentIntent](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/index.html#1814490530%2FFunctions%2F2002900378) to present the payment sheet. After the customer completes the payment, the sheet dismisses and the [PaymentSheetResultCallback](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet-result-callback/index.html) is called with a [PaymentSheetResult](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet-result/index.html). #### Kotlin ```kotlin // ... class CheckoutActivity : AppCompatActivity() { lateinit var paymentSheet: PaymentSheet lateinit var customerConfig: PaymentSheet.CustomerConfiguration lateinit var paymentIntentClientSecret: String // ...fun presentPaymentSheet() { paymentSheet.presentWithPaymentIntent(paymentIntentClientSecret, PaymentSheet.Configuration.Builder(merchantDisplayName = "My merchant name") .customer(customerConfig) // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. .allowsDelayedPaymentMethods(true) .build() ) } fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) {when(paymentSheetResult) { is PaymentSheetResult.Canceled -> { print("Canceled") } is PaymentSheetResult.Failed -> { print("Error: ${paymentSheetResult.error}") } is PaymentSheetResult.Completed -> { // Display for example, an order confirmation screen print("Completed") } } } } ``` #### Java ```java // ... public class CheckoutActivity extends AppCompatActivity {private static final String TAG = "CheckoutActivity"; private PaymentSheet paymentSheet; private String paymentClientSecret; PaymentSheet.CustomerConfiguration customerConfig; // ...private void presentPaymentSheet() { final PaymentSheet.Configuration configuration = new PaymentSheet.Configuration.Builder("Example, Inc.") .customer(customerConfig) // Set `allowsDelayedPaymentMethods` to true if your business handles payment methods // delayed notification payment methods like US bank accounts. .allowsDelayedPaymentMethods(true) .build(); paymentSheet.presentWithPaymentIntent(paymentClientSecret, configuration ); } private void onPaymentSheetResult( final PaymentSheetResult paymentSheetResult ) {if (paymentSheetResult instanceof PaymentSheetResult.Canceled) { Log.d(TAG, "Canceled") } else if (paymentSheetResult instanceof PaymentSheetResult.Failed) { Log.e(TAG, "Got error: ", ((PaymentSheetResult.Failed) paymentSheetResult).getError()); } else if (paymentSheetResult instanceof PaymentSheetResult.Completed) { // Display for example, an order confirmation screen Log.d(TAG, "Completed") } } } ``` Setting `allowsDelayedPaymentMethods` to true allows [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment methods like US bank accounts. For these payment methods, the final payment status isn’t known when the `PaymentSheet` completes, and instead succeeds or fails later. If you support these types of payment methods, inform the customer their order is confirmed and only fulfill their order (for example, ship their product) when the payment is successful. ## Handle post-payment events [Server-side] Stripe sends a [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) event when the payment completes. Use the [Dashboard webhook tool](https://dashboard.stripe.com/webhooks) or follow the [webhook guide](https://docs.stripe.com/webhooks/quickstart.md) to receive these events and run actions, such as sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow. Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events is what enables you to accept [different types of payment methods](https://stripe.com/payments/payment-methods-guide) with a single integration. In addition to handling the `payment_intent.succeeded` event, we recommend handling these other events when collecting payments with the Payment Element: | Event | Description | Action | | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.succeeded) | Sent when a customer successfully completes a payment. | Send the customer an order confirmation and *fulfill* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) their order. | | [payment_intent.processing](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.processing) | Sent when a customer successfully initiates a payment, but the payment has yet to complete. This event is most commonly sent when the customer initiates a bank debit. It’s followed by either a `payment_intent.succeeded` or `payment_intent.payment_failed` event in the future. | Send the customer an order confirmation that indicates their payment is pending. For digital goods, you might want to fulfill the order before waiting for payment to complete. | | [payment_intent.payment_failed](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.payment_failed) | Sent when a customer attempts a payment, but the payment fails. | If a payment transitions from `processing` to `payment_failed`, offer the customer another attempt to pay. | ## Test the integration #### Cards | Card number | Scenario | How to test | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | 4242424242424242 | The card payment succeeds and doesn’t require authentication. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000002500003155 | The card payment requires *authentication* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase). | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 4000000000009995 | The card is declined with a decline code like `insufficient_funds`. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | | 6205500000000000004 | The UnionPay card has a variable length of 13-19 digits. | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. | #### Bank redirects | Payment method | Scenario | How to test | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | Bancontact, iDEAL | Your customer fails to authenticate on the redirect page for a redirect-based and immediate notification payment method. | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | Pay by Bank | Your customer successfully pays with a redirect-based and [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page. | | Pay by Bank | Your customer fails to authenticate on the redirect page for a redirect-based and delayed notification payment method. | Choose the payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. | | BLIK | BLIK payments fail in a variety of ways—immediate failures (for example, the code is expired or invalid), delayed errors (the bank declines) or timeouts (the customer didn’t respond in time). | Use email patterns to [simulate the different failures.](https://docs.stripe.com/payments/blik/accept-a-payment.md#simulate-failures) | #### Bank debits | Payment method | Scenario | How to test | | ----------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SEPA Direct Debit | Your customer successfully pays with SEPA Direct Debit. | Fill out the form using the account number `AT321904300235473204`. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later. | | SEPA Direct Debit | Your customer’s payment intent status transitions from `processing` to `requires_payment_method`. | Fill out the form using the account number `AT861904300235473202`. | See [Testing](https://docs.stripe.com/testing.md) for additional information to test your integration. ## Optional: Enable Link Enable Link in your [Payment Method settings](https://dashboard.stripe.com/settings/payment_methods) to allow your customers to securely save and reuse their payment information using Link’s one-click express checkout button. ### Pass your customer’s email to the Mobile Payment Element Link authenticates a customer using their email address. Stripe recommends prefilling as much information as possible to streamline the checkout process. To prefill the customer’s name, email address, and phone number, supply `defaultBillingDetails` with your customer information when initializing `PaymentSheet.Configuration`. #### Kotlin ```kotlin val configuration = PaymentSheet.Configuration.Builder(merchantDisplayName = "Example, Inc.") .defaultBillingDetails( PaymentSheet.BillingDetails( name = "Jenny Rosen", email = "jenny.rosen@example.com", phone = "888-888-8888" ) ) .build() ``` #### Java ```java PaymentSheet.BillingDetails billingDetails = new PaymentSheet.BillingDetails.Builder() .name("Jenny Rosen") .email("jenny.rosen@example.com") .phone("888-888-8888") .build(); PaymentSheet.Configuration configuration = new PaymentSheet.Configuration.Builder(...) .defaultBillingDetails(billingDetails) .build(); ``` ## Optional: Enable Google Pay ### Set up your integration To use Google Pay, first enable the Google Pay API by adding the following to the `` tag of your **AndroidManifest.xml**: ```xml ... ``` For more details, see Google Pay’s [Set up Google Pay API](https://developers.google.com/pay/api/android/guides/setup) for Android. ### Add Google Pay To add Google Pay to your integration, pass a [PaymentSheet.GooglePayConfiguration](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-google-pay-configuration/index.html) with your Google Pay environment (production or test) and the [country code of your business](https://dashboard.stripe.com/settings/account) when initializing [PaymentSheet.Configuration](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-configuration/index.html). #### Kotlin ```kotlin val googlePayConfiguration = PaymentSheet.GooglePayConfiguration( environment = PaymentSheet.GooglePayConfiguration.Environment.Test, countryCode = "US", currencyCode = "USD" // Required for Setup Intents, optional for Payment Intents ) val configuration = PaymentSheet.Configuration.Builder(merchantDisplayName = "My merchant name") .googlePay(googlePayConfiguration) .build() ``` #### Java ```java final PaymentSheet.GooglePayConfiguration googlePayConfiguration = new PaymentSheet.GooglePayConfiguration( PaymentSheet.GooglePayConfiguration.Environment.Test, "US" ); final PaymentSheet.Configuration configuration = // ... configuration.setGooglePay(googlePayConfiguration); ); ``` ### Test Google Pay Google allows you to make test payments through their [Test card suite](https://developers.google.com/pay/api/android/guides/resources/test-card-suite). The test suite supports using Stripe [test cards](https://docs.stripe.com/testing.md). You must test Google Pay using a physical Android device instead of a simulated device, in a country where Google Pay is supported. Log in to a Google account on your test device with a real card saved to Google Wallet. ## Optional: Enable card scanning To enable card scanning support, [request production access](https://developers.google.com/pay/api/android/guides/test-and-deploy/request-prod-access) to the Google Pay API from the [Google Pay and Wallet Console](https://pay.google.com/business/console?utm_source=devsite&utm_medium=devsite&utm_campaign=devsite). - If you’ve enabled Google Pay, the card scanning feature is automatically available in our UI on eligible devices. To learn more about eligible devices, see the [Google Pay API constraints](https://developers.google.com/pay/payment-card-recognition/debit-credit-card-recognition) - **Important:** The card scanning feature only appears in builds signed with the same signing key registered in the [Google Pay & Wallet Console](https://pay.google.com/business/console). Test or debug builds using different signing keys (for example, builds distributed through Firebase App Tester) won’t show the **Scan card** option. To test card scanning in pre-release builds, you must either: - Sign your test builds with your production signing key - Add your test signing key fingerprint to the Google Pay and Wallet Console ## Optional: Enable ACH payments To enable ACH debit payments include Financial Connections as a dependency for your app. The [Stripe Android SDK](https://github.com/stripe/stripe-android) is open source and [fully documented](https://stripe.dev/stripe-android/). To install the SDK, add `financial-connections` to the `dependencies` block of your [app/build.gradle](https://developer.android.com/studio/build/dependencies) file: #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Financial Connections Android SDK implementation("com.stripe:financial-connections:22.6.1") } ``` #### Groovy ```groovy apply plugin: 'com.android.application' android { ... } dependencies { // ... // Financial Connections Android SDK implementation 'com.stripe:financial-connections:22.6.1' } ``` > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-android/releases) page on GitHub. To receive notifications when a new release is published, [watch releases for the repository](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository). ## Optional: Customize the sheet All customization is configured using the [PaymentSheet.Configuration](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-configuration/index.html) object. ### Appearance Customize colors, fonts, and more to match the look and feel of your app by using the [appearance API](https://docs.stripe.com/elements/appearance-api.md?platform=android). ### Payment method layout Configure the layout of payment methods in the sheet using [paymentMethodLayout](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-configuration/-builder/index.html#2123253356%2FFunctions%2F2002900378). You can display them horizontally, vertically, or let Stripe optimize the layout automatically. ![](https://b.stripecdn.com/docs-statics-srv/assets/android-mpe-payment-method-layouts.3bcfe828ceaad1a94e0572a22d91733f.png) #### Kotlin ```kotlin PaymentSheet.Configuration.Builder("Example, Inc.") .paymentMethodLayout(PaymentSheet.PaymentMethodLayout.Automatic) .build() ``` #### Java ```java new PaymentSheet.Configuration.Builder("Example, Inc.") .paymentMethodLayout(PaymentSheet.PaymentMethodLayout.Automatic) .build(); ``` ### Collect users addresses Collect local and international shipping or billing addresses from your customers using the [Address Element](https://docs.stripe.com/elements/address-element.md?platform=android). ### Business display name Specify a customer-facing business name by setting [merchantDisplayName](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-configuration/index.html#-191101533%2FProperties%2F2002900378). By default, this is your app’s name. #### Kotlin ```kotlin PaymentSheet.Configuration.Builder( merchantDisplayName = "My app, Inc." ).build() ``` #### Java ```java new PaymentSheet.Configuration.Builder("My app, Inc.") .build(); ``` ### Dark mode By default, `PaymentSheet` automatically adapts to the user’s system-wide appearance settings (light and dark mode). You can change this by setting light or dark mode on your app: #### Kotlin ```kotlin // force dark AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) // force light AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) ``` #### Java ```java // force dark AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); // force light AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); ``` ### Default billing details To set default values for billing details collected in the payment sheet, configure the `defaultBillingDetails` property. The `PaymentSheet` pre-populates its fields with the values that you provide. #### Kotlin ```kotlin val address = PaymentSheet.Address(country = "US") val billingDetails = PaymentSheet.BillingDetails( address = address, email = "foo@bar.com" ) val configuration = PaymentSheet.Configuration.Builder(merchantDisplayName = "Merchant, Inc.") .defaultBillingDetails(billingDetails) .build() ``` #### Java ```java PaymentSheet.Address address = new PaymentSheet.Address.Builder() .country("US") .build(); PaymentSheet.BillingDetails billingDetails = new PaymentSheet.BillingDetails.Builder() .address(address) .email("foo@bar.com") .build(); PaymentSheet.Configuration configuration = new PaymentSheet.Configuration.Builder("Merchant, Inc.") .defaultBillingDetails(billingDetails) .build(); ``` ### Configure collection of billing details Use `BillingDetailsCollectionConfiguration` to specify how you want to collect billing details in the PaymentSheet. You can collect your customer’s name, email, phone number, and address. If you want to attach default billing details to the PaymentMethod object even when those fields aren’t collected in the UI, set `billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod` to `true`. #### Kotlin ```kotlin val billingDetails = PaymentSheet.BillingDetails( email = "foo@bar.com" ) val billingDetailsCollectionConfiguration = BillingDetailsCollectionConfiguration( attachDefaultsToPaymentMethod = true, name = BillingDetailsCollectionConfiguration.CollectionMode.Always, email = BillingDetailsCollectionConfiguration.CollectionMode.Never, address = BillingDetailsCollectionConfiguration.AddressCollectionMode.Full, ) val configuration = PaymentSheet.Configuration.Builder(merchantDisplayName = "Merchant, Inc.") .defaultBillingDetails(billingDetails) .billingDetailsCollectionConfiguration(billingDetailsCollectionConfiguration) .build() ``` #### Java ```java PaymentSheet.BillingDetails billingDetails = new PaymentSheet.BillingDetails.Builder() .email("foo@bar.com") .build(); BillingDetailsCollectionConfiguration billingDetailsCollectionConfiguration = new BillingDetailsCollectionConfiguration( /* name */ BillingDetailsCollectionConfiguration.CollectionMode.Always, /* email */ BillingDetailsCollectionConfiguration.CollectionMode.Never, /* phone */ BillingDetailsCollectionConfiguration.CollectionMode.Automatic, /* address */ BillingDetailsCollectionConfiguration.AddressCollectionMode.Automatic, /* attachDefaultsToPaymentMethod */ true ) PaymentSheet.Configuration configuration = new PaymentSheet.Configuration.Builder("Merchant, Inc.") .defaultBillingDetails(billingDetails) .billingDetailsCollectionConfiguration(billingDetailsCollectionConfiguration) .build(); ``` > Consult with your legal counsel regarding laws that apply to collecting information. Only collect phone numbers if you need them for the transaction. ## Optional: Handle user logout `PaymentSheet` stores some information locally to remember whether a user has used Link within an app. To clear the internal state of `PaymentSheet`, call the `PaymentSheet.resetCustomer()` method when your user logs out. #### Kotlin ```kotlin class MyActivity: Activity { fun onLogoutButtonClicked() { PaymentSheet.resetCustomer(this) // Other logout logic required by your app } } ``` #### Java ```java import com.stripe.android.paymentsheet.*; class MyActivity extends Activity { void onLogoutButtonClicked() { PaymentSheet.resetCustomer(this) // Other logout logic required by your app } } ``` ## Optional: Complete payment in your UI You can present Payment Sheet to only collect payment method details and complete the payment back in your app’s UI. This is useful if you have a custom buy button or require additional steps after payment details are collected. ![](https://b.stripecdn.com/docs-statics-srv/assets/android-multi-step.84d8a0a44b1baa596bda491322b6d9fd.png) > A sample integration is [available on our GitHub](https://github.com/stripe/stripe-android/blob/master/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/samples/ui/paymentsheet/custom_flow/CustomFlowActivity.kt). 1. First, initialize [PaymentSheet.FlowController](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-flow-controller/index.html) instead of `PaymentSheet` using one of the [Builder](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-flow-controller/-builder/index.html) methods. #### Android (Kotlin) ```kotlin class CheckoutActivity : AppCompatActivity() { private lateinit var flowController: PaymentSheet.FlowController override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val flowController = PaymentSheet.FlowController.Builder( resultCallback = ::onPaymentSheetResult, paymentOptionResultCallback = ::onPaymentOption, ).build(this) } } ``` #### Android (Java) ```java public class CheckoutActivity extends AppCompatActivity { private PaymentSheet.FlowController flowController; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); final PaymentOptionCallback paymentOptionCallback = paymentOption -> { onPaymentOption(paymentOption); }; final PaymentSheetResultCallback paymentSheetResultCallback = paymentSheetResult -> { onPaymentSheetResult(paymentSheetResult); }; flowController = new PaymentSheet.FlowController.Builder( paymentSheetResultCallback, paymentOptionCallback ).build(this); } } ``` 1. Next, call `configureWithPaymentIntent` with the Stripe object keys fetched from your backend and update your UI in the callback using [getPaymentOption()](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-flow-controller/index.html#-2091462043%2FFunctions%2F2002900378). This contains an image and label representing the customer’s currently selected payment method. #### Android (Kotlin) ```kotlin flowController.configureWithPaymentIntent( paymentIntentClientSecret = paymentIntentClientSecret, configuration = PaymentSheet.Configuration.Builder("Example, Inc.") .customer(PaymentSheet.CustomerConfiguration( id = customerId, ephemeralKeySecret = ephemeralKeySecret )) .build() ) { isReady, error -> if (isReady) { // Update your UI using `flowController.getPaymentOption()` } else { // handle FlowController configuration failure } } ``` #### Android (Java) ```java flowController.configureWithPaymentIntent( paymentIntentClientSecret, new PaymentSheet.Configuration.Builder("Example, Inc.") .customer(new PaymentSheet.CustomerConfiguration( customerId, ephemeralKeySecret )) .build(), (success, error) -> { if (success) { // Update your UI using `flowController.getPaymentOption()` } else { // handle FlowController configuration failure } } ); ``` 1. Next, call [presentPaymentOptions](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-flow-controller/index.html#449924733%2FFunctions%2F2002900378) to collect payment details. When the customer finishes, the sheet is dismissed and calls the [paymentOptionCallback](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-option-callback/index.html) passed earlier in `create`. Implement this method to update your UI with the returned `paymentOption`. #### Android (Kotlin) ```kotlin // ... flowController.presentPaymentOptions() // ... private fun onPaymentOption(paymentOptionResult: PaymentOptionResult) { val paymentOption = paymentOptionResult.paymentOption if (paymentOption != null) { paymentMethodButton.text = paymentOption.label paymentMethodButton.setCompoundDrawablesRelativeWithIntrinsicBounds( paymentOption.drawableResourceId, 0, 0, 0 ) } else { paymentMethodButton.text = "Select" paymentMethodButton.setCompoundDrawablesRelativeWithIntrinsicBounds( null, null, null, null ) } } ``` #### Android (Java) ```java // ... flowController.presentPaymentOptions()); // ... private void onPaymentOption( @Nullable PaymentOption paymentOption ) { if (paymentOption != null) { paymentMethodButton.setText(paymentOption.getLabel()); paymentMethodButton.setCompoundDrawablesRelativeWithIntrinsicBounds( paymentOption.getDrawableResourceId(), 0, 0, 0 ); } else { paymentMethodButton.setText("Select"); paymentMethodButton.setCompoundDrawablesRelativeWithIntrinsicBounds( null, null, null, null ); } } private void onCheckout() { // see below } } ``` 1. Finally, call [confirm](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-flow-controller/index.html#-479056656%2FFunctions%2F2002900378) to complete the payment. When the customer finishes, the sheet is dismissed and calls the [paymentResultCallback](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet-result-callback/index.html#237248767%2FFunctions%2F2002900378) passed earlier in `create`. #### Android (Kotlin) ```kotlin // ... flowController.confirmPayment() // ... private fun onPaymentSheetResult( paymentSheetResult: PaymentSheetResult ) { when (paymentSheetResult) { is PaymentSheetResult.Canceled -> { // Payment canceled } is PaymentSheetResult.Failed -> { // Payment Failed. See logcat for details or inspect paymentSheetResult.error } is PaymentSheetResult.Completed -> { // Payment Complete } } } ``` #### Android (Java) ```java // ... flowController.confirmPayment(); // ... private void onPaymentSheetResult( final PaymentSheetResult paymentSheetResult ) { if (paymentSheetResult instanceof PaymentSheetResult.Canceled) { // Payment Canceled } else if (paymentSheetResult instanceof PaymentSheetResult.Failed) { // Payment Failed. See logcat for details or inspect paymentSheetResult.getError() } else if (paymentSheetResult instanceof PaymentSheetResult.Completed) { // Payment Complete } } ``` Setting `allowsDelayedPaymentMethods` to true allows [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment methods like US bank accounts. For these payment methods, the final payment status isn’t known when the `PaymentSheet` completes, and instead succeeds or fails later. If you support these types of payment methods, inform the customer their order is confirmed and only fulfill their order (for example, ship their product) when the payment is successful. ## Optional: Enable CVC recollection on confirmation The following instructions for re-collecting the CVC of a saved card during PaymentIntent confirmation assume that your integration includes the following: - Creation of PaymentIntents before collecting payment details ### Update parameters of the intent creation To re-collect the CVC when confirming payment, include `require_cvc_recollection` during the creation of the PaymentIntent. #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an Ephemeral Key for the Customer curl https://api.stripe.com/v1/ephemeral_keys \ -u <>: \ -H "Stripe-Version: 2026-01-28.clover" \ -H "Stripe-Account: 2026-01-28.clover" \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \-d "payment_method_options[card][require_cvc_recollection]"=true \ # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. -d "automatic_payment_methods[enabled]"=true \ ``` #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' post '/payment-sheet' do # Use an existing Customer ID if this is a returning customer customer = Stripe::Customer.create({stripe_account: '{{CONNECTED_ACCOUNT_ID}}'}) ephemeralKey = Stripe::EphemeralKey.create({ customer: customer['id'], }, {stripe_version: '2026-01-28.clover', stripe_account: '{{CONNECTED_ACCOUNT_ID}}'}) paymentIntent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'eur', customer: customer['id'],payment_method_options: { card: {require_cvc_recollection: true} } # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods: { enabled: true, }, }) { paymentIntent: paymentIntent['client_secret'], ephemeralKey: ephemeralKey['secret'], customer: customer['id'], publishableKey: '<>' }.to_json end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' @app.route('/payment-sheet', methods=['POST']) def payment_sheet(): # Use an existing Customer ID if this is a returning customer customer = stripe.Customer.create(stripe_account="{{CONNECTED_ACCOUNT_ID}}") ephemeralKey = stripe.EphemeralKey.create( customer=customer['id'], stripe_account="{{CONNECTED_ACCOUNT_ID}}", stripe_version='2026-01-28.clover', ) paymentIntent = stripe.PaymentIntent.create( amount=1099, currency='eur', customer=customer['id'],payment_method_options={ 'card': { 'require_cvc_recollection': True } }, # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods={ 'enabled': True, }, ) return jsonify(paymentIntent=paymentIntent.client_secret, ephemeralKey=ephemeralKey.secret, customer=customer.id, publishableKey='<>') ``` #### PHP ```php >'); // Use an existing Customer ID if this is a returning customer. $customer = $stripe->customers->create(['stripe_account => '{{CONNECTED_ACCOUNT_ID}}']); $ephemeralKey = $stripe->ephemeralKeys->create([ 'customer' => $customer->id, ], [ 'stripe_account' => '{{CONNECTED_ACCOUNT_ID}}', 'stripe_version' => '2026-01-28.clover', ]); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'eur', 'customer' => $customer->id,'payment_method_options' => [ 'card' => ['require_cvc_recollection' => true] ], // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. 'automatic_payment_methods' => [ 'enabled' => 'true', ], ]); echo json_encode( [ 'paymentIntent' => $paymentIntent->client_secret, 'ephemeralKey' => $ephemeralKey->secret, 'customer' => $customer->id, 'publishableKey' => '<>' ] ); http_response_code(200); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; post( "/payment-sheet", (request, response) -> { response.type("application/json"); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); Customer customer = Customer.create(customerParams); // Set the connected account ID String connectedAccountId = "{{CONNECTED_ACCOUNT_ID}}"; // Create RequestOptions with the Stripe-Account header RequestOptions requestOptions = RequestOptions.builder() .setStripeAccount(connectedAccountId) .build(); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); // Pass the requestOptions when creating the customer Customer customer = Customer.create(customerParams, requestOptions); }); EphemeralKeyCreateParams ephemeralKeyParams = EphemeralKeyCreateParams.builder() .setStripeAccount("{{CONNECTED_ACCOUNT_ID}}") .setStripeVersion("2026-01-28.clover") .setCustomer(customer.getId()) .build(); EphemeralKey ephemeralKey = EphemeralKey.create(ephemeralKeyParams); PaymentIntentCreateParams paymentIntentParams = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("eur") .setCustomer(customer.getId()).setPaymentMethodOptions( PaymentIntentCreateParams.PaymentMethodOptions.builder() .setCard( PaymentIntentCreateParams.PaymentMethodOptions.Card.builder() .setRequireCvcRecollection(true) .build() ) .build() ) // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder() .setEnabled(true) .build() ) .build(); PaymentIntent paymentIntent = PaymentIntent.create(paymentIntentParams); Map responseData = new HashMap(); responseData.put("paymentIntent", paymentIntent.getClientSecret()); responseData.put("ephemeralKey", ephemeralKey.getSecret()); responseData.put("customer", customer.getId()); responseData.put("publishableKey", "<>"); return gson.toJson(responseData); }); ``` #### Node.js ```javascript const stripe = require('stripe')('<>'); // This example sets up an endpoint using the Express framework. app.post('/payment-sheet', async (req, res) => { // Use an existing Customer ID if this is a returning customer. const customer = await stripe.customers.create(stripeAccount:'{{CONNECTED_ACCOUNT_ID}}'); const ephemeralKey = await stripe.ephemeralKeys.create( {customer: customer.id}, { stripeAccount: '{{CONNECTED_ACCOUNT_ID}}', apiVersion: '2026-01-28.clover' } ); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'eur', customer: customer.id,payment_method_options: { card: { require_cvc_recollection: true, }, }, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. automatic_payment_methods: { enabled: true, }, }); res.json({ paymentIntent: paymentIntent.client_secret, ephemeralKey: ephemeralKey.secret, customer: customer.id, publishableKey: '<>' }); }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func handlePaymentSheet(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) return } // Use an existing Customer ID if this is a returning customer. cparams := &stripe.CustomerParams{} stripe.SetStripeAccount(cparams.ExtraParams, "{{CONNECTED_ACCOUNT_ID}}") c, _ := customer.New(cparams) ekparams := &stripe.EphemeralKeyParams{ Customer: stripe.String(c.ID), StripeAccount: stripe.String("{{CONNECTED_ACCOUNT_ID}}") StripeVersion: stripe.String("2026-01-28.clover"), } ek, _ := ephemeralKey.New(ekparams) piparams := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyEUR)), Customer: stripe.String(c.ID),PaymentMethodOptions: stripe.PaymentIntentPaymentMethodOptionsParams{ Card: stripe.PaymentIntentPaymentMethodOptionsCardParams{ RequireCvcRecollection: stripe.Bool(true), } }, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods: &stripe.PaymentIntentAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, } pi, _ := paymentintent.New(piparams) writeJSON(w, struct { PaymentIntent string `json:"paymentIntent"` EphemeralKey string `json:"ephemeralKey"` Customer string `json:"customer"` PublishableKey string `json:"publishableKey"` }{ PaymentIntent: pi.ClientSecret, EphemeralKey: ek.Secret, Customer: c.ID, PublishableKey: "<>", }) } ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; [HttpPost("payment-sheet")] public ActionResult CreatePaymentSheet([FromBody] CreatePaymentSheetRequest req) { // Use an existing Customer ID if this is a returning customer. var customerOptions = new CustomerCreateOptions(); var customerService = new CustomerService(); var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTED_ACCOUNT_ID}}" }; var customer = customerService.Create(customerOptions, requestOptions); var ephemeralKeyOptions = new EphemeralKeyCreateOptions { Customer = customer.Id, StipeAccount = "{{CONNECTED_ACCOUNT_ID}}", StripeVersion = "2026-01-28.clover", }; var ephemeralKeyService = new EphemeralKeyService(); var ephemeralKey = ephemeralKeyService.Create(ephemeralKeyOptions); var paymentIntentOptions = new PaymentIntentCreateOptions { Amount = 1099, Currency = "eur", Customer = customer.Id,PaymentMethodOptions = new PaymentIntentPaymentMethodOptionsOptions { Card = new PaymentIntentPaymentMethodOptionsCardOptions { RequireCvcRecollection = true, }, }, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, }; var paymentIntentService = new PaymentIntentService(); PaymentIntent paymentIntent = paymentIntentService.Create(paymentIntentOptions); return new PaymentSheetCreateResponse { PaymentIntent = paymentIntent.ClientSecret, EphemeralKey = ephemeralKey.Secret, Customer = customer.Id, PublishableKey = "<>", }; } ``` # In-app integration for React Native > This is a In-app integration for React Native for when payment-ui is mobile and platform is react-native. View the full page at https://docs.stripe.com/payments/accept-a-payment?payment-ui=mobile&platform=react-native. ![](https://b.stripecdn.com/docs-statics-srv/assets/ios-overview.9e0d68d009dc005f73a6f5df69e00458.png) This integration combines all of the steps required to pay, including collecting payment details and confirming the payment, into a single sheet that displays on top of your app. ## Set up Stripe [Server-side] [Client-side] First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register). ### Server-side This integration requires endpoints on your server that talk to the Stripe API. Use the official libraries for access to the Stripe API from your server: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` #### Python ```bash # Install through pip pip3 install --upgrade stripe ``` ```bash # Or find the Stripe package on http://pypi.python.org/pypi/stripe/ ``` ```python # Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=5.0.0 ``` #### PHP ```bash # Install the PHP library with Composer composer require stripe/stripe-php ``` ```bash # Or download the source directly: https://github.com/stripe/stripe-php/releases ``` #### Java ```java /* For Gradle, add the following dependency to your build.gradle and replace with the version number you want to use from: - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:31.3.0" ``` ```xml com.stripe stripe-java 31.3.0 ``` ```bash # For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson ``` #### Node.js ```bash # Install with npm npm install stripe --save ``` #### Go ```bash # Make sure your project is using Go Modules go mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v84 ``` ```go // Then import the package import ( "github.com/stripe/stripe-go/v84" ) ``` #### .NET ```bash # Install with dotnet dotnet add package Stripe.net dotnet restore ``` ```bash # Or install with NuGet Install-Package Stripe.net ``` ### Client-side The [React Native SDK](https://github.com/stripe/stripe-react-native) is open source and fully documented. Internally, it uses the [native iOS](https://github.com/stripe/stripe-ios) and [Android](https://github.com/stripe/stripe-android) SDKs. To install Stripe’s React Native SDK, run one of the following commands in your project’s directory (depending on which package manager you use): #### yarn ```bash yarn add @stripe/stripe-react-native ``` #### npm ```bash npm install @stripe/stripe-react-native ``` Next, install some other necessary dependencies: - For iOS, go to the **ios** directory and run `pod install` to ensure that you also install the required native dependencies. - For Android, there are no more dependencies to install. > We recommend following the [official TypeScript guide](https://reactnative.dev/docs/typescript#adding-typescript-to-an-existing-project) to add TypeScript support. ### Stripe initialization To initialize Stripe in your React Native app, either wrap your payment screen with the `StripeProvider` component, or use the `initStripe` initialization method. Only the API [publishable key](https://docs.stripe.com/keys.md#obtain-api-keys) in `publishableKey` is required. The following example shows how to initialize Stripe using the `StripeProvider` component. ```jsx import { useState, useEffect } from 'react'; import { StripeProvider } from '@stripe/stripe-react-native'; function App() { const [publishableKey, setPublishableKey] = useState(''); const fetchPublishableKey = async () => { const key = await fetchKey(); // fetch key from your server here setPublishableKey(key); }; useEffect(() => { fetchPublishableKey(); }, []); return ( {/* Your app code here */} ); } ``` > Use your API [test keys](https://docs.stripe.com/keys.md#obtain-api-keys) while you test and develop, and your [live mode](https://docs.stripe.com/keys.md#test-live-modes) keys when you publish your app. ## Enable payment methods View your [payment methods settings](https://dashboard.stripe.com/settings/payment_methods) and enable the payment methods you want to support. You need at least one payment method enabled to create a *PaymentIntent* (The Payment Intents API tracks the lifecycle of a customer checkout flow and triggers additional authentication steps when required by regulatory mandates, custom Radar fraud rules, or redirect-based payment methods). By default, Stripe enables cards and other prevalent payment methods that can help you reach more customers, but we recommend turning on additional payment methods that are relevant for your business and customers. See [Payment method support](https://docs.stripe.com/payments/payment-methods/payment-method-support.md) for product and payment method support, and our [pricing page](https://stripe.com/pricing/local-payment-methods) for fees. ## Add an endpoint [Server-side] > #### Note > > To display the PaymentSheet before you create a PaymentIntent, see [Collect payment details before creating an Intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=payment). If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. This integration uses three Stripe API objects: 1. [PaymentIntent](https://docs.stripe.com/api/payment_intents.md): Stripe uses this to represent your intent to collect payment from a customer, tracking your charge attempts and payment state changes throughout the process. 1. (Optional) [Customer](https://docs.stripe.com/api/customers.md): To set up a payment method for future payments, you must attach it to a *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments). Create a Customer object when your customer creates an account with your business. If your customer is making a payment as a guest, you can create a Customer object before payment and associate it with your own internal representation of the customer’s account later. 1. (Optional) [CustomerSession](https://docs.stripe.com/api/customer_sessions.md): Information on the Customer object is sensitive, and can’t be retrieved directly from an app. A CustomerSession grants the SDK temporary scoped access to the Customer and provides additional configuration options. See a complete list of [configuration options](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components). > If you never save cards to a Customer and don’t allow returning Customers to reuse saved cards, you can omit the Customer and CustomerSession objects from your integration. For security reasons, your app can’t create these objects. Instead, add an endpoint on your server that: 1. Retrieves the Customer, or creates a new one. 1. Creates a [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) for the Customer. 1. Creates a PaymentIntent with the [amount](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-amount), [currency](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-currency), and [customer](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer). 1. Returns the Payment Intent’s *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)), the CustomerSession’s `client_secret`, the Customer’s [id](https://docs.stripe.com/api/customers/object.md#customer_object-id), and your [publishable key](https://dashboard.stripe.com/apikeys) to your app. The payment methods shown to customers during the checkout process are also included on the PaymentIntent. You can let Stripe pull payment methods from your Dashboard settings or you can list them manually. Regardless of the option you choose, know that the currency passed in the PaymentIntent filters the payment methods shown to the customer. For example, if you pass `eur` on the PaymentIntent and have OXXO enabled in the Dashboard, OXXO won’t be shown to the customer because OXXO doesn’t support `eur` payments. Unless your integration requires a code-based option for offering payment methods, Stripe recommends the automated option. This is because Stripe evaluates the currency, payment method restrictions, and other parameters to determine the list of supported payment methods. Payment methods that increase conversion and that are most relevant to the currency and customer’s location are prioritized. #### Manage payment methods from the Dashboard You can manage payment methods from the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow. The PaymentIntent is created using the payment methods you configured in the Dashboard. If you don’t want to use the Dashboard or if you want to specify payment methods manually, you can list them using the `payment_method_types` attribute. #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. -d "automatic_payment_methods[enabled]"=true \ ``` #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' post '/payment-sheet' do # Use an existing Customer ID if this is a returning customer customer = Stripe::Customer.create({stripe_account: '{{CONNECTED_ACCOUNT_ID}}'}) customerSession = Stripe::CustomerSession.create({ customer: customer['id'], components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled', }, }, }, }) paymentIntent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'eur', customer: customer['id'], # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods: { enabled: true, }, }) { paymentIntent: paymentIntent['client_secret'], customerSessionClientSecret: customerSession['client_secret'], customer: customer['id'], publishableKey: '<>' }.to_json end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' @app.route('/payment-sheet', methods=['POST']) def payment_sheet(): # Use an existing Customer ID if this is a returning customer customer = stripe.Customer.create(stripe_account="{{CONNECTED_ACCOUNT_ID}}") customerSession = stripe.CustomerSession.create( customer=customer['id'], components={"mobile_payment_element": { "enabled": True "features": { "payment_method_save": "enabled", "payment_method_redisplay": "enabled", "payment_method_remove": "enabled" } }, ) paymentIntent = stripe.PaymentIntent.create( amount=1099, currency='eur', customer=customer['id'], # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods={ 'enabled': True, }, ) return jsonify(paymentIntent=paymentIntent.client_secret, customerSessionClientSecret=customerSession.client_secret, customer=customer.id, publishableKey='<>') ``` #### PHP ```php >'); // Use an existing Customer ID if this is a returning customer. $customer = $stripe->customers->create(['stripe_account => '{{CONNECTED_ACCOUNT_ID}}']); $customerSession = $stripe->customerSessions->create([ 'customer' => $customer->id, 'components' => ['mobile_payment_element' => [ 'enabled' => true, 'features' => [ 'payment_method_save' => 'enabled', 'payment_method_redisplay' => 'enabled', 'payment_method_remove' => 'enabled', ], ], ], ]); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'eur', 'customer' => $customer->id, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. 'automatic_payment_methods' => [ 'enabled' => 'true', ], ]); echo json_encode( [ 'paymentIntent' => $paymentIntent->client_secret, 'customerSessionClientSecret' => $customerSession->client_secret, 'customer' => $customer->id, 'publishableKey' => '<>' ] ); http_response_code(200); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; post( "/payment-sheet", (request, response) -> { response.type("application/json"); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); Customer customer = Customer.create(customerParams); // Set the connected account ID String connectedAccountId = "{{CONNECTED_ACCOUNT_ID}}"; // Create RequestOptions with the Stripe-Account header RequestOptions requestOptions = RequestOptions.builder() .setStripeAccount(connectedAccountId) .build(); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); // Pass the requestOptions when creating the customer Customer customer = Customer.create(customerParams, requestOptions); }); CustomerSessionCreateParams params = CustomerSessionCreateParams.builder() .setCustomer(customer.getId()) .setComponents(CustomerSessionCreateParams.Components.builder().build()) .putExtraParam("components[mobile_payment_element][enabled]", true) .putExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled" ) .build(); CustomerSession customerSession = CustomerSession.create(params); PaymentIntentCreateParams paymentIntentParams = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("eur") .setCustomer(customer.getId()) // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder() .setEnabled(true) .build() ) .build(); PaymentIntent paymentIntent = PaymentIntent.create(paymentIntentParams); Map responseData = new HashMap(); responseData.put("paymentIntent", paymentIntent.getClientSecret()); responseData.put("customerSessionClientSecret", customerSession.getClientSecret()); responseData.put("customer", customer.getId()); responseData.put("publishableKey", "<>"); return gson.toJson(responseData); }); ``` #### Node.js ```javascript const stripe = require('stripe')('<>'); // This example sets up an endpoint using the Express framework. app.post('/payment-sheet', async (req, res) => { // Use an existing Customer ID if this is a returning customer. const customer = await stripe.customers.create(stripeAccount:'{{CONNECTED_ACCOUNT_ID}}'); const customerSession = await stripe.customerSessions.create({ customer: customer.id, components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled' } }, }, }); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'eur', customer: customer.id, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. automatic_payment_methods: { enabled: true, }, }); res.json({ paymentIntent: paymentIntent.client_secret, customerSessionClientSecret: customerSession.client_secret, customer: customer.id, publishableKey: '<>' }); }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func handlePaymentSheet(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) return } // Use an existing Customer ID if this is a returning customer. cparams := &stripe.CustomerParams{} stripe.SetStripeAccount(cparams.ExtraParams, "{{CONNECTED_ACCOUNT_ID}}") c, _ := customer.New(cparams) csParams := &stripe.CustomerSessionParams{ Customer: stripe.String(c.ID), Components: &stripe.CustomerSessionComponentsParams{}, } csParam.AddExtra("components[mobile_payment_element][enabled]", true) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_save]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_remove]", "enabled", ) cs, _ := customersession.New(csParams); piparams := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyEUR)), Customer: stripe.String(c.ID), // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods: &stripe.PaymentIntentAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, } pi, _ := paymentintent.New(piparams) writeJSON(w, struct { PaymentIntent string `json:"paymentIntent"` CustomerSessionClientKey string `json:"customerSessionClientSecret"` Customer string `json:"customer"` PublishableKey string `json:"publishableKey"` }{ PaymentIntent: pi.ClientSecret, CustomerSessionClientKey: cs.ClientSecret, Customer: c.ID, PublishableKey: "<>", }) } ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; [HttpPost("payment-sheet")] public ActionResult CreatePaymentSheet([FromBody] CreatePaymentSheetRequest req) { // Use an existing Customer ID if this is a returning customer. var customerOptions = new CustomerCreateOptions(); var customerService = new CustomerService(); var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTED_ACCOUNT_ID}}" }; var customer = customerService.Create(customerOptions, requestOptions); var customerSessionOptions = new CustomerSessionCreateOptions { Customer = customer.Id, Components = new CustomerSessionComponentsOptions() } customerSessionOptions.AddExtraParam("components[mobile_payment_element][enabled]", true); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled"); var service = new CustomerSessionService(); var customerSession = service.Create(options); var paymentIntentOptions = new PaymentIntentCreateOptions { Amount = 1099, Currency = "eur", Customer = customer.Id, // In the latest version of the API, specifying the `automatic_payment_methods` parameter // is optional because Stripe enables its functionality by default. AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, }; var paymentIntentService = new PaymentIntentService(); PaymentIntent paymentIntent = paymentIntentService.Create(paymentIntentOptions); return new PaymentSheetCreateResponse { PaymentIntent = paymentIntent.ClientSecret, CustomerSessionClientSecret = customerSession.ClientSecret Customer = customer.Id, PublishableKey = "<>", }; } ``` #### Listing payment methods manually #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ -d "payment_method_types[]"="bancontact" \ -d "payment_method_types[]"="card" \ -d "payment_method_types[]"="ideal" \ -d "payment_method_types[]"="klarna" \ -d "payment_method_types[]"="sepa_debit" \ ``` #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. post '/payment-sheet' do # Use an existing Customer ID if this is a returning customer customer = Stripe::Customer.create({stripe_account: '{{CONNECTED_ACCOUNT_ID}}'}) customerSession = Stripe::CustomerSession.create({ customer: customer['id'], components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled', }, }, }, }) paymentIntent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'eur', customer: customer['id'], payment_method_types: ['bancontact', 'card', 'ideal', 'klarna', 'sepa_debit'], }) { paymentIntent: paymentIntent['client_secret'], customerSessionClientSecret: customerSession['client_secret'], customer: customer['id'], publishableKey: '<>' }.to_json end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck. @app.route('/payment-sheet', methods=['POST']) def payment_sheet(): # Use an existing Customer ID if this is a returning customer customer = stripe.Customer.create(stripe_account="{{CONNECTED_ACCOUNT_ID}}") customerSession = stripe.CustomerSession.create( customer=customer['id'], components={"mobile_payment_element": { "enabled": True "features": { "payment_method_save": "enabled", "payment_method_redisplay": "enabled", "payment_method_remove": "enabled" } }, ) paymentIntent = stripe.PaymentIntent.create( amount=1099, currency='eur', customer=customer['id'], payment_method_types=["bancontact", "card", "ideal", "klarna", "sepa_debit"], ) return jsonify(paymentIntent=paymentIntent.client_secret, customerSessionClientSecret=customerSession.client_secret, customer=customer.id, publishableKey='<>') ``` #### PHP ```php >'); // Use an existing Customer ID if this is a returning customer. $customer = $stripe->customers->create(['stripe_account => '{{CONNECTED_ACCOUNT_ID}}']); $customerSession = $stripe->customerSessions->create([ 'customer' => $customer->id, 'components' => ['mobile_payment_element' => [ 'enabled' => true, 'features' => [ 'payment_method_save' => 'enabled', 'payment_method_redisplay' => 'enabled', 'payment_method_remove' => 'enabled', ], ], ], ]); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'eur', 'customer' => $customer->id, 'payment_method_types' => ['bancontact', 'card', 'ideal', 'klarna', 'sepa_debit'], ]); echo json_encode( [ 'paymentIntent' => $paymentIntent->client_secret, 'customerSessionClientSecret' => $customerSession->client_secret, 'customer' => $customer->id, 'publishableKey' => '<>' ] ); http_response_code(200); ``` #### Java ```java // This example sets up an endpoint using the Spark framework. post("/payment-sheet", (request, response) -> { response.type("application/json"); // Use an existing Customer ID if this is a returning customer. CustomerCreateParams customerParams = CustomerCreateParams.builder().build(); Customer customer = Customer.create(customerParams); CustomerSessionCreateParams params = CustomerSessionCreateParams.builder() .setCustomer(customer.getId()) .setComponents(CustomerSessionCreateParams.Components.builder().build()) .putExtraParam("components[mobile_payment_element][enabled]", true) .putExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled" ) .putExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled" ) .build(); CustomerSession customerSession = CustomerSession.create(params); List paymentMethodTypes = new ArrayList(); paymentMethodTypes.add("bancontact"); paymentMethodTypes.add("card"); paymentMethodTypes.add("ideal"); paymentMethodTypes.add("klarna"); paymentMethodTypes.add("sepa_debit"); PaymentIntentCreateParams paymentIntentParams = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("eur") .setCustomer(customer.getId()) .addAllPaymentMethodType(paymentMethodTypes) .build(); PaymentIntent paymentIntent = PaymentIntent.create(paymentIntentParams); Map responseData = new HashMap(); responseData.put("paymentIntent", paymentIntent.getClientSecret()); responseData.put("ephemeralKey", ephemeralKey.getSecret()); responseData.put("customer", customer.getId()); responseData.put("publishableKey", "<>"); return gson.toJson(responseData); }); ``` #### Node.js ```javascript // This example sets up an endpoint using the Express framework. app.post('/payment-sheet', async (req, res) => { // Use an existing Customer ID if this is a returning customer. const customer = await stripe.customers.create(stripeAccount:'{{CONNECTED_ACCOUNT_ID}}'); const customerSession = await stripe.customerSessions.create({ customer: customer.id, components: { mobile_payment_element: { enabled: true, features: { payment_method_save: 'enabled', payment_method_redisplay: 'enabled', payment_method_remove: 'enabled' } }, }, }); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'eur', customer: customer.id, payment_method_types: ['bancontact', 'card', 'ideal', 'klarna', 'sepa_debit'], }); res.json({ paymentIntent: paymentIntent.client_secret, customerSessionClientSecret: customerSession.client_secret, customer: customer.id, publishableKey: '<>' }); }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func handlePaymentSheet(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) return } // Use an existing Customer ID if this is a returning customer. cparams := &stripe.CustomerParams{} stripe.SetStripeAccount(cparams.ExtraParams, "{{CONNECTED_ACCOUNT_ID}}") c, _ := customer.New(cparams) csParams := &stripe.CustomerSessionParams{ Customer: stripe.String(c.ID), Components: &stripe.CustomerSessionComponentsParams{}, } csParam.AddExtra("components[mobile_payment_element][enabled]", true) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_save]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled", ) csParam.AddExtra( "components[mobile_payment_element][features][payment_method_remove]", "enabled", ) cs, _ := customersession.New(csParams); piparams := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyEUR)), Customer: stripe.String(c.ID), PaymentMethodTypes: []*string{ stripe.String("bancontact"), stripe.String("card"), stripe.String("ideal"), stripe.String("klarna"), stripe.String("sepa_debit"), }, } pi, _ := paymentintent.New(piparams) writeJSON(w, struct { PaymentIntent string `json:"paymentIntent"` CustomerSessionClientKey string `json:"customerSessionClientSecret"` Customer string `json:"customer"` PublishableKey string `json:"publishableKey"` }{ PaymentIntent: pi.ClientSecret, CustomerSessionClientKey: cs.ClientSecret, Customer: c.ID, PublishableKey: "<>", }) } ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; [HttpPost("payment-sheet")] public ActionResult CreatePaymentSheet([FromBody] CreatePaymentSheetRequest req) { // Use an existing Customer ID if this is a returning customer. var customerOptions = new CustomerCreateOptions(); var customerService = new CustomerService(); var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTED_ACCOUNT_ID}}" }; var customer = customerService.Create(customerOptions, requestOptions); var customerSessionOptions = new CustomerSessionCreateOptions { Customer = customer.Id, Components = new CustomerSessionComponentsOptions() } customerSessionOptions.AddExtraParam("components[mobile_payment_element][enabled]", true); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_save]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_redisplay]", "enabled"); customerSessionOptions.AddExtraParam( "components[mobile_payment_element][features][payment_method_remove]", "enabled"); var service = new CustomerSessionService(); var customerSession = service.Create(options); var paymentIntentOptions = new PaymentIntentCreateOptions { Amount = 1099, Currency = "eur", Customer = customer.Id, PaymentMethodTypes = new List { "bancontact", "card", "ideal", "klarna", "sepa_debit", }, }; var paymentIntentService = new PaymentIntentService(); PaymentIntent paymentIntent = paymentIntentService.Create(paymentIntentOptions); return new PaymentSheetCreateResponse { PaymentIntent = paymentIntent.ClientSecret, CustomerSessionClientSecret = customerSession.ClientSecret Customer = customer.Id, PublishableKey = "<>", }; } ``` > Each payment method needs to support the currency passed in the PaymentIntent and your business needs to be based in one of the countries each payment method supports. See the [Payment method integration options](https://docs.stripe.com/payments/payment-methods/integration-options.md) page for more details about what’s supported. ## Collect payment details [Client-side] Before displaying the mobile Payment Element, your checkout page should: - Show the products being purchased and the total amount - Collect any required shipping information - Include a checkout button to present Stripe’s UI In the checkout of your app, make a network request to the backend endpoint you created in the previous step and call `initPaymentSheet` from the `useStripe` hook. ```javascript export default function CheckoutScreen() { const { initPaymentSheet, presentPaymentSheet } = useStripe(); const [loading, setLoading] = useState(false); const fetchPaymentSheetParams = async () => { const response = await fetch(`${API_URL}/payment-sheet`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, }); const { paymentIntent, ephemeralKey, customer } = await response.json(); return { paymentIntent, ephemeralKey, customer, }; }; const initializePaymentSheet = async () => { const { paymentIntent, ephemeralKey, customer, } = await fetchPaymentSheetParams(); const { error } = await initPaymentSheet({ merchantDisplayName: "Example, Inc.", customerId: customer, customerEphemeralKeySecret: ephemeralKey, paymentIntentClientSecret: paymentIntent, // Set `allowsDelayedPaymentMethods` to true if your business can handle payment //methods that complete payment after a delay, like SEPA Debit and Sofort. allowsDelayedPaymentMethods: true, defaultBillingDetails: { name: 'Jane Doe', } }); if (!error) { setLoading(true); } }; const openPaymentSheet = async () => { // see below }; useEffect(() => { initializePaymentSheet(); }, []); return ( ``` ```ruby get '/checkout' do @intent = # ... Fetch or create the PaymentIntent erb :checkout end ``` #### Python ```html
``` ```python @app.route('/checkout') def checkout(): intent = # ... Fetch or create the PaymentIntent return render_template('checkout.html', client_secret=intent.client_secret) ``` #### PHP ```php ...
... ``` #### Java ```html
``` ```java import java.util.HashMap; import java.util.Map; import com.stripe.model.PaymentIntent; import spark.ModelAndView; import static spark.Spark.get; public class StripeJavaQuickStart { public static void main(String[] args) { get("/checkout", (request, response) -> { PaymentIntent intent = // ... Fetch or create the PaymentIntent Map map = new HashMap(); map.put("client_secret", intent.getClientSecret()); return new ModelAndView(map, "checkout.hbs"); }, new HandlebarsTemplateEngine()); } } ``` #### Node.js ```html
``` ```javascript const express = require('express'); const expressHandlebars = require('express-handlebars'); const app = express(); app.engine('.hbs', expressHandlebars({ extname: '.hbs' })); app.set('view engine', '.hbs'); app.set('views', './views'); app.get('/checkout', async (req, res) => { const intent = // ... Fetch or create the PaymentIntent res.render('checkout', { client_secret: intent.client_secret }); }); app.listen(3000, () => { console.log('Running on port 3000'); }); ``` #### Go ```html
``` ```go package main import ( "html/template" "net/http" stripe "github.com/stripe/stripe-go/v76.0.0" ) type CheckoutData struct { ClientSecret string } func main() { checkoutTmpl := template.Must(template.ParseFiles("views/checkout.html")) http.HandleFunc("/checkout", func(w http.ResponseWriter, r *http.Request) { intent := // ... Fetch or create the PaymentIntent data := CheckoutData{ ClientSecret: intent.ClientSecret, } checkoutTmpl.Execute(w, data) }) http.ListenAndServe(":3000", nil) } ``` #### .NET ```html
``` ```csharp using System; using Microsoft.AspNetCore.Mvc; using Stripe; namespace StripeExampleApi.Controllers { [Route("/[controller]")] public class CheckoutApiController : Controller { public IActionResult Index() { var intent = // ... Fetch or create the PaymentIntent ViewData["ClientSecret"] = intent.ClientSecret; return View(); } } } ``` ## Collect payment details [Client-side] Collect payment details on the client with the [Payment Element](https://docs.stripe.com/payments/payment-element.md). The Payment Element is a prebuilt UI component that simplifies collecting payment details for a variety of payment methods. The Payment Element contains an iframe that securely sends payment information to Stripe over an HTTPS connection. Avoid placing the Payment Element within another iframe because some payment methods require redirecting to another page for payment confirmation. If you do choose to use an iframe and want to accept Apple Pay or Google Pay, the iframe must have the [allow](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allowpaymentrequest) attribute set to equal `"payment *"`. The checkout page address must start with `https://` rather than `http://` for your integration to work. You can test your integration without using HTTPS, but remember to [enable it](https://docs.stripe.com/security/guide.md#tls) when you’re ready to accept live payments. #### HTML + JS ### Set up Stripe.js The Payment Element is automatically available as a feature of Stripe.js. Include the Stripe.js script on your checkout page by adding it to the `head` of your HTML file. Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Don’t include the script in a bundle or host a copy of it yourself. ```html Checkout ``` Create an instance of Stripe with the following JavaScript on your checkout page: ```javascript // Set your publishable key: remember to change this to your live publishable key in production // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe('<>'); ``` ### Add the Payment Element to your payment page The Payment Element needs a place to live on your payment page. Create an empty DOM node (container) with a unique ID in your payment form: ```html
``` When the previous form loads, create an instance of the Payment Element and mount it to the container DOM node. Pass the [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) from the previous step into `options` when you create the [Elements](https://docs.stripe.com/js/elements_object/create) instance: Handle the client secret carefully because it can complete the charge. Don’t log it, embed it in URLs, or expose it to anyone but the customer. ```javascript const options = { clientSecret: '{{CLIENT_SECRET}}', // Fully customizable with appearance API. appearance: {/*...*/}, }; // Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in a previous stepconst elements = stripe.elements(options); // Create and mount the Payment Element const paymentElementOptions = { layout: 'accordion'}; const paymentElement = elements.create('payment', paymentElementOptions); paymentElement.mount('#payment-element'); ``` #### React ### Set up Stripe.js Install [React Stripe.js](https://www.npmjs.com/package/@stripe/react-stripe-js) and the [Stripe.js loader](https://www.npmjs.com/package/@stripe/stripe-js) from the npm public registry: ```bash npm install --save @stripe/react-stripe-js @stripe/stripe-js ``` ### Add and configure the Elements provider to your payment page To use the Payment Element component, wrap your checkout page component in an [Elements provider](https://docs.stripe.com/sdks/stripejs-react.md#elements-provider). Call `loadStripe` with your publishable key, and pass the returned `Promise` to the `Elements` provider. Also pass the [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) from the previous step as `options` to the `Elements` provider. ```jsx import React from 'react'; import ReactDOM from 'react-dom'; import {Elements} from '@stripe/react-stripe-js'; import {loadStripe} from '@stripe/stripe-js'; import CheckoutForm from './CheckoutForm'; // Make sure to call `loadStripe` outside of a component’s render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe('<>'); function App() { const options = { // passing the client secret obtained in step 3 clientSecret: '{{CLIENT_SECRET}}', // Fully customizable with appearance API. appearance: {/*...*/}, }; return ( ); }; ReactDOM.render(, document.getElementById('root')); ``` ### Add the Payment Element component Use the `PaymentElement` component to build your form: ```jsx import React from 'react'; import {PaymentElement} from '@stripe/react-stripe-js'; const CheckoutForm = () => { return (
); }; export default CheckoutForm; ``` Stripe Elements is a collection of drop-in UI components. To further customize your form or collect different customer information, browse the [Elements docs](https://docs.stripe.com/payments/elements.md). The Payment Element renders a dynamic form that allows your customer to pick a payment method. For each payment method, the form automatically asks the customer to fill in all necessary payment details. ### Customize appearance Customize the Payment Element to match the design of your site by passing the [appearance object](https://docs.stripe.com/js/elements_object/create#stripe_elements-options-appearance) into `options` when creating the `Elements` provider. ### Collect addresses By default, the Payment Element only collects the necessary billing address details. Some behavior, such as [calculating tax](https://docs.stripe.com/api/tax/calculations/create.md) or entering shipping details, requires your customer’s full address. You can: - Use the [Address Element](https://docs.stripe.com/elements/address-element.md) to take advantage of autocomplete and localization features to collect your customer’s full address. This helps ensure the most accurate tax calculation. - Collect address details using your own custom form. ### Request Apple Pay merchant token If you’ve configured your integration to [accept Apple Pay payments](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=paymentintents#apple-pay-and-google-pay), we recommend configuring the Apple Pay interface to return a merchant token to enable merchant initiated transactions (MIT). [Request the relevant merchant token type](https://docs.stripe.com/apple-pay/merchant-tokens.md?pay-element=web-pe) in the Payment Element. ## Optional: Fetch updates from the server [Client-side] You might want to update attributes on the PaymentIntent after the Payment Element renders, such as the [amount](https://docs.stripe.com/api/payment_intents/update.md#update_payment_intent-amount) (for example, discount codes or shipping costs). You can [update the PaymentIntent](https://docs.stripe.com/api/payment_intents/update.md) on your server, then call [elements.fetchUpdates](https://docs.stripe.com/js/elements_object/fetch_updates) to see the new amount reflected in the Payment Element. This example shows you how to create the server endpoint that updates the amount on the PaymentIntent: #### Ruby ```ruby get '/update' do intent = Stripe::PaymentIntent.update( '{{PAYMENT_INTENT_ID}}', {amount: 1499}, ) {status: intent.status}.to_json end ``` #### Python ```python @app.route('/update') def secret(): intent = stripe.PaymentIntent.modify( "{{PAYMENT_INTENT_ID}}", amount=1499, ) return jsonify(status=intent.status) ``` #### PHP ```php paymentIntents->update( '{{PAYMENT_INTENT_ID}}', ['amount' => 1499] ); echo json_encode(array('status' => $intent->status)); ?> ``` #### Java ```java import java.util.HashMap; import java.util.Map; import com.stripe.model.PaymentIntent; import com.google.gson.Gson; import static spark.Spark.get; public class StripeJavaQuickStart { public static void main(String[] args) { Gson gson = new Gson(); get("/update", (request, response) -> { PaymentIntent paymentIntent = PaymentIntent.retrieve( "{{PAYMENT_INTENT_ID}}" ); Map params = new HashMap<>(); params.put("amount", 1499); PaymentIntent updatedPaymentIntent = paymentIntent.update(params); Map response = new HashMap(); response.put("status", updatedPaymentIntent.getStatus()); return map; }, gson::toJson); } } ``` #### Node.js ```javascript app.get('/update', async (req, res) => { const intent = await stripe.paymentIntents.update( '{{PAYMENT_INTENT_ID}}', {amount: 1499} ); res.json({status: intent.status}); }); ``` #### Go ```go package main import ( "encoding/json" "net/http" stripe "github.com/stripe/stripe-go/v76.0.0" ) type UpdateData struct { Status string `json:"status"` } func main() { http.HandleFunc("/update", func(w http.ResponseWriter, r *http.Request) { params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1499), } pi, _ := paymentintent.Update( "{{PAYMENT_INTENT_ID}}", params, ) data := UpdateData{ Status: pi.Status, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(data) }) http.ListenAndServe(":3000", nil) } ``` #### .NET ```csharp using System; using Microsoft.AspNetCore.Mvc; using Stripe; namespace StripeExampleApi.Controllers { [Route("update")] [ApiController] public class CheckoutApiController : Controller { [HttpPost] public ActionResult Post() { var options = new PaymentIntentUpdateOptions { Amount = 1499, }; var service = new PaymentIntentService(); var intent = service.Update( "{{PAYMENT_INTENT_ID}}", options); return Json(new {status = intent.Status}); } } } ``` This example demonstrates how to update the UI to reflect these changes on the client side: ```javascript (async () => { const response = await fetch('/update'); if (response.status === 'requires_payment_method') { const {error} = await elements.fetchUpdates(); } })(); ``` ## Submit the payment to Stripe [Client-side] Use [stripe.confirmPayment](https://docs.stripe.com/js/payment_intents/confirm_payment) to complete the payment using details from the Payment Element. Provide a [return_url](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-return_url) to this function to indicate where Stripe should redirect the user after they complete the payment. Your user may be first redirected to an intermediate site, like a bank authorization page, before being redirected to the `return_url`. Card payments immediately redirect to the `return_url` when a payment is successful. If you don’t want to redirect for card payments after payment completion, you can set [redirect](https://docs.stripe.com/js/payment_intents/confirm_payment#confirm_payment_intent-options-redirect) to `if_required`. This only redirects customers that check out with redirect-based payment methods. #### HTML + JS ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', async (event) => { event.preventDefault(); const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // This point will only be reached if there is an immediate error when // confirming the payment. Show error to your customer (for example, payment // details incomplete) const messageContainer = document.querySelector('#error-message'); messageContainer.textContent = error.message; } else { // Your customer will be redirected to your `return_url`. For some payment // methods like iDEAL, your customer will be redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } }); ``` #### React To call [stripe.confirmPayment](https://docs.stripe.com/js/payment_intents/confirm_payment) from your payment form component, use the [useStripe](https://docs.stripe.com/sdks/stripejs-react.md#usestripe-hook) and [useElements](https://docs.stripe.com/sdks/stripejs-react.md#useelements-hook) hooks. If you prefer traditional class components over hooks, you can instead use an [ElementsConsumer](https://docs.stripe.com/sdks/stripejs-react.md#elements-consumer). ```jsx import React, {useState} from 'react'; import {useStripe, useElements, PaymentElement} from '@stripe/react-stripe-js'; const CheckoutForm = () => { const stripe = useStripe(); const elements = useElements(); const [errorMessage, setErrorMessage] = useState(null); const handleSubmit = async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); if (!stripe || !elements) { // Stripe.js hasn't yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; } const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // This point will only be reached if there is an immediate error when // confirming the payment. Show error to your customer (for example, payment // details incomplete) setErrorMessage(error.message); } else { // Your customer will be redirected to your `return_url`. For some payment // methods like iDEAL, your customer will be redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } }; return (
{/* Show error message to your customers */} {errorMessage &&
{errorMessage}
} ) }; export default CheckoutForm; ``` Make sure the `return_url` corresponds to a page on your website that provides the status of the payment. When Stripe redirects the customer to the `return_url`, we provide the following URL query parameters: | Parameter | Description | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | `payment_intent` | The unique identifier for the `PaymentIntent`. | | `payment_intent_client_secret` | The [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) of the `PaymentIntent` object. | > If you have tooling that tracks the customer’s browser session, you might need to add the `stripe.com` domain to the referrer exclude list. Redirects cause some tools to create new sessions, which prevents you from tracking the complete session. Use one of the query parameters to retrieve the PaymentIntent. Inspect the [status of the PaymentIntent](https://docs.stripe.com/payments/paymentintents/lifecycle.md) to decide what to show your customers. You can also append your own query parameters when providing the `return_url`, which persist through the redirect process. #### HTML + JS ```javascript // Initialize Stripe.js using your publishable key const stripe = Stripe('<>'); // Retrieve the "payment_intent_client_secret" query parameter appended to // your return_url by Stripe.js const clientSecret = new URLSearchParams(window.location.search).get( 'payment_intent_client_secret' ); // Retrieve the PaymentIntent stripe.retrievePaymentIntent(clientSecret).then(({paymentIntent}) => { const message = document.querySelector('#message') // Inspect the PaymentIntent `status` to indicate the status of the payment // to your customer. // // Some payment methods will [immediately succeed or fail][0] upon // confirmation, while others will first enter a `processing` state. // // [0]: https://stripe.com/docs/payments/payment-methods#payment-notification switch (paymentIntent.status) { case 'succeeded': message.innerText = 'Success! Payment received.'; break; case 'processing': message.innerText = "Payment processing. We'll update you when payment is received."; break; case 'requires_payment_method': message.innerText = 'Payment failed. Please try another payment method.'; // Redirect your user back to your payment page to attempt collecting // payment again break; default: message.innerText = 'Something went wrong.'; break; } }); ``` #### React ```jsx import React, {useState, useEffect} from 'react'; import {useStripe} from '@stripe/react-stripe-js'; const PaymentStatus = () => { const stripe = useStripe(); const [message, setMessage] = useState(null); useEffect(() => { if (!stripe) { return; } // Retrieve the "payment_intent_client_secret" query parameter appended to // your return_url by Stripe.js const clientSecret = new URLSearchParams(window.location.search).get( 'payment_intent_client_secret' ); // Retrieve the PaymentIntent stripe .retrievePaymentIntent(clientSecret) .then(({paymentIntent}) => { // Inspect the PaymentIntent `status` to indicate the status of the payment // to your customer. // // Some payment methods will [immediately succeed or fail][0] upon // confirmation, while others will first enter a `processing` state. // // [0]: https://stripe.com/docs/payments/payment-methods#payment-notification switch (paymentIntent.status) { case 'succeeded': setMessage('Success! Payment received.'); break; case 'processing': setMessage("Payment processing. We'll update you when payment is received."); break; case 'requires_payment_method': // Redirect your user back to your payment page to attempt collecting // payment again setMessage('Payment failed. Please try another payment method.'); break; default: setMessage('Something went wrong.'); break; } }); }, [stripe]); return message; }; export default PaymentStatus; ``` ## Redirect and authenticate transactions Customers can authenticate crypto transactions in the browser. After calling `confirmPayment`, we redirect customers to a page hosted by *crypto.stripe.com* to confirm their payment. When confirmation is complete, we redirect customers to the `return_url`. ## Test your integration Test your crypto payment integration by opening the payment redirect page using your test API keys. You can test a successful payment flow at no cost using [testnet assets](https://docs.stripe.com/payments/accept-stablecoin-payments.md#testnet-assets). 1. In a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes), create a new transaction using your chosen integration method, and open its redirect URL. 1. Connect your preferred wallet and payment network. 1. Complete the payment, and validate that you’re redirected to the expected URL. ### Test payments with testnet assets Most cryptocurrencies offer testnet assets, or tokens that have no monetary value, that you can use to test blockchain transactions. Stripe recommends the MetaMask wallet, Polygon Amoy testnet, and Circle faucet for testing, but you can use your own preferred services. #### Install a wallet 1. [Download the MetaMask extension](https://metamask.io/download) for your web browser. 1. [Create a new wallet](https://support.metamask.io/start/creating-a-new-wallet/) or [import an existing one](https://support.metamask.io/start/use-an-existing-wallet/). #### Enable a testnet 1. In your MetaMask wallet, select **Networks** from the main menu. 1. Click **Add custom network**. 1. Enter the following details: - **Network name**: `Polygon Amoy` - **Default RPC URL**: `https://rpc-amoy.polygon.technology/` - **Chain ID**: `80002` - **Currency symbol**: `POL` - **Block explorer URL**: `https://amoy.polygonscan.com/` 1. Click **Save**. #### Import a token 1. In your MetaMask wallet, under **Tokens**, select **Polygon Amoy** from the network dropdown. 1. Click the overflow menu (⋯), and select **Import tokens**. 1. Click **Select a network** > **Polygon Amoy**. 1. Under **Token contract address**, paste the Polygon Amoy testnet contract address: ``` 0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582 ``` The **Token symbol** field automatically updates with `USDC` and the **Decimals** field with `6`. 1. Click **Next**. 1. Verify that you’re importing the `USDC` token, and then click **Import**. Your MetaMask wallet now shows **Polygon Amoy** and **USDC** in the tokens list. #### Get testnet assets 1. Open [faucet.circle.com](https://faucet.circle.com/) 1. Click **USDC**. 1. Under **Network**, select **Polygon PoS Amoy**. 1. Under **Send to**, paste your wallet address. 1. Click **Send 10 USDC**. In addition to USDC for making payments, you need POL to pay transaction costs: 1. Open [faucet.polygon.technology](https://faucet.polygon.technology/). 1. Under **Select Chain & Token**, select **Polygon Amoy** and **POL**. 1. Under **Verify your identity**, click the third-party platform you want to authenticate with, and complete the login process. 1. Under **Enter Wallet Address**, paste your wallet address. 1. Click **Claim**. Testnet transactions can take a few minutes to complete. Check your wallet to confirm that the USDC and POL has transferred. ### More testnet faucets Check these faucet services for more testing token options: - [Paxos USDP](https://faucet.paxos.com/) - [Devnet SOL](https://faucet.solana.com/) - [Sepolia ETH](https://faucets.chain.link/sepolia) - [Amoy POL](https://faucet.polygon.technology/) # Direct API > This is a Direct API for when payment-ui is direct-api. View the full page at https://docs.stripe.com/payments/accept-stablecoin-payments?payment-ui=direct-api. Integrate Pay with Crypto directly through the *Payment Intents API* (The Payment Intents API tracks the lifecycle of a customer checkout flow and triggers additional authentication steps when required by regulatory mandates, custom Radar fraud rules, or redirect-based payment methods). ## Set up Stripe [Server-side] First, [create a Stripe account](https://dashboard.stripe.com/register) or [sign in](https://dashboard.stripe.com/login). Use our official libraries to access the Stripe API from your application: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` #### Python ```bash # Install through pip pip3 install --upgrade stripe ``` ```bash # Or find the Stripe package on http://pypi.python.org/pypi/stripe/ ``` ```python # Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=5.0.0 ``` #### PHP ```bash # Install the PHP library with Composer composer require stripe/stripe-php ``` ```bash # Or download the source directly: https://github.com/stripe/stripe-php/releases ``` #### Java ```java /* For Gradle, add the following dependency to your build.gradle and replace with the version number you want to use from: - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:31.3.0" ``` ```xml com.stripe stripe-java 31.3.0 ``` ```bash # For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson ``` #### Node.js ```bash # Install with npm npm install stripe --save ``` #### Go ```bash # Make sure your project is using Go Modules go mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v84 ``` ```go // Then import the package import ( "github.com/stripe/stripe-go/v84" ) ``` #### .NET ```bash # Install with dotnet dotnet add package Stripe.net dotnet restore ``` ```bash # Or install with NuGet Install-Package Stripe.net ``` ## Create a PaymentIntent and retrieve the client secret [Server-side] The [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) object represents your intent to collect payment from your customer and tracks the lifecycle of the payment process. Create a PaymentIntent on your server and specify the amount to collect and a supported currency. If you have an existing PaymentIntents integration, add `crypto` to the list of [payment_method_types](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-payment_method_types). ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "payment_method_types[]"=crypto ``` ```cli stripe payment_intents create \ --amount=1099 \ --currency=usd \ -d "payment_method_types[0]"=crypto ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', payment_method_types: ['crypto'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 1099, "currency": "usd", "payment_method_types": ["crypto"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'usd', 'payment_method_types' => ['crypto'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") .addPaymentMethodType("crypto") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', payment_method_types: ['crypto'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(1099), Currency: stripe.String(stripe.CurrencyUSD), PaymentMethodTypes: []*string{stripe.String("crypto")}, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", PaymentMethodTypes = new List { "crypto" }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` ### Retrieve the client secret The PaymentIntent includes a *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)) that the client side uses to securely complete the payment process. You can use different approaches to pass the client secret to the client side. #### Single-page application Retrieve the client secret from an endpoint on your server, using the browser’s `fetch` function. This approach is best if your client side is a single-page application, particularly one built with a modern frontend framework like React. Create the server endpoint that serves the client secret: #### Ruby ```ruby get '/secret' do intent = # ... Create or retrieve the PaymentIntent {client_secret: intent.client_secret}.to_json end ``` #### Python ```python from flask import Flask, jsonify app = Flask(__name__) @app.route('/secret') def secret(): intent = # ... Create or retrieve the PaymentIntent return jsonify(client_secret=intent.client_secret) ``` #### PHP ```php $intent->client_secret)); ?> ``` #### Java ```java import java.util.HashMap; import java.util.Map; import com.stripe.model.PaymentIntent; import com.google.gson.Gson; import static spark.Spark.get; public class StripeJavaQuickStart { public static void main(String[] args) { Gson gson = new Gson(); get("/secret", (request, response) -> { PaymentIntent intent = // ... Fetch or create the PaymentIntent Map map = new HashMap(); map.put("client_secret", intent.getClientSecret()); return map; }, gson::toJson); } } ``` #### Node.js ```javascript const express = require('express'); const app = express(); app.get('/secret', async (req, res) => { const intent = // ... Fetch or create the PaymentIntent res.json({client_secret: intent.client_secret}); }); app.listen(3000, () => { console.log('Running on port 3000'); }); ``` #### Go ```go package main import ( "encoding/json" "net/http" stripe "github.com/stripe/stripe-go/v76.0.0" ) type CheckoutData struct { ClientSecret string `json:"client_secret"` } func main() { http.HandleFunc("/secret", func(w http.ResponseWriter, r *http.Request) { intent := // ... Fetch or create the PaymentIntent data := CheckoutData{ ClientSecret: intent.ClientSecret, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(data) }) http.ListenAndServe(":3000", nil) } ``` #### .NET ```csharp using System; using Microsoft.AspNetCore.Mvc; using Stripe; namespace StripeExampleApi.Controllers { [Route("secret")] [ApiController] public class CheckoutApiController : Controller { [HttpGet] public ActionResult Get() { var intent = // ... Fetch or create the PaymentIntent return Json(new {client_secret = intent.ClientSecret}); } } } ``` And then fetch the client secret with JavaScript on the client side: ```javascript (async () => { const response = await fetch('/secret'); const {client_secret: clientSecret} = await response.json(); // Render the form using the clientSecret })(); ``` #### Server-side rendering Pass the client secret to the client from your server. This approach works best if your application generates static content on the server before sending it to the browser. Add the [client_secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) in your checkout form. In your server-side code, retrieve the client secret from the PaymentIntent: #### Ruby ```erb
``` ```ruby get '/checkout' do @intent = # ... Fetch or create the PaymentIntent erb :checkout end ``` #### Python ```html
``` ```python @app.route('/checkout') def checkout(): intent = # ... Fetch or create the PaymentIntent return render_template('checkout.html', client_secret=intent.client_secret) ``` #### PHP ```php ...
... ``` #### Java ```html
``` ```java import java.util.HashMap; import java.util.Map; import com.stripe.model.PaymentIntent; import spark.ModelAndView; import static spark.Spark.get; public class StripeJavaQuickStart { public static void main(String[] args) { get("/checkout", (request, response) -> { PaymentIntent intent = // ... Fetch or create the PaymentIntent Map map = new HashMap(); map.put("client_secret", intent.getClientSecret()); return new ModelAndView(map, "checkout.hbs"); }, new HandlebarsTemplateEngine()); } } ``` #### Node.js ```html
``` ```javascript const express = require('express'); const expressHandlebars = require('express-handlebars'); const app = express(); app.engine('.hbs', expressHandlebars({ extname: '.hbs' })); app.set('view engine', '.hbs'); app.set('views', './views'); app.get('/checkout', async (req, res) => { const intent = // ... Fetch or create the PaymentIntent res.render('checkout', { client_secret: intent.client_secret }); }); app.listen(3000, () => { console.log('Running on port 3000'); }); ``` #### Go ```html
``` ```go package main import ( "html/template" "net/http" stripe "github.com/stripe/stripe-go/v76.0.0" ) type CheckoutData struct { ClientSecret string } func main() { checkoutTmpl := template.Must(template.ParseFiles("views/checkout.html")) http.HandleFunc("/checkout", func(w http.ResponseWriter, r *http.Request) { intent := // ... Fetch or create the PaymentIntent data := CheckoutData{ ClientSecret: intent.ClientSecret, } checkoutTmpl.Execute(w, data) }) http.ListenAndServe(":3000", nil) } ``` #### .NET ```html
``` ```csharp using System; using Microsoft.AspNetCore.Mvc; using Stripe; namespace StripeExampleApi.Controllers { [Route("/[controller]")] public class CheckoutApiController : Controller { public IActionResult Index() { var intent = // ... Fetch or create the PaymentIntent ViewData["ClientSecret"] = intent.ClientSecret; return View(); } } } ``` ## Redirect to the stablecoin payments page Use [Stripe.js](https://docs.stripe.com/js.md) to submit the payment to Stripe when a customer chooses **Crypto** as a payment method. Stripe.js is the foundational JavaScript library for building payment flows. It automatically handles complexities like the redirect described below, and lets you extend your integration to other payment methods. Include the Stripe.js script on your checkout page by adding it to the `` of your HTML file. ```html Checkout ``` Create an instance of Stripe.js with the following JavaScript on your checkout page: ```javascript // Set your publishable key. Remember to change this to your live publishable key in production! // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe('<>'); ``` Use the PaymentIntent [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) and call `stripe.confirmPayment` to handle the Pay with Crypto redirect. Add a `return_url` to determine where Stripe redirects the customer after they complete the payment: ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', async function(event) { event.preventDefault(); // Set the clientSecret of the PaymentIntent const { error } = await stripe.confirmPayment({ clientSecret: clientSecret, confirmParams: { payment_method_data: { type: 'crypto', }, // Return URL where the customer should be redirected after the authorization return_url: `${window.location.href}`, }, }); if (error) { // Inform the customer that there was an error. const errorElement = document.getElementById('error-message'); errorElement.textContent = result.error.message; } }); ``` The `return_url` corresponds to a page on your website that displays the result of the payment. You can determine what to display by [verifying the status](https://docs.stripe.com/payments/payment-intents/verifying-status.md#checking-status) of the PaymentIntent. To verify the status, the Stripe redirect to the `return_url` includes the following URL query parameters. You can also append your own query parameters to the `return_url`. They persist throughout the redirect process. | `payment_intent` | The unique identifier for the `PaymentIntent`. | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | `payment_intent_client_secret` | The [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) of the `PaymentIntent` object. | ## Optional: Handle post-payment events Stripe sends a [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) event when the payment completes. Use the Dashboard, a custom [webhook](https://docs.stripe.com/webhooks.md), or a partner solution to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow. Listen for these events rather than waiting on a callback from the client. On the client, the customer might close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events can also help you accept more payment methods in the future. To see the differences between all supported payment methods, see our [payment methods](https://stripe.com/payments/payment-methods-guide) guide. ### Receive events and run business actions There are a few options for receiving and running business actions: - **Manually:** Use the [Stripe Dashboard](https://dashboard.stripe.com/test/payments) to view all your Stripe payments, send email receipts, handle payouts, or retry failed payments. - **Custom code:** [Build a webhook](https://docs.stripe.com/webhooks/handling-payment-events.md#build-your-own-webhook) handler to listen for events and build custom asynchronous payment flows. Test and debug your webhook integration locally with the Stripe CLI. - **Prebuilt apps:** Handle common business events, like [automation](https://stripe.partners/?f_category=automation) or [marketing and sales](https://stripe.partners/?f_category=marketing-and-sales), by integrating a partner application. ### Supported currencies You can create crypto payments in the currencies that map to your country. The default local currency for crypto is USD, with customers also seeing their purchase amount in this currency. ## Test your integration Test your crypto payment integration by opening the payment redirect page using your test API keys. You can test a successful payment flow at no cost using [testnet assets](https://docs.stripe.com/payments/accept-stablecoin-payments.md#testnet-assets). 1. In a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes), create a new transaction using your chosen integration method, and open its redirect URL. 1. Connect your preferred wallet and payment network. 1. Complete the payment, and validate that you’re redirected to the expected URL. ### Test payments with testnet assets Most cryptocurrencies offer testnet assets, or tokens that have no monetary value, that you can use to test blockchain transactions. Stripe recommends the MetaMask wallet, Polygon Amoy testnet, and Circle faucet for testing, but you can use your own preferred services. #### Install a wallet 1. [Download the MetaMask extension](https://metamask.io/download) for your web browser. 1. [Create a new wallet](https://support.metamask.io/start/creating-a-new-wallet/) or [import an existing one](https://support.metamask.io/start/use-an-existing-wallet/). #### Enable a testnet 1. In your MetaMask wallet, select **Networks** from the main menu. 1. Click **Add custom network**. 1. Enter the following details: - **Network name**: `Polygon Amoy` - **Default RPC URL**: `https://rpc-amoy.polygon.technology/` - **Chain ID**: `80002` - **Currency symbol**: `POL` - **Block explorer URL**: `https://amoy.polygonscan.com/` 1. Click **Save**. #### Import a token 1. In your MetaMask wallet, under **Tokens**, select **Polygon Amoy** from the network dropdown. 1. Click the overflow menu (⋯), and select **Import tokens**. 1. Click **Select a network** > **Polygon Amoy**. 1. Under **Token contract address**, paste the Polygon Amoy testnet contract address: ``` 0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582 ``` The **Token symbol** field automatically updates with `USDC` and the **Decimals** field with `6`. 1. Click **Next**. 1. Verify that you’re importing the `USDC` token, and then click **Import**. Your MetaMask wallet now shows **Polygon Amoy** and **USDC** in the tokens list. #### Get testnet assets 1. Open [faucet.circle.com](https://faucet.circle.com/) 1. Click **USDC**. 1. Under **Network**, select **Polygon PoS Amoy**. 1. Under **Send to**, paste your wallet address. 1. Click **Send 10 USDC**. In addition to USDC for making payments, you need POL to pay transaction costs: 1. Open [faucet.polygon.technology](https://faucet.polygon.technology/). 1. Under **Select Chain & Token**, select **Polygon Amoy** and **POL**. 1. Under **Verify your identity**, click the third-party platform you want to authenticate with, and complete the login process. 1. Under **Enter Wallet Address**, paste your wallet address. 1. Click **Claim**. Testnet transactions can take a few minutes to complete. Check your wallet to confirm that the USDC and POL has transferred. ### More testnet faucets Check these faucet services for more testing token options: - [Paxos USDP](https://faucet.paxos.com/) - [Devnet SOL](https://faucet.solana.com/) - [Sepolia ETH](https://faucets.chain.link/sepolia) - [Amoy POL](https://faucet.polygon.technology/) # iOS > This is a iOS for when payment-ui is mobile and platform is ios. View the full page at https://docs.stripe.com/payments/accept-stablecoin-payments?payment-ui=mobile&platform=ios. We recommend you use the [Mobile Payment Element](https://docs.stripe.com/payments/accept-a-payment.md?=ios), an embeddable payment form, to add Pay with Crypto and other payment methods to your integration with the least amount of effort. Pay with Crypto is a [single-use](https://docs.stripe.com/payments/payment-methods.md#usage) payment method where customers are required to [authenticate](https://docs.stripe.com/payments/payment-methods.md#customer-actions) their payment. Customers are redirected from your app, authorize the payment with Stripe Crypto, then return to your app. You’re [immediately notified](https://docs.stripe.com/payments/payment-methods.md#payment-notification) when the payment succeeds or fails. ## Set up Stripe [Server-side] [Client-side] First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register). ### Server-side This integration requires endpoints on your server that talk to the Stripe API. Use the official libraries for access to the Stripe API from your server: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` #### Python ```bash # Install through pip pip3 install --upgrade stripe ``` ```bash # Or find the Stripe package on http://pypi.python.org/pypi/stripe/ ``` ```python # Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=5.0.0 ``` #### PHP ```bash # Install the PHP library with Composer composer require stripe/stripe-php ``` ```bash # Or download the source directly: https://github.com/stripe/stripe-php/releases ``` #### Java ```java /* For Gradle, add the following dependency to your build.gradle and replace with the version number you want to use from: - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:31.3.0" ``` ```xml com.stripe stripe-java 31.3.0 ``` ```bash # For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson ``` #### Node.js ```bash # Install with npm npm install stripe --save ``` #### Go ```bash # Make sure your project is using Go Modules go mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v84 ``` ```go // Then import the package import ( "github.com/stripe/stripe-go/v84" ) ``` #### .NET ```bash # Install with dotnet dotnet add package Stripe.net dotnet restore ``` ```bash # Or install with NuGet Install-Package Stripe.net ``` ### Client-side The [Stripe iOS SDK](https://github.com/stripe/stripe-ios) is open source, [fully documented](https://stripe.dev/stripe-ios/index.html), and compatible with apps supporting iOS 13 or above. #### Swift Package Manager To install the SDK, follow these steps: 1. In Xcode, select **File** > **Add Package Dependencies…** and enter `https://github.com/stripe/stripe-ios-spm` as the repository URL. 1. Select the latest version number from our [releases page](https://github.com/stripe/stripe-ios/releases). 1. Add the **StripePaymentsUI** product to the [target of your app](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app). #### CocoaPods 1. If you haven’t already, install the latest version of [CocoaPods](https://guides.cocoapods.org/using/getting-started.html). 1. If you don’t have an existing [Podfile](https://guides.cocoapods.org/syntax/podfile.html), run the following command to create one: ```bash pod init ``` 1. Add this line to your `Podfile`: ```podfile pod 'StripePaymentsUI' ``` 1. Run the following command: ```bash pod install ``` 1. Don’t forget to use the `.xcworkspace` file to open your project in Xcode, instead of the `.xcodeproj` file, from here on out. 1. In the future, to update to the latest version of the SDK, run: ```bash pod update StripePaymentsUI ``` #### Carthage 1. If you haven’t already, install the latest version of [Carthage](https://github.com/Carthage/Carthage#installing-carthage). 1. Add this line to your `Cartfile`: ```cartfile github "stripe/stripe-ios" ``` 1. Follow the [Carthage installation instructions](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos). Make sure to embed all of the required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripePaymentsUI/README.md#manual-linking). 1. In the future, to update to the latest version of the SDK, run the following command: ```bash carthage update stripe-ios --platform ios ``` #### Manual Framework 1. Head to our [GitHub releases page](https://github.com/stripe/stripe-ios/releases/latest) and download and unzip **Stripe.xcframework.zip**. 1. Drag **StripePaymentsUI.xcframework** to the **Embedded Binaries** section of the **General** settings in your Xcode project. Make sure to select **Copy items if needed**. 1. Repeat step 2 for all required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripePaymentsUI/README.md#manual-linking). 1. In the future, to update to the latest version of our SDK, repeat steps 1–3. > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-ios/releases) page on GitHub. To receive notifications when a new release is published, [watch releases](https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository#watching-releases-for-a-repository) for the repository. Configure the SDK with your Stripe [publishable key](https://dashboard.stripe.com/test/apikeys) on app start. This enables your app to make requests to the Stripe API. #### Swift ```swift import UIKitimportStripePaymentsUI @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {StripeAPI.defaultPublishableKey = "<>" // do any other necessary launch configuration return true } } ``` #### Objective-C ```objc #import "AppDelegate.h"@import StripeCore; @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {[StripeAPI setDefaultPublishableKey:@"<>"]; // do any other necessary launch configuration return YES; } @end ``` > Use your [test keys](https://docs.stripe.com/keys.md#obtain-api-keys) while you test and develop, and your [live mode](https://docs.stripe.com/keys.md#test-live-modes) keys when you publish your app. ## Create a PaymentIntent [Server-side] [Client-side] ### Server-side A [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md) is an object that represents your intent to collect payment from a customer and tracks the lifecycle of the payment process through each stage. #### Manage payment methods in the Dashboard You can manage payment methods in the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow. Create a PaymentIntent on your server with an amount and currency. Before creating the PaymentIntent, make sure to turn **Pay with Crypto** on in your [Payment methods settings](https://dashboard.stripe.com/settings/payment_methods). > Always decide how much to charge on the server-side, a trusted environment, as opposed to the client. This prevents customers from being able to choose their own prices. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "automatic_payment_methods[enabled]"=true ``` ```cli stripe payment_intents create \ --amount=1099 \ --currency=usd \ -d "automatic_payment_methods[enabled]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 1099, "currency": "usd", "automatic_payment_methods": {"enabled": True}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'usd', 'automatic_payment_methods' => ['enabled' => true], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder().setEnabled(true).build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', automatic_payment_methods: { enabled: true, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(1099), Currency: stripe.String(stripe.CurrencyUSD), AutomaticPaymentMethods: &stripe.PaymentIntentCreateAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` #### List payment methods manually If you don’t want to use the Dashboard or you want to manually specify payment methods, you can list them using the `payment_method_types` attribute. Create a PaymentIntent on your server with an amount, currency, and a list of payment methods. > Always decide how much to charge on the server-side, a trusted environment, as opposed to the client. This prevents customers from being able to choose their own prices. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "payment_method_types[]"=crypto ``` ```cli stripe payment_intents create \ --amount=1099 \ --currency=usd \ -d "payment_method_types[0]"=crypto ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', payment_method_types: ['crypto'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 1099, "currency": "usd", "payment_method_types": ["crypto"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'usd', 'payment_method_types' => ['crypto'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") .addPaymentMethodType("crypto") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', payment_method_types: ['crypto'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(1099), Currency: stripe.String(stripe.CurrencyUSD), PaymentMethodTypes: []*string{stripe.String("crypto")}, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", PaymentMethodTypes = new List { "crypto" }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` ### Client-side On the client, request a PaymentIntent from your server and store its *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)). #### Swift ```swift class CheckoutViewController: UIViewController { var paymentIntentClientSecret: String? // ...continued from previous step override func viewDidLoad() { // ...continued from previous step startCheckout() } func startCheckout() { // Request a PaymentIntent from your server and store its client secret // Click View full sample to see a complete implementation } } ``` #### Objective C ```objc @interface CheckoutViewController () // ...continued from previous step @property (strong) NSString *paymentIntentClientSecret; @end @implementation CheckoutViewController - (void)viewDidLoad { [super viewDidLoad]; // ...continued from previous step [self startCheckout]; } - (void)startCheckout { // Request a PaymentIntent from your server and store its client secret // Click View full sample to see a complete implementation } @end ``` ## Submit the payment to Stripe [Client-side] When a customer taps to pay with Pay with Crypto, confirm the `PaymentIntent` to complete the payment. Configure an `STPPaymentIntentParams` object with the `PaymentIntent` [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret). The client secret is different from your API keys that authenticate Stripe API requests. Handle it carefully because it can complete the charge. Don’t log it, embed it in URLs, or expose it to anyone but the customer. ### Set up a return URL The iOS SDK presents a webview in your app to complete the Pay with Crypto payment. When authentication is finished, the webview can automatically dismiss itself instead of having your customer close it. To enable this behavior, configure a custom URL scheme or universal link and set up your app delegate to forward the URL to the SDK. #### Swift ```swift // This method handles opening custom URL schemes (for example, "your-app://stripe-redirect") func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { let stripeHandled = StripeAPI.handleURLCallback(with: url) if (stripeHandled) { return true } else { // This was not a Stripe url – handle the URL normally as you would } return false } // This method handles opening universal link URLs (for example, "https://example.com/stripe_ios_callback") func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { if userActivity.activityType == NSUserActivityTypeBrowsingWeb { if let url = userActivity.webpageURL { let stripeHandled = StripeAPI.handleURLCallback(with: url) if (stripeHandled) { return true } else { // This was not a Stripe url – handle the URL normally as you would } } } return false } ``` #### Objective C ```objc // This method handles opening custom URL schemes (for example, "your-app://stripe-redirect") - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { BOOL stripeHandled = [StripeAPI handleStripeURLCallbackWithURL:url]; if (stripeHandled) { return YES; } else { // This was not a Stripe url – handle the URL normally as you would } return NO; } // This method handles opening universal link URLs (for example, "https://example.com/stripe_ios_callback") - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray> * _Nullable))restorationHandler { if (userActivity.activityType == NSUserActivityTypeBrowsingWeb) { if (userActivity.webpageURL) { BOOL stripeHandled = [StripeAPI handleStripeURLCallbackWithURL:userActivity.webpageURL]; if (stripeHandled) { return YES; } else { // This was not a Stripe url – handle the URL normally as you would } return NO; } } return NO; } ``` Pass the URL as the `return_url` when you confirm the PaymentIntent. After webview-based authentication finishes, Stripe redirects the user to the `return_url`. ### Confirm the Pay with Crypto payment Complete the payment by calling `STPPaymentHandler.confirmPayment`. This presents a webview where the customer can complete the payment with Pay with Crypto. After completion, Stripe calls the completion block with the result of the payment. #### Swift ```swift let paymentIntentParams = STPPaymentIntentParams(clientSecret: paymentIntentClientSecret) // Pay with Crypto does not require additional parameters so we only need to pass the initialized // STPPaymentMethodCryptoParams instance to STPPaymentMethodParams let crypto = STPPaymentMethodCryptoParams() let paymentMethodParams = STPPaymentMethodParams(crypto: crypto, billingDetails: nil, metadata: nil) paymentIntentParams.paymentMethodParams = paymentMethodParams paymentIntentParams.returnURL = "payments-example://stripe-redirect" STPPaymentHandler.shared().confirmPayment(paymentIntentParams, with: self) { (handlerStatus, paymentIntent, error) in switch handlerStatus { case .succeeded: // Payment succeeded // ... case .canceled: // Payment canceled // ... case .failed: // Payment failed // ... @unknown default: fatalError() } } ``` #### Objective C ```objc STPPaymentIntentParams *paymentIntentParams = [[STPPaymentIntentParams alloc] initWithClientSecret:clientSecret]; STPPaymentMethodCryptoParams *crypto = [[STPPaymentMethodCryptoParams alloc] init]; // Pay with Crypto does not require additional parameters so we only need to pass the initialized // STPPaymentMethodCryptoParams instance to STPPaymentMethodParams paymentIntentParams.paymentMethodParams = [STPPaymentMethodParams paramsWithCrypto:crypto billingDetails:nil metadata:nil]; paymentIntentParams.returnURL = @"payments-example://stripe-redirect"; [[STPPaymentHandler sharedHandler] confirmPayment:paymentIntentParams withAuthenticationContext:self.delegate completion:^(STPPaymentHandlerActionStatus handlerStatus, STPPaymentIntent * handledIntent, NSError * _Nullable handlerError) { switch (handlerStatus) {     case STPPaymentHandlerActionStatusFailed:         // Payment failed             // ...             break;         case STPPaymentHandlerActionStatusCanceled:         // Payment canceled             // ...         break;         case STPPaymentHandlerActionStatusSucceeded:           // Payment succeeded             // ...             break; } }]; ``` ## Optional: Handle post-payment events Stripe sends a [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) event when the payment completes. Use the Dashboard, a custom *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests), or a partner solution to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow. Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events also helps you accept more payment methods in the future. Learn about the [differences between all supported payment methods](https://stripe.com/payments/payment-methods-guide). - **Handle events manually in the Dashboard** Use the Dashboard to [View your test payments in the Dashboard](https://dashboard.stripe.com/test/payments), send email receipts, handle payouts, or retry failed payments. - **Build a custom webhook** [Build a custom webhook](https://docs.stripe.com/webhooks/handling-payment-events.md#build-your-own-webhook) handler to listen for events and build custom asynchronous payment flows. Test and debug your webhook integration locally with the Stripe CLI. - **Integrate a prebuilt app** Handle common business events, such as [automation](https://stripe.partners/?f_category=automation) or [marketing and sales](https://stripe.partners/?f_category=marketing-and-sales), by integrating a partner application. # Android > This is a Android for when payment-ui is mobile and platform is android. View the full page at https://docs.stripe.com/payments/accept-stablecoin-payments?payment-ui=mobile&platform=android. We recommend you use the [Mobile Payment Element](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=mobile&platform=android), an embeddable payment form, to add Pay with Crypto and other payment methods to your integration with the least amount of effort. Pay with Crypto is a [single-use](https://docs.stripe.com/payments/payment-methods.md#usage) payment method where customers are required to [authenticate](https://docs.stripe.com/payments/payment-methods.md#customer-actions) their payment. Customers are redirected from your app, authorize the payment with Stripe, then return to your app. You’re [immediately notified](https://docs.stripe.com/payments/payment-methods.md#payment-notification) when the payment succeeds or fails. ## Set up Stripe [Server-side] [Client-side] First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register). ### Server-side This integration requires endpoints on your server that talk to the Stripe API. Use the official libraries for access to the Stripe API from your server: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` #### Python ```bash # Install through pip pip3 install --upgrade stripe ``` ```bash # Or find the Stripe package on http://pypi.python.org/pypi/stripe/ ``` ```python # Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=5.0.0 ``` #### PHP ```bash # Install the PHP library with Composer composer require stripe/stripe-php ``` ```bash # Or download the source directly: https://github.com/stripe/stripe-php/releases ``` #### Java ```java /* For Gradle, add the following dependency to your build.gradle and replace with the version number you want to use from: - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:31.3.0" ``` ```xml com.stripe stripe-java 31.3.0 ``` ```bash # For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson ``` #### Node.js ```bash # Install with npm npm install stripe --save ``` #### Go ```bash # Make sure your project is using Go Modules go mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v84 ``` ```go // Then import the package import ( "github.com/stripe/stripe-go/v84" ) ``` #### .NET ```bash # Install with dotnet dotnet add package Stripe.net dotnet restore ``` ```bash # Or install with NuGet Install-Package Stripe.net ``` ### Client-side The [Stripe Android SDK](https://github.com/stripe/stripe-android) is open source and [fully documented](https://stripe.dev/stripe-android/). To install the SDK, add `stripe-android` to the `dependencies` block of your [app/build.gradle](https://developer.android.com/studio/build/dependencies) file: #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Stripe Android SDK implementation("com.stripe:stripe-android:22.6.1") // Include the financial connections SDK to support US bank account as a payment method implementation("com.stripe:financial-connections:22.6.1") } ``` #### Groovy ```groovy apply plugin: 'com.android.application' android { ... } dependencies { // ... // Stripe Android SDK implementation 'com.stripe:stripe-android:22.6.1' // Include the financial connections SDK to support US bank account as a payment method implementation 'com.stripe:financial-connections:22.6.1' } ``` > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-android/releases) page on GitHub. To receive notifications when a new release is published, [watch releases for the repository](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository). Configure the SDK with your Stripe [publishable key](https://dashboard.stripe.com/apikeys) so that it can make requests to the Stripe API, such as in your `Application` subclass: #### Kotlin ```kotlin import com.stripe.android.PaymentConfiguration class MyApp : Application() { override fun onCreate() { super.onCreate() PaymentConfiguration.init( applicationContext, "<>" ) } } ``` #### Java ```java import com.stripe.android.PaymentConfiguration; public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); PaymentConfiguration.init( getApplicationContext(), "<>" ); } } ``` > Use your [test keys](https://docs.stripe.com/keys.md#obtain-api-keys) while you test and develop, and your [live mode](https://docs.stripe.com/keys.md#test-live-modes) keys when you publish your app. Stripe samples also use [OkHttp](https://github.com/square/okhttp) and [GSON](https://github.com/google/gson) to make HTTP requests to a server. ## Create a PaymentIntent [Server-side] [Client-side] ### Server-side A [PaymentIntent](https://docs.stripe.com/api/payment_intents/object.md) is an object that represents your intent to collect payment from a customer and tracks the lifecycle of the payment process through each stage. #### Manage payment methods in the Dashboard You can manage payment methods in the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). Stripe handles the return of eligible payment methods based on factors, such as the transaction’s amount, currency, and payment flow. Create a PaymentIntent on your server with an amount and currency. Before creating the PaymentIntent, make sure to turn **Pay with Crypto** on in the [payment methods settings](https://dashboard.stripe.com/settings/payment_methods) page. > Always decide how much to charge on the server-side, a trusted environment, as opposed to the client. This prevents customers from being able to choose their own prices. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "automatic_payment_methods[enabled]"=true ``` ```cli stripe payment_intents create \ --amount=1099 \ --currency=usd \ -d "automatic_payment_methods[enabled]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 1099, "currency": "usd", "automatic_payment_methods": {"enabled": True}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'usd', 'automatic_payment_methods' => ['enabled' => true], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder().setEnabled(true).build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', automatic_payment_methods: { enabled: true, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(1099), Currency: stripe.String(stripe.CurrencyUSD), AutomaticPaymentMethods: &stripe.PaymentIntentCreateAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` #### List payment methods manually If you don’t want to use the Dashboard or you want to manually specify payment methods, you can list them using the `payment_method_types` attribute. Create a PaymentIntent on your server with an amount, currency, and a list of payment methods. > Always decide how much to charge on the server-side, a trusted environment, as opposed to the client. This prevents customers from being able to choose their own prices. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "payment_method_types[]"=crypto ``` ```cli stripe payment_intents create \ --amount=1099 \ --currency=usd \ -d "payment_method_types[0]"=crypto ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', payment_method_types: ['crypto'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 1099, "currency": "usd", "payment_method_types": ["crypto"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'usd', 'payment_method_types' => ['crypto'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") .addPaymentMethodType("crypto") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', payment_method_types: ['crypto'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(1099), Currency: stripe.String(stripe.CurrencyUSD), PaymentMethodTypes: []*string{stripe.String("crypto")}, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", PaymentMethodTypes = new List { "crypto" }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` ### Client-side On the client, request a PaymentIntent from your server and store its *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)). #### Kotlin ```kotlin class CheckoutActivity : AppCompatActivity() { private lateinit var paymentIntentClientSecret: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... startCheckout() } private fun startCheckout() { // Request a PaymentIntent from your server and store its client secret in paymentIntentClientSecret // Click View full sample to see a complete implementation } } ``` #### Java ```java public class CheckoutActivity extends AppCompatActivity { private String paymentIntentClientSecret; @Override public void onCreate(Bundle savedInstanceState) { // ... startCheckout(); } private void startCheckout() { // Request a PaymentIntent from your server and store its client secret in paymentIntentClientSecret // Click View full sample to see a complete implementation } } ``` ## Submit the payment to Stripe [Client-side] When a customer taps to pay with Pay with Crypto, confirm the `PaymentIntent` to complete the payment. Configure a `ConfirmPaymentIntentParams` object with the `PaymentIntent` [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret). The client secret is different from your API keys that authenticate Stripe API requests. Handle it carefully because it can complete the charge. Don’t log it, embed it in URLs, or expose it to anyone but the customer. ### Confirm Pay with Crypto payment Complete the payment by calling [PaymentLauncher confirm](https://stripe.dev/stripe-android/payments-core/com.stripe.android.payments.paymentlauncher/-payment-launcher/confirm.html). This redirects the customer to *https://crypto.stripe.com/pay*, where they can complete the payment with Pay with Crypto. After completion, Stripe calls the `PaymentResultCallback` you set with the result of the payment. #### Kotlin ```kotlin class CheckoutActivity : AppCompatActivity() { // ... private val paymentLauncher: PaymentLauncher by lazy { val paymentConfiguration = PaymentConfiguration.getInstance(applicationContext) PaymentLauncher.create( activity = this, publishableKey = paymentConfiguration.publishableKey, stripeAccountId = paymentConfiguration.stripeAccountId, callback = ::onPaymentResult, ) } // … private fun startCheckout() { // ... val cryptoParams = PaymentMethodCreateParams.createCrypto() val confirmParams = ConfirmPaymentIntentParams .createWithPaymentMethodCreateParams( paymentMethodCreateParams = cryptoParams, clientSecret = paymentIntentClientSecret, ) paymentLauncher.confirm(confirmParams) } private fun onPaymentResult(paymentResult: PaymentResult) { // Handle the payment result… } } ``` #### Java ```java public class CheckoutActivity extends AppCompatActivity { // ... private PaymentLauncher paymentLauncher; @Override public void onCreate(@Nullable Bundle savedInstanceState) { // ... final PaymentConfiguration paymentConfiguration = PaymentConfiguration.getInstance(context); paymentLauncher = PaymentLauncher.create( this, paymentConfiguration.getPublishableKey(), paymentConfiguration.getStripeAccountId(), this::onPaymentResult ); } private void startCheckout() { // ... PaymentMethodCreateParams cryptoParams = PaymentMethodCreateParams.createCrypto(); ConfirmPaymentIntentParams createParams = ConfirmPaymentIntentParams .createWithPaymentMethodCreateParams( cryptoParams, paymentIntentClientSecret ); paymentLauncher.confirm(confirmParams); } // ... private void onPaymentResult(PaymentResult paymentResult) { // Handle the payment result… } } ``` ## Optional: Handle post-payment events Stripe sends a [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) event when the payment completes. Use the Dashboard, a custom *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests), or a partner solution to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow. Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events also helps you accept more payment methods in the future. Learn about the [differences between all supported payment methods](https://stripe.com/payments/payment-methods-guide). - **Handle events manually in the Dashboard** Use the Dashboard to [View your test payments in the Dashboard](https://dashboard.stripe.com/test/payments), send email receipts, handle payouts, or retry failed payments. - **Build a custom webhook** [Build a custom webhook](https://docs.stripe.com/webhooks/handling-payment-events.md#build-your-own-webhook) handler to listen for events and build custom asynchronous payment flows. Test and debug your webhook integration locally with the Stripe CLI. - **Integrate a prebuilt app** Handle common business events, such as [automation](https://stripe.partners/?f_category=automation) or [marketing and sales](https://stripe.partners/?f_category=marketing-and-sales), by integrating a partner application. ### Test your integration Test your crypto payment integration by opening the payment redirect page using your test API keys. You can test a successful payment flow at no cost using [testnet assets](https://docs.stripe.com/payments/accept-stablecoin-payments.md#testnet-assets). 1. In a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes), create a new transaction using your chosen integration method, and open its redirect URL. 1. Connect your preferred wallet and payment network. 1. Complete the payment, and validate that you’re redirected to the expected URL. ### Test payments with testnet assets Most cryptocurrencies offer testnet assets, or tokens that have no monetary value, that you can use to test blockchain transactions. Stripe recommends the MetaMask wallet, Polygon Amoy testnet, and Circle faucet for testing, but you can use your own preferred services. #### Install a wallet 1. [Download the MetaMask extension](https://metamask.io/download) for your web browser. 1. [Create a new wallet](https://support.metamask.io/start/creating-a-new-wallet/) or [import an existing one](https://support.metamask.io/start/use-an-existing-wallet/). #### Enable a testnet 1. In your MetaMask wallet, select **Networks** from the main menu. 1. Click **Add custom network**. 1. Enter the following details: - **Network name**: `Polygon Amoy` - **Default RPC URL**: `https://rpc-amoy.polygon.technology/` - **Chain ID**: `80002` - **Currency symbol**: `POL` - **Block explorer URL**: `https://amoy.polygonscan.com/` 1. Click **Save**. #### Import a token 1. In your MetaMask wallet, under **Tokens**, select **Polygon Amoy** from the network dropdown. 1. Click the overflow menu (⋯), and select **Import tokens**. 1. Click **Select a network** > **Polygon Amoy**. 1. Under **Token contract address**, paste the Polygon Amoy testnet contract address: ``` 0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582 ``` The **Token symbol** field automatically updates with `USDC` and the **Decimals** field with `6`. 1. Click **Next**. 1. Verify that you’re importing the `USDC` token, and then click **Import**. Your MetaMask wallet now shows **Polygon Amoy** and **USDC** in the tokens list. #### Get testnet assets 1. Open [faucet.circle.com](https://faucet.circle.com/) 1. Click **USDC**. 1. Under **Network**, select **Polygon PoS Amoy**. 1. Under **Send to**, paste your wallet address. 1. Click **Send 10 USDC**. In addition to USDC for making payments, you need POL to pay transaction costs: 1. Open [faucet.polygon.technology](https://faucet.polygon.technology/). 1. Under **Select Chain & Token**, select **Polygon Amoy** and **POL**. 1. Under **Verify your identity**, click the third-party platform you want to authenticate with, and complete the login process. 1. Under **Enter Wallet Address**, paste your wallet address. 1. Click **Claim**. Testnet transactions can take a few minutes to complete. Check your wallet to confirm that the USDC and POL has transferred. ### More testnet faucets Check these faucet services for more testing token options: - [Paxos USDP](https://faucet.paxos.com/) - [Devnet SOL](https://faucet.solana.com/) - [Sepolia ETH](https://faucets.chain.link/sepolia) - [Amoy POL](https://faucet.polygon.technology/) ## Optional: Handle the redirect manually [Server-side] The best way to handle redirects is to use Stripe.js with `confirmPayment`. If you need to manually redirect your customers: 1. Provide the URL to redirect your customers to after they complete their payment. ```curl curl https://api.stripe.com/v1/payment_intents/pi_1DRuHnHgsMRlo4MtwuIAUe6u/confirm \ -u "<>:" \ -d payment_method=pm_1EnPf7AfTbPYpBIFLxIc8SD9 \ --data-urlencode return_url="https://shop.example.com/crtA6B28E1" ``` ```cli stripe payment_intents confirm pi_1DRuHnHgsMRlo4MtwuIAUe6u \ --payment-method=pm_1EnPf7AfTbPYpBIFLxIc8SD9 \ --return-url="https://shop.example.com/crtA6B28E1" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.confirm( 'pi_1DRuHnHgsMRlo4MtwuIAUe6u', { payment_method: 'pm_1EnPf7AfTbPYpBIFLxIc8SD9', return_url: 'https://shop.example.com/crtA6B28E1', }, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.confirm( "pi_1DRuHnHgsMRlo4MtwuIAUe6u", { "payment_method": "pm_1EnPf7AfTbPYpBIFLxIc8SD9", "return_url": "https://shop.example.com/crtA6B28E1", }, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->confirm( 'pi_1DRuHnHgsMRlo4MtwuIAUe6u', [ 'payment_method' => 'pm_1EnPf7AfTbPYpBIFLxIc8SD9', 'return_url' => 'https://shop.example.com/crtA6B28E1', ] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentConfirmParams params = PaymentIntentConfirmParams.builder() .setPaymentMethod("pm_1EnPf7AfTbPYpBIFLxIc8SD9") .setReturnUrl("https://shop.example.com/crtA6B28E1") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().confirm("pi_1DRuHnHgsMRlo4MtwuIAUe6u", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.confirm( 'pi_1DRuHnHgsMRlo4MtwuIAUe6u', { payment_method: 'pm_1EnPf7AfTbPYpBIFLxIc8SD9', return_url: 'https://shop.example.com/crtA6B28E1', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentConfirmParams{ PaymentMethod: stripe.String("pm_1EnPf7AfTbPYpBIFLxIc8SD9"), ReturnURL: stripe.String("https://shop.example.com/crtA6B28E1"), } result, err := sc.V1PaymentIntents.Confirm( context.TODO(), "pi_1DRuHnHgsMRlo4MtwuIAUe6u", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentConfirmOptions { PaymentMethod = "pm_1EnPf7AfTbPYpBIFLxIc8SD9", ReturnUrl = "https://shop.example.com/crtA6B28E1", }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Confirm("pi_1DRuHnHgsMRlo4MtwuIAUe6u", options); ``` 1. Confirm the `PaymentIntent` has a status of `requires_action`. The type for the `next_action` will be `redirect_to_url`. ```json "next_action": { "type": "redirect_to_url", "redirect_to_url": { "url": "https://hooks.stripe.com/...", "return_url": "https://example.com/checkout/complete" } } ``` 1. Redirect the customer to the URL provided in the `next_action` property. When the customer finishes the payment process, they’re sent to the `return_url` destination. The `payment_intent` and `payment_intent_client_secret` URL query parameters are included and you can pass through your own query parameters, as described above. --- # Source: https://docs.stripe.com/acceptable-verification-documents.md # Acceptable verification documents by country Learn which documents Stripe accepts for verification of identity, address, and legal entity. See the following list of documents that Stripe accepts as proof of identity, address, and entity for each country Stripe supports. ## Common requirements - Identity documents (including but not limited to passports and driver’s licenses) must be no more than one step removed from the original document: - Document copies and scans must be in PDF format and taken directly from the original document; they can’t be processed, converted, or embedded in other files - A picture of a physical document must be the original, unprocessed picture in JPEG or PNG format - Screenshots aren’t acceptable - When the back side of a document contains required information, and you submit it using the API, include an image of the back side using the `document_back` parameter - Photos and scans of the Photo IDs must be in color - Photos of paper documents must be in color, but scans of paper documents (not Photo IDs) may be black and white - Images must not be low-quality - Identity and legal entity documents must not be expired - Documents must be readable and in a valid upload file format - Documents must not be cropped or missing pages with crucial information, and all borders must be visible - If the country of residence differs from the country of the account, a passport is required for identity verification ## Select a country to view its requirements #### Item 1 #### Item 1 Required information: - Full legal name that matches the name in your settings - Date of birth (DOB) that matches what’s in your settings - Photo of person (except where exclusions apply) #### Brazil Required information: - Personal Tax ID that matches the one in your Stripe profile - Full legal name that matches the name in your settings - Date of birth (DOB) that matches what’s in your settings - Photo of person (except where exclusions apply) #### Item 2 Required information: - Full legal name that matches the name in your settings - Personal address that matches the personal address in your settings - Document that’s dated within the acceptable range, if specified in the above country section ## Cross Border Verification Requirements If the country either doesn’t have any address verification documents listed or is missing from [the list of documents](https://docs.stripe.com/acceptable-verification-documents.md?country=US&document-type=address), we accept the following documents: - A utility bill (issued within the last 6 months) - A bank statement (issued within the last 6 months) Be aware of the following exceptions: - For cross border situations where a US person is added to a non-US account, a US driver’s license is an acceptable form of proof of address. - Credit card statements are acceptable documents for proof of address for China based owners and directors. - For Singapore based Stripe accounts, a CN ID Card is acceptable as proof of Address. - A Turkish Resident Certificate is an acceptable form of address verification for Turkey based account representatives. #### Item 3 Required information: - Full company legal entity name that matches the legal entity name in your settings - Tax ID from the local tax authority that matches what’s in your settings (excluding Canada) - Company address that matches what’s in your settings unless specified otherwise. #### Item 1 #### Item 2 - All documents must be issued or notarized in the last 12 months. #### Item 4 Required information: - Account holder name - Bank account number #### Item 5 #### Item 6 #### Item 1 Required information: - Legal entity name - Where applicable, all director, shareholder, and beneficial owner names and positions #### Singapore Required information: - Legal entity name and UEN - **Issue date**: All documents must be issued or notarized in the last 12 months. - **UBO verification**: All beneficial owner names and positions, and where applicable, ownership amount - **Representative authority verification**: Representative name and position; and if using a Letter of Authorization, Authorizer name, position, and identity documents are additionally required. ### Support articles #### Item 1 - [Passport, ID, or driver’s license upload requirement](https://support.stripe.com/questions/passport-id-or-drivers-license-upload-requirement) #### Item 2 - [Documents for identity and home address verification](https://support.stripe.com/questions/documents-for-identity-and-home-address-verification) #### Item 3 - [Update tax ID information from the Dashboard](https://support.stripe.com/questions/update-tax-id-information-from-the-dashboard) - [What do I need to do to verify my Stripe account?](https://support.stripe.com/questions/what-do-i-need-to-do-to-verify-my-stripe-account) #### Item 4 - [Bank account ownership verification](https://support.stripe.com/questions/bank-account-ownership-verification) #### Item 5 - [Beneficial ownership requirements for nonprofit organizations](https://support.stripe.com/questions/beneficial-ownership-requirements-for-nonprofit-organizations) #### Item 6 - [Company beneficial ownership and director requirement](https://support.stripe.com/questions/company-beneficial-ownership-and-director-requirement) #### Default #### Item 1 #### Item 2 #### Item 3 #### Item 4 #### Item 5 #### Item 6 #### Australia #### Item 1 **Country-specific:** - [Documents for identity and home address verification](https://support.stripe.com/questions/documents-for-identity-and-home-address-verification) #### Item 2 **Country-specific:** - [Connect address validation](https://support.stripe.com/questions/connect-address-validation) #### Item 3 #### Item 4 #### Item 5 #### Item 6 #### Austria #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Documents for business verification of Unincorporated Entities, Partnerships, or Non-profits](https://support.stripe.com/questions/documents-for-business-verification-of-unincorporated-entities-partnerships-or-non-profits) #### Item 4 #### Item 5 #### Item 6 #### Belgium #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Documents for business verification of Unincorporated Entities, Partnerships, or Non-profits](https://support.stripe.com/questions/documents-for-business-verification-of-unincorporated-entities-partnerships-or-non-profits) #### Item 4 #### Item 5 #### Item 6 #### Brazil #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Accepted documents for verification in Brazil](https://support.stripe.com/questions/accepted-documents-for-verification-in-brazil) - [Information needed to open a Stripe account in Brazil](https://support.stripe.com/questions/information-needed-to-open-a-stripe-account-in-brazil) - [Updating tax information for Stripe accounts in Brazil](https://support.stripe.com/questions/updating-tax-information-for-stripe-accounts-in-brazil) #### Item 4 **Country-specific:** - [Supported bank accounts in Brazil](https://support.stripe.com/questions/supported-bank-accounts-in-brazil) #### Item 5 #### Item 6 #### Canada #### Item 1 #### Item 2 **Country-specific:** - [Connect address validation](https://support.stripe.com/questions/connect-address-validation) - [Onboarding Requirements Updates](https://support.stripe.com/user/questions/onboarding-requirements-updates) #### Item 3 **Country-specific:** - [Documents for business verification of Unincorporated Entities, Partnerships, or Non-profits](https://support.stripe.com/questions/documents-for-business-verification-of-unincorporated-entities-partnerships-or-non-profits) - [Onboarding Requirements Updates](https://support.stripe.com/user/questions/onboarding-requirements-updates) - [Social Insurance Number (SIN) / Numéro D’Assurance Sociale (NAS) requirement for Canadian businesses](https://support.stripe.com/questions/social-insurance-number-%28sin%29-num%C3%A9ro-dassurance-sociale-%28nas%29-requirement-for-canadian-businesses) - [Types of business and structure guidelines in Canada](https://support.stripe.com/questions/types-of-business-and-structure-guidelines-in-canada) - [Verifying registered charity status in Canada](https://support.stripe.com/questions/verifying-registered-charity-status-in-canada) #### Item 4 **Country-specific:** - [Canada Bank Verification](https://support.stripe.com/questions/canada-bank-verification) - [Onboarding Requirements Updates](https://support.stripe.com/user/questions/onboarding-requirements-updates) #### Item 5 **Country-specific:** - [Verifying Registered Charity status in Canada](https://support.stripe.com/questions/verifying-registered-charity-status-in-canada) #### Item 6 **Country-specific:** - [Beneficial Ownership Requirements: Canada](https://support.stripe.com/questions/beneficial-ownership-requirements-canada) - [Onboarding Requirements Updates](https://support.stripe.com/user/questions/onboarding-requirements-updates) #### Czech Republic #### Item 1 #### Item 2 #### Item 3 #### Item 4 #### Item 5 #### Item 6 **Country-specific:** - [Beneficial Ownership Requirements: Czech Republic, Estonia, and Latvia](https://support.stripe.com/questions/beneficial-ownership-requirements-czech-republic-estonia-and-latvia) #### Estonia #### Item 1 #### Item 2 **Country-specific:** - [Supporting companies that registered in Estonia through e-residency](https://support.stripe.com/questions/supporting-companies-that-registered-in-estonia-through-e-residency) #### Item 3 #### Item 4 #### Item 5 #### Item 6 **Country-specific:** - [Beneficial Ownership Requirements: Czech Republic, Estonia, and Latvia](https://support.stripe.com/questions/beneficial-ownership-requirements-czech-republic-estonia-and-latvia) #### France #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Documents for business verification of Unincorporated Entities, Partnerships, or Non-profits](https://support.stripe.com/questions/documents-for-business-verification-of-unincorporated-entities-partnerships-or-non-profits) - [Stripe availability for outlying territories of supported countries](https://support.stripe.com/questions/stripe-availability-for-outlying-territories-of-supported-countries) #### Item 4 #### Item 5 #### Item 6 #### Germany #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Documents for business verification of Unincorporated Entities, Partnerships, or Non-profits](https://support.stripe.com/questions/documents-for-business-verification-of-unincorporated-entities-partnerships-or-non-profits) #### Item 4 #### Item 5 #### Item 6 #### Hong Kong #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Requirements for Hong Kong-based businesses](https://support.stripe.com/questions/requirements-for-hong-kong-based-businesses) #### Item 4 #### Item 5 #### Item 6 #### India #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Onboarding requirements for Stripe Connect in India](https://support.stripe.com/questions/onboarding-requirements-for-stripe-connect-in-india) #### Item 4 #### Item 5 #### Item 6 #### Indonesia #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Requirements to open a Stripe account in Indonesia](https://support.stripe.com/questions/requirements-to-open-a-stripe-account-in-indonesia) #### Item 4 #### Item 5 #### Item 6 #### Ireland #### Item 1 #### Item 2 #### Item 3 #### Item 4 #### Item 5 #### Item 6 **Country-specific:** - [Beneficial Ownership Requirements: Ireland](https://support.stripe.com/questions/beneficial-ownership-requirements-ireland) - [Irish-registered businesses: how to collect Beneficial Ownership Information from the Register of Beneficial Ownership (RBO)](https://support.stripe.com/questions/irish-registered-businesses-how-to-collect-beneficial-ownership-information-from-the-register-of-beneficial-ownership-%28rbo%29) #### Italy #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Documents for business verification of Unincorporated Entities, Partnerships, or Non-profits](https://support.stripe.com/questions/documents-for-business-verification-of-unincorporated-entities-partnerships-or-non-profits) #### Item 4 #### Item 5 #### Item 6 #### Latvia #### Item 1 #### Item 2 #### Item 3 #### Item 4 #### Item 5 #### Item 6 **Country-specific:** - [Beneficial Ownership Requirements: Czech Republic, Estonia, and Latvia](https://support.stripe.com/questions/beneficial-ownership-requirements-czech-republic-estonia-and-latvia) #### Mexico #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Accounts from Mexico: Update your tax information](https://support.stripe.com/questions/accounts-from-mexico-update-your-tax-information) #### Item 4 #### Item 5 #### Item 6 #### Netherlands #### Item 1 **Country-specific:** - [Documents for identity and home address verification](https://support.stripe.com/questions/documents-for-identity-and-home-address-verification) #### Item 2 #### Item 3 #### Item 4 #### Item 5 #### Item 6 #### Portugal #### Item 1 #### Item 2 #### Item 3 **Country-specific:** - [Documents for business verification of Unincorporated Entities, Partnerships, or Non-profits](https://support.stripe.com/questions/documents-for-business-verification-of-unincorporated-entities-partnerships-or-non-profits) #### Item 4 #### Item 5 #### Item 6 #### Singapore #### Item 1 **Country-specific:** - [2025 updates to Singapore verification requirements](https://support.stripe.com/questions/2025-updates-to-singapore-verification-requirements) - [Singapore verification requirements for Custom connected accounts](https://support.stripe.com/questions/singapore-verification-requirements-for-custom-connected-accounts-faq) - [Singapore verification requirements for Standard and Express platforms](https://support.stripe.com/questions/singapore-verification-requirements-for-platforms-updates-and-faq) - [Enhanced identity verification for Singapore-based accounts](https://support.stripe.com/questions/enhanced-identity-verification-for-singapore-based-accounts) #### Item 2 #### Item 3 **Country-specific:** - [2025 updates to Singapore verification requirements](https://support.stripe.com/questions/2025-updates-to-singapore-verification-requirements) - [Singapore verification requirements for Custom connected accounts](https://support.stripe.com/questions/singapore-verification-requirements-for-custom-connected-accounts-faq) #### Item 4 #### Item 5 #### Item 6 **Country-specific:** - [2025 updates to Singapore verification requirements](https://support.stripe.com/questions/2025-updates-to-singapore-verification-requirements) - [Ultimate Beneficial Ownership Requirements: Singapore](https://support.stripe.com/questions/singapore-ultimate-beneficial-ownership-and-director-requirements) - [Representative Authority Verification](https://support.stripe.com/questions/representative-authority-verification) #### Thailand #### Item 1 **Country-specific:** - [What documents are accepted to verify my account in Thailand?](https://support.stripe.com/questions/what-documents-are-accepted-to-verify-my-account-in-thailand) #### Item 2 #### Item 3 **Country-specific:** - [What documents are accepted to verify my account in Thailand?](https://support.stripe.com/questions/what-documents-are-accepted-to-verify-my-account-in-thailand) - [Why is Stripe requesting evidence of licensing for my business in Thailand?](https://support.stripe.com/questions/why-is-stripe-requesting-evidence-of-licensing-for-my-business-in-thailand) #### Item 4 #### Item 5 #### Item 6 #### United Arab Emirates #### Item 1 **Country-specific:** - [Continuous Verification in the UAE](https://support.stripe.com/questions/continuous-verification-in-the-uae) - [Owner verification in the UAE](https://support.stripe.com/questions/owner-verification-in-the-uae) - [Troubleshooting UAE Verification Issues](https://support.stripe.com/questions/troubleshooting-uae-verification-issues) - [Using the API to upload UAE verification documents](https://support.stripe.com/questions/using-the-api-to-upload-uae-verification-documents) #### Item 2 #### Item 3 **Country-specific:** - [Continuous Verification in the UAE](https://support.stripe.com/questions/continuous-verification-in-the-uae) - [Troubleshooting UAE Verification Issues](https://support.stripe.com/questions/troubleshooting-uae-verification-issues) - [Using the API to upload UAE verification documents](https://support.stripe.com/questions/using-the-api-to-upload-uae-verification-documents) - [Verification of businesses in the UAE](https://support.stripe.com/questions/verification-of-businesses-in-the-uae) #### Item 4 **Country-specific:** - [Supported banks in the UAE](https://support.stripe.com/questions/supported-banks-in-the-uae) #### Item 5 #### Item 6 **Country-specific:** - [Beneficial Ownership Verification for Holding Companies](https://support.stripe.com/questions/beneficial-ownership-verification-for-holding-companies) #### United Kingdom #### Item 1 #### Item 2 #### Item 3 #### Item 4 #### Item 5 #### Item 6 **Country-specific:** - [Beneficial ownership requirements](https://support.stripe.com/questions/beneficial-ownership-requirements-united-kingdom) #### United States #### Item 1 **Country-specific:** - [Verification after name has changed](https://support.stripe.com/questions/verification-after-name-has-changed) - [“Verify your tax information” error messages](https://support.stripe.com/questions/verify-your-tax-information-error-messages) #### Item 2 **Country-specific:** - [Connect address validation](https://support.stripe.com/questions/connect-address-validation) #### Item 3 **Country-specific:** - [2023/2024 US verification requirements updates for Standard and Express Platforms: FAQs](https://support.stripe.com/questions/2023-2024-us-verification-requirements-updates-for-standard-and-express-platforms-faqs) - [2024 updates to US verification requirements FAQ](https://support.stripe.com/questions/2024-updates-to-us-verification-requirements-faq) - [How to check your EIN status with the IRS](https://support.stripe.com/questions/how-to-check-your-ein-status-with-the-irs) - [Newly-issued US tax ID number (TIN) not verifying](https://support.stripe.com/questions/newly-issued-us-tax-id-number-%28tin%29-not-verifying) - [Signing up for a US Stripe account without a tax ID or employer ID number](https://support.stripe.com/questions/signing-up-for-a-us-stripe-account-without-a-tax-id-or-employer-id-number) - [Tax ID Number (TIN) format is different than Stripe’s suggested TIN format in the dashboard](https://support.stripe.com/questions/tax-id-number-\(tin\)-format-is-different-than-stripe-s-suggested-tin-format-in-the-dashboard) - [Tax information to submit when signing up for Stripe as a US-based nonprofit or tax-exempt organization](https://support.stripe.com/questions/tax-information-to-submit-when-signing-up-for-stripe-as-a-us-based-nonprofit-or-tax-exempt-organization) - [“This combination of tax ID and legal name was not recognized by the IRS” error when entering tax ID for verification](https://support.stripe.com/questions/this-combination-of-tax-id-and-legal-name-was-not-recognized-by-the-irs-error-when-entering-tax-id-for-verification) - [Using IRS documentation as reference when entering business name and tax ID number (TIN) for US-based businesses](https://support.stripe.com/questions/using-irs-documentation-as-reference-when-entering-business-name-and-tax-id-number-%28tin%29-for-us-based-businesses) - [“Verify your tax information” error messages](https://support.stripe.com/questions/verify-your-tax-information-error-messages) #### Item 4 #### Item 5 #### Item 6 **Country-specific:** - [Beneficial Ownership Requirements: United States](https://support.stripe.com/questions/beneficial-ownership-requirements-united-states) ## Upload your verification documents Due to the sensitive nature of your verification documents, Stripe can only accept documents that are uploaded through the Dashboard. Don’t send documents by email. In the [Dashboard](https://dashboard.stripe.com/dashboard), banners direct you to the correct location to upload any required documents. --- # Source: https://docs.stripe.com/payments/analytics/acceptance.md # Acceptance analytics Understand what affects card payment acceptance and why payments fail or are declined. Use the [Acceptance](https://dashboard.stripe.com/acceptance) page to analyze your payment success rate and network authorization rate, and view pivot reports for common criteria. You can identify where payments fail and why they fail, and use this information to help increase your revenue. > Optimization calculations are estimates and aren’t guarantees of any outcomes. The data we provide is intended to help inform your decision-making, in order for you to make your own independent determinations about whether to use these features. The calculation methodology for estimated impacts is also subject to change without prior notice. Refer to this page regularly to ensure you have the latest understanding of the estimated optimization feature benefits. ## Available data The **Acceptance** page includes data for attempted and authorized card payments: - **Attempted payments**: Stripe sends the details of a customer’s payment attempt through a *card network* (A network that processes the transactions of a particular card brand. It might be an intermediary in front of an issuing bank as with Visa or Mastercard, or a standalone entity as with American Express), such as Visa, Mastercard, or China UnionPay. The card network sends the request to the *card issuing bank* (The entity that issued a payment card to a cardholder. This could be a bank, such as with the Visa or Mastercard network, or it could be the card network itself, such as with American Express), which authorizes or [declines](https://docs.stripe.com/declines.md) the payment. - **Authorized payments**: The card issuing bank validates the customer’s card details and reserves sufficient funds for the transaction. The issuing bank approves the payment and secures the amount, but waits to transfer funds until after you capture the transaction. Authorized payments don’t consider whether the payments were ultimately captured. Learn more about the distinction between [authorization and capture](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md). ## Configure your data set You can apply the filters to all metrics, reports, and tables on the **Acceptance** page. Stripe processes your data daily starting at 12:00 PM UTC and ending at 11:59 PM UTC. All data shown is in the UTC time zone. ![Filters for acceptance analytics](https://b.stripecdn.com/docs-statics-srv/assets/acceptance-filters.1e474c5f0210ec309fe3368a8c5ce340.png) Filters on the Acceptance page ### Specify the account type If you use [Organizations](https://docs.stripe.com/get-started/account/orgs.md), you can see the acceptance analytics for each account: 1. In the Dashboard, click the account picker, and select your organization. 1. To open the **Acceptance analytics** page, go to **Payments** > [**Analytics**](https://dashboard.stripe.com/org/acceptance). 1. (Optional) To view analytics for a specific account, under the filters, click **Account**, and select an account. 1. (Optional) By default, the acceptance analytics for Organizations are displayed in USD. To change the displayed currency of your data, click **Show in USD**, and select your preferred currency from the dropdown. The displayed currency setting is different than the [currency filter](https://docs.stripe.com/payments/analytics/acceptance.md#specify-currency). ### Specify the processor Apply the processor filter to display acceptance analytics for a specific payment processor. Based on your configuration, you might accept payments from other processors, in addition to Stripe. To specify a processor, click **Processor**, select the processor, and click **Apply**. You can choose to view multiple processors. ### Specify Connect Connect platforms can see direct charge activity aggregated across all of their connected accounts. To see data from Standard accounts, platforms must enable [Platform controls](https://docs.stripe.com/connect/platform-controls-for-stripe-dashboard-accounts.md). - To include connected accounts data, click **Include connected accounts**. - To exclude connected accounts data, click **Don’t include connected accounts**. ### Specify the payment success rate or the authorization rate Apply the rate filter to display analytics for a payment success rate or an authorization rate. #### Payment success rate The payment success rate measures the success of all payment attempts throughout the payment process, including 3DS authentication, Stripe or Radar blocks, and card network authentication. To calculate the rate, we divide the number of charges authorized by the card network by the number of unique payment attempts submitted through Stripe. We include all payment attempts, except [invalid API calls](https://docs.stripe.com/declines.md#invalid-api-calls). The types of payment attempts include: - Failed 3DS authentication payments - Blocked payments - Issuer declines - Authorized payments To specify a payment success rate, click **Payment success rate**. #### Authorization rate The authorization rate (also known as network authorization rate) measures the success of payment attempts that reach the card networks. To calculate the rate, we divide the number of payments authorized by the card issuer by the number of unique payment attempts submitted to the card network for authorization. We exclude [invalid API calls](https://docs.stripe.com/declines.md#invalid-api-calls), payments that fail 3D Secure authentication, and [blocked payments](https://docs.stripe.com/declines.md#blocked-payments) in the denominator because these failures occur before Stripe sends the authorization request to the issuer. The types of payment attempts include: - Issuer declines - Authorized payments To specify an authorization rate, click **Authorization rate**. > You can’t specify an authorization rate if you set the processor filter to a non-Stripe processor. Stripe doesn’t have access to non-Stripe data. #### Example acceptance rate calculation #### Example rate calculation The following is an example calculation for payment success rate and authorization rate: | Calculation component | Component value | | -------------------------------------------------- | ------------------------- | | Total payment requests to Stripe | 103,000 | | Invalid API requests | (3,000) | | Valid API requests | 100,000 | | Failed authentication attempts | (1,000) | | Blocked payment attempts | (1,000) | | Total payment attempts that reach the card network | 98,000 | | Authorized payments | 93,000 | | Payment success rate | 93% = (93,000 / 100,000) | | Authorization rate | 94.9% = (93,000 / 98,000) | ### Specify the raw rate or the deduplicated rate Some payment attempts are repeat attempts of the same unique purchase. For example, if the original payment attempt is declined because the CVC is wrong, the customer must resubmit payment after correcting the error. We include all payment attempts, except invalid API requests. #### Raw rate The raw rate includes all payment attempts (including retries) to make the same purchase. To specify the raw rate, click **Raw**. #### Deduplicated rate The deduplicated rate groups the retried payment attempts together and calculates the acceptance rate based on the final outcome. Stripe groups payment attempts as follows: - For payments through [Stripe Invoices](https://docs.stripe.com/api/invoices.md), we group attempts on the same Invoice. - For payments with [Customers](https://docs.stripe.com/api/customers.md), we group attempts on the same Customer, if they’re attempted close to each other in time and for the same amount. - For all other payments, we group on the same card number for attempts close to each other in time and for the same amount. When looking at deduplicated rates, you might see a temporary drop in the success rate or authorization rate for the past month, if all payment retries haven’t been attempted. You can also schedule repeat payment retries (called “dunning”), which is common for businesses with recurring revenue. If you perform dunning through [Stripe Billing](https://docs.stripe.com/billing.md), Stripe highlights the affected portion of the report using your Billing settings. To specify the deduplicated rate, click **Deduplicated**. #### Example rate calculation #### Example rate calculation The following is an example calculation showing the difference between raw and deduplicated rate: | Calculation step | Result | | ----------------------------------------------------------------- | ----------------------------------------------------------- | | Payment A, attempt 1 | Failed | | Payment A, attempt 2 | Failed | | Payment A, attempt 3 | Authorized | | Raw rate *(Counts all attempts)* | 33.3% = (1 / 3) *(1 authorized attempt / 3 total attempts)* | | Deduplicated rate *(Counts only the final attempt for payment A)* | 100% = (1 / 1) *(1 authorized attempt / 1 total attempt)* | ### Specify the currency Apply a currency filter to display only payments made using the selected currency. If you don’t apply a currency filter, all payments appear in your default settlement currency, regardless of the payment currency. For example, your default settlement currency is USD, but you apply the EUR currency filter. The transactions that display only include payments made in EUR, and excludes payments made in all other currencies, such as USD. To specify the currency, click **More filters** > **Currency**, and select your preferred currency. ## Transaction detail page You can view the underlying transaction data that populates the charts in each report. To access this detailed view, click the expander ↗ at the top of any report. This opens the transaction detail page. You can **Download** :download: the acceptance data that’s generated for your report. This data includes all payments that match the filters you selected. If you have an active [Sigma](https://docs.stripe.com/stripe-data/how-sigma-works.md) subscription, you can click **Explore** :explorer: to access templates for the queries that represent each chart. You can use this interface to perform custom analyses on the data that populates the charts. ## Key metrics report This report shows the key metrics for the filters you selected, including the rate, number of authorized payments, and authorized payment volume. The time series compares the rate to a `previous_period`, which you can customize. By default, the comparison period starts right before your chosen timeframe and represents the same length of time. You can explore trends using [Sigma](https://docs.stripe.com/stripe-data/how-sigma-works.md), or filter by available charge attributes using the itemized download. For example, [card testing](https://docs.stripe.com/disputes/prevention/card-testing.md) can lead to a reduction in the rate and a sudden spike in payment count. ## Card payments breakdown report This report shows the card acceptance metrics across several common criteria that drive acceptance. Each top-level filter has a corresponding pivot report. You can pair the filtering capabilities with the pivot reports to monitor how different groups of payments perform over time. You can also analyze payments across options such as card brands, countries, or input methods your customers use to pay. Use the tabs to compare rates, payment count (in absolute numbers or as a share of payments), and payment volume. You can see how changes in the rate relate to changes in payment count or payment volume. | Option | Description | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Card country | The country of the card issuer, rather than the physical location of your customer at the time of payment. On average, domestic success rates are higher than cross-border payments (where the card country and your business are located in different regions). This pivot might also help you identify your customers’ locations. | | Card type | On average, credit success rates are higher than debit success rates, which in turn are higher than prepaid success rates. This is usually because payments made with debit and prepaid cards are more likely to be declined for having insufficient funds to complete the purchases. | | CVC response | The 3 or 4 digit verification number printed on a card, usually on the signature strip or the front of the card. When Stripe sends the [CVC](https://docs.stripe.com/disputes/prevention/verification.md#cvc-check) (or CVV) to the card network for authorization, the card issuer checks the CVC against the customer information on-file as additional verification. If the provided information doesn’t match, the CVC verification check fails, which can result in a declined payment. A failed CVC check might indicate the payment is fraudulent, so review it carefully before fulfilling the order. Example values: - **Not sent** - The CVC wasn’t sent to the card networks. - **Passed** - The CVC was sent to the card networks and passed validation. - **Failed** - The CVC was sent to the card networks and failed validation. - **Unchecked** - The CVC was sent to the card networks, but validation wasn’t performed. | | Input method | Digital wallets, such as Apple Pay or Google Pay, typically have higher success rates than card payments because they’re tokenized and device-authenticated, creating a higher level of trust for the card issuer. If you use [Stripe Terminal](https://docs.stripe.com/terminal.md), you might also see **Card present** as an input method, which represents in-person payments. Card present success rates are typically higher than card not present transactions. The physical card must be present at the time of purchase for in-person payments, so these payments often have lower risk profiles for card issuers than online payments. | | Interaction type | The card networks divide card payments into two types, based on whether the customer participates in the payment flow: [Customer-Initiated Transactions (CITs) and Merchant-Initiated Transactions (MITs)](https://docs.stripe.com/payments/cits-and-mits.md). Card issuers assign different characteristics and risk profiles to these transaction types, so you might see varying success rates between the two. Each interaction type includes granular sub-categories of interaction type entailed by this filter or pivot option. - **Customer-initiated payments** include one-time, saved card and recurring initial payments. A recurring initial payment is the first payment in a series of recurring payments. - **Merchant-initiated payments** include recurring subsequent and unscheduled payments. | | Network token usage | A [network token](https://stripe.com/guides/understanding-benefits-of-network-tokens#what-are-network-tokens) (NT) is a non-sensitive, 16-digit numeric substitute for a “front-of-card” number, also referred to as a primary account number (PAN). When paired with a cryptogram, a network token can be sent to the card network in the authorization message, instead of a PAN. Unlike PANs, network tokens are payment credentials that you can dynamically restrict to specific businesses and channels, reducing the risk and impact of potential security breaches and intrusions. Businesses also use NTs for authorization rate uplift; networks contain the latest mapping between NTs and PANs, so Stripe can continue to use the same NT even if the underlying PAN changes, and avoid declines on legitimate payment attempts. | | Postal code response | The Address Verification Service (AVS) is an identity verification tool that lets you detect and prevent potentially fraudulent credit or debit card payments by comparing the billing address provided by a customer with the billing address on-file with the customer’s card issuer, to confirm they match. Address verification is primarily supported by card issuers in the United States, Canada, and the United Kingdom. Example values: - **Not sent** - The postal code wasn’t sent to the card networks. - **Passed** - The postal code was sent to the card networks and passed validation. - **Failed** - The postal code was sent to the card networks and failed validation. - **Unchecked** - The postal code was sent to the card networks, but validation wasn’t performed. | | Processor | If your configuration includes multiple processors, you can use the [processor filter](https://docs.stripe.com/payments/analytics/acceptance.md#specify-processor) to view the Card payments breakdown report for the selected processor. | | Retry status | View transactions based on whether a payment has been retried. This differs from [deduplication](https://docs.stripe.com/payments/analytics/acceptance.md#specify-raw-rate-deduplicated-rate), which is the final payment attempt and can be the first attempt with the final result. | | Other | The Other category groups low volume data points that aren’t represented on the pivot report. For example, you might want to see the full set of card-issued countries in your data. To do so, you can view the data in Sigma or download the data, both available in the [transaction detail page](https://docs.stripe.com/payments/analytics/acceptance.md#transaction-detail-page). | ## Failed card payments report This report shows why payments failed or were declined. A payment attempt can fail at multiple stages, even before the payment is sent to the card network. For example, it might fail [3D Secure authentication](https://docs.stripe.com/payments/3d-secure.md) or get blocked by *Stripe Radar* (Stripe Radar helps detect and block fraud for any type of business using machine learning that trains on data across millions of global companies. It’s built into Stripe and requires no additional setup to get started). After the payment is sent to the card network, issuers can decline it for reasons such as insufficient funds on the card account or incorrect card information. Occasionally, issuers incorrectly decline legitimate payments for suspected fraud. ### Before the payment is sent to the card network Failures might occur before the payment is sent to the card network for the following reasons. | Reason | Description | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Authentication failed** | You can use the API or a Radar rule to request 3D Secure (3DS) [authentication](https://docs.stripe.com/payments/3d-secure/authentication-flow.md) for payments. Stripe might also trigger 3DS to comply with certain regulations, such as [Strong Customer Authentication (SCA)](https://stripe.com/guides/strong-customer-authentication) requirements in Europe. This failed attempt is for situations where the customer didn’t finish the authentication steps or failed the authentication for other reasons. To learn more about authentication failures, see [Payments analytics](https://docs.stripe.com/payments/analytics.md). | | **Block payments by reason** | Stripe Radar blocks high risk payments, such as payments with mismatched CVC or postal code values. This automated fraud prevention feature evaluates each payment, without requiring any action from you. This blocked attempt is for situations where Stripe blocks payments. We obtain initial authorization from the card issuer, but don’t charge the card. This can help prevent potential fraudulent payments that might lead to disputes. To learn more about the reasons for blocked payments, see the [Blocked card payments report](https://docs.stripe.com/payments/analytics/acceptance.md#blocked-payments-report). | ### After the payment is sent to the card network Failures might occur after the payment is sent to the card network for the following reasons. #### Issuer declines Card issuers use automated systems and models to determine whether to authorize a submitted payment request. If the issuer declines a payment, Stripe shares the [reason](https://docs.stripe.com/declines/card.md) provided by the issuer. In some cases, the issuer provides specific reasons for the decline with a [decline code](https://docs.stripe.com/declines/codes.md). However, many payments are categorized into generic declines (the most common is `do_not_honor`). For privacy and security, card issuers can only discuss specific details with their cardholders, and not with you or Stripe. For most businesses, card issuers decline payments for the following reasons. | Reason | Description | | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Generic response, such as do not honor or service not allowed** | The issuer has chosen not to provide the specific reason for their decision. Prompt the customer to contact their card issuer for more information, or to try a different payment method. You can also retry the payment method. | | **Incorrect card information, such as incorrect number or CVC** | The customer has entered incorrect card information or card information that’s no longer valid. Make sure you enabled [automatic card updates](https://docs.stripe.com/payments/charges-api.md). Contact the customer through multiple channels, such as email, text message, or in-app notification to re-enter their payment details or contact their card issuer if problems persist. Otherwise, try a different payment method. | | **Insufficient funds** | The account doesn’t have sufficient funds to cover the payment amount at the time of authorization. Prompt the customer to try a different payment method, or obtain approval from the customer to retry the payment at a later date. | | **Lost or stolen card** | The customer has reported the card as either lost or stolen. Retries won’t succeed, and the customer must contact their card issuer for more information. Don’t report the specific reason to the customer, in case the legitimate cardholder isn’t the one attempting the purchase. | | **Transaction not allowed** | The issuer declined the payment for unspecified reasons, which might be related to the card or payment. If it’s the payment, the merchant spend category might not be allowed on the card (for example, FSA cards for ineligible items). The customer must contact their card issuer for more information (retries are unlikely to succeed until the issuer is contacted), or try a different payment method. | For the full list of potential reasons why card issuers decline payments, see [decline codes](https://docs.stripe.com/declines/codes.md). ## Blocked card payments report This report shows why payments were blocked. | Block reason | Description | | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Radar - Rule match | Some payments are blocked because of a rule that you configured in Radar. This doesn’t include payments that Radar blocked by default because of their risk score. | | Radar - Post authorization rule match | Some payments are blocked after the card issuer has authorized the payment because of a configured rule in Radar. Specifically, Radar rules that require a response from the card issuer, such as ensuring postal code or CVC match what the card issuer had on-file. This doesn’t include payments that Radar blocked by default because of their risk score. | | Radar - High risk | Some payments are blocked by Radar by default because of their risk score. Radar determines this score using AI, and you can adjust the minimum score that it blocks by default. There are some Radar rules that block payments after they have been authorized. | | Stripe - Adaptive Acceptance | For users with [IC+ pricing](https://support.stripe.com/questions/understanding-blended-interchange-pricing), Adaptive Acceptance blocks certain payments to help you [avoid unnecessary network costs and penalties](https://docs.stripe.com/payments/analytics/optimization.md#cost-savings-from-optimizations). For example, Adaptive Acceptance can help you avoid excessive retry penalties. Adaptive Acceptance can also help you avoid network costs by blocking payments that have low likelihood of authorization. | | Stripe - Rule match | Some payments are blocked by Stripe for other reasons not included above. For example, the payment was initiated by a card on deny-lists that are globally known to be fraudulent, or from sanctioned countries. Additionally, Stripe might block payments that are suspected to be connected to [card testing](https://docs.stripe.com/disputes/prevention/card-testing.md). | ## See also - [Authentication analytics](https://docs.stripe.com/payments/analytics/authentication.md) - [Disputes analytics](https://docs.stripe.com/payments/analytics/disputes.md) - [Payment methods analytics](https://docs.stripe.com/payments/analytics/payment-methods.md) --- # Source: https://docs.stripe.com/identity/access-verification-results.md # Access verification results Learn how to access sensitive verification results. You can write code to [display a modal to collect identity documents](https://docs.stripe.com/identity/verify-identity-documents.md) and [handle verification outcomes](https://docs.stripe.com/identity/handle-verification-outcomes.md). You might need to access the sensitive verification results, such as your user’s date of birth or pictures of the collected document, at a later date. You have several options for doing so. First, consider using the [Identity Dashboard](https://dashboard.stripe.com/identity) to access sensitive verification results. If needed, [give team members controlled access](https://docs.stripe.com/get-started/account/teams.md) to your Stripe account. This saves you development time and ensures the sensitive verification data is kept [securely](https://support.stripe.com/questions/managing-your-id-verification-information) on Stripe. You can [access most verification details programmatically](https://docs.stripe.com/identity/verification-sessions.md#results), such as the result of a verification check or the user’s name and address using your [secret key](https://docs.stripe.com/keys.md). Access to more sensitive fields require [restricted API keys](https://docs.stripe.com/keys-best-practices.md#limit-access). | Verification result | Available in Dashboard | Secret key access | Restricted API key access | Recommended Verification Session field | Expand property | | -------------------------------- | ---------------------- | ----------------- | ------------------------- | ------------------------------------------------------------ | --------------------------------------------------- | | Address | ✓ Yes | ✓ Yes | ✓ Yes | `verified_outputs.address` | `verified_outputs` | | Document type | ✓ Yes | ✓ Yes | ✓ Yes | `last_verification_report.document.type` | `last_verification_report` | | First and last names | ✓ Yes | ✓ Yes | ✓ Yes | `verified_outputs.first_name and verified_outputs.last_name` | `last_verification_report` | | Issuing country of the document | ✓ Yes | ✓ Yes | ✓ Yes | `last_verification_report.document.issuing_country` | `last_verification_report` | | Result of the verification check | ✓ Yes | ✓ Yes | ✓ Yes | `status` | Expand not required | | Issued date of the document | ✓ Yes | ✓ Yes | ✓ Yes | `last_verification_report.document.issued_date` | `last_verification_report` | | Type of ID number | ✓ Yes | ✓ Yes | ✓ Yes | `last_verification_report.document.id_number.type` | `last_verification_report` | | Email address | ✓ Yes | ✓ Yes | ✓ Yes | `verified_outputs.email` | `verified_outputs` | | Phone number | ✓ Yes | ✓ Yes | ✓ Yes | `verified_outputs.phone` | `verified_outputs` | | Expiration date of the document | ✓ Yes | ✗ No | ✓ Yes | `last_verification_report.document.expiration_date` | `last_verification_report.document.expiration_date` | | Date of birth | ✓ Yes | ✗ No | ✓ Yes | `verified_outputs.dob` | `verified_outputs.dob` | | Document ID number | ✓ Yes | ✗ No | ✓ Yes | `last_verification_report.document.number` | `last_verification_report.document.number` | | Document images | ✓ Yes | ✗ No | ✓ Yes | `last_verification_report.document.files` | `last_verification_report` | | Face images | ✓ Yes | ✗ No | ✓ Yes | `last_verification_report.selfie.selfie` | `last_verification_report` | | ID number | ✓ Yes | ✗ No | ✓ Yes | `verified_outputs.id_number` | `verified_outputs.id_number` | Restricted API keys allow access based on the security measures associated with it: - **Restricted keys** — Allow access to sensitive verification results for verifications processed in the last 48 hours. - **IP restricted keys** - Allow access to sensitive verification results for all verifications. In this guide, you’ll learn how to: 1. Consider your sensitive data access requirements carefully. 1. Create restricted API keys. 1. Make API requests to obtain sensitive verification results. 1. Roll your keys if they’re compromised. 1. Communicate your sensitive verification results and security measures to your users. 1. Add IP restrictions to your key for long-term access to sensitive verification results. 1. Consider your sensitive data access requirements carefully. 1. Create restricted API keys. 1. Make API requests to obtain sensitive verification results. 1. Roll your keys if they’re compromised. 1. Communicate your sensitive verification results and security measures to your users. ## Consider your sensitive data access requirements carefully To build an integration with Stripe Identity that prioritizes your user’s privacy, you must first decide the minimum amount of PII that you need access to. If you don’t need access to the most sensitive data (that requires authentication with a restricted API key), then your integration can authenticate using your secret key only. To access PII resulting from a verification, you can retrieve a VerificationSession and [expand](https://docs.stripe.com/api/expanding_objects.md) either the [verified_outputs](https://docs.stripe.com/api/identity/verification_sessions/object.md#identity_verification_session_object-verified_outputs) field or - if you need more granular detail on the verification result - the [last_verification_report](https://docs.stripe.com/api/identity/verification_sessions/object.md#identity_verification_session_object-last_verification_report). Expanding either of these fields automatically includes all of the PII fields they contain that only require a secret key. Here is an example of how to expand the `verified_outputs` field to retrieve a user’s name that was verified by Stripe Identity. #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const verificationSession = await stripe.identity.verificationSessions.retrieve( '{{SESSION_ID}}', { expand: [ 'verified_outputs', ], } ); const firstName = verificationSession.verified_outputs.first_name; ``` #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' verification_session = Stripe::Identity::VerificationSession.retrieve({ id: '{{SESSION_ID}}', expand: [ 'verified_outputs', ], }) first_name = verification_session.verified_outputs.first_name ``` #### Python ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' verification_session = stripe.identity.VerificationSession.retrieve( '{{SESSION_ID}}', expand=[ 'verified_outputs', ], ) first_name = verification_session.verified_outputs.first_name ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('<>'); $verification_session = $stripe->identity->verificationSessions->retrieve( '{{SESSION_ID}}', [ 'expand' => [ 'verified_outputs', ], ] ); $first_name = $verification_session->verified_outputs->first_name; ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; VerificationSessionRetrieveParams params = VerificationSessionRetrieveParams.builder() .addExpand("verified_outputs") .build(); VerificationSession verificationSession = VerificationSession.retrieve("{{SESSION_ID}}", params, null); String firstName = verificationSession.getVerifiedOutputs() .getFirstName(); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" params := &stripe.IdentityVerificationSessionParams{} params.AddExpand("verified_outputs") vs, _ := verificationsession.Get("{{SESSION_ID}}", params) first_name := vs.VerifiedOutputs.FirstName ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; var options = new VerificationSessionGetOptions(); options.AddExpand("verified_outputs"); var service = new VerificationSessionService(); var verificationSession = service.Get("{{SESSION_ID}}", options); var firstName = verificationSession.VerifiedOutputs.FirstName; ``` If you do need to access sensitive PII that requires a restricted key, follow the steps in this guide. ## Create a restricted API key [Dashboard] You can use your account’s secret API keys to perform any API request without restriction. Accessing sensitive verification results requires [restricted keys](https://docs.stripe.com/keys-best-practices.md#limit-access), which are more secure. To create a new restricted key, 1. Go to the [API keys page](https://dashboard.stripe.com/apikeys) in the Dashboard and click [**Create restricted key**](https://dashboard.stripe.com/apikeys/create). 1. Name your key. 1. Make sure the Identity **Verification Sessions and Reports** and **Access recent sensitive verification results** permissions are set to **Read**. 1. (optional) If you need to access collected images, add the Files **Write** permission. 1. Click **Create key**. 1. Store the key securely. [Learn more about keeping your keys safe](https://docs.stripe.com/keys-best-practices.md). ![](https://b.stripecdn.com/docs-statics-srv/assets/rak_identity_permissions.51347778adedec20ad9aaec2cb5a5bb9.png) ## Make API requests to obtain sensitive verification results [Server-side] [VerificationReports](https://docs.stripe.com/api/identity/verification_reports.md) contain all the collected data and verification results from a submitted session. VerificationReports are created when all verification checks for a session are processed. They allow you to understand why a verification check failed and what data was successfully verified. You can [expand](https://docs.stripe.com/expand.md) the [last_verification_report](https://docs.stripe.com/api/identity/verification_sessions/object.md#identity_verification_session_object-last_verification_report) session field to retrieve the associated VerificationReport. By default, VerificationReports don’t include sensitive verification results. To access these, you’ll need to: 1. Authenticate using the restricted API key created in step 1. 1. [Expand](https://docs.stripe.com/api/expanding_objects.md) the fields you want to access. Here’s an example of accessing the extracted date of birth, ID number, and document number from a [document check](https://docs.stripe.com/identity/verification-checks.md?type=document): #### Node.js ```javascript // Set your restricted key. Remember to switch to a live restricted key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('rk_test_...'); const verificationSession = await stripe.identity.verificationSessions.retrieve( '{{SESSION_ID}}', { expand: [ 'verified_outputs.dob', 'verified_outputs.id_number', 'last_verification_report.document.number', 'last_verification_report.document.expiration_date', ], } ); const dateOfBirth = verificationSession.verified_outputs.dob; const idNumber = verificationSession.verified_outputs.id_number; const documentNumber = verificationSession.last_verification_report.document.number; const documentExpirationDate = verificationSession.last_verification_report.document.expiration_date; ``` #### Ruby ```ruby # Set your restricted key. Remember to switch to a live restricted key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = 'rk_test_...' verification_session = Stripe::Identity::VerificationSession.retrieve({ id: '{{SESSION_ID}}', expand: [ 'verified_outputs.dob', 'verified_outputs.id_number', 'last_verification_report.document.number', 'last_verification_report.document.expiration_date', ], }) date_of_birth = verification_session.verified_outputs.dob id_number = verification_session.verified_outputs.id_number document_number = verification_session.last_verification_report.document.number document_expiration_date = verification_session.last_verification_report.document.expiration_date ``` #### Python ```python # Set your restricted key. Remember to switch to a live restricted key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = 'rk_test_...' verification_session = stripe.identity.VerificationSession.retrieve( '{{SESSION_ID}}', expand=[ 'verified_outputs.dob', 'verified_outputs.id_number', 'last_verification_report.document.number', 'last_verification_report.document.expiration_date', ], ) date_of_birth = verification_session.verified_outputs.dob id_number = verification_session.verified_outputs.id_number document_number = verification_session.last_verification_report.document.number document_expiration_date = verification_session.last_verification_report.document.expiration_date ``` #### PHP ```php // Set your restricted key. Remember to switch to a live restricted key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('rk_test_...'); $verification_session = $stripe->identity->verificationSessions->retrieve( '{{SESSION_ID}}', [ 'expand' => [ 'verified_outputs.dob', 'verified_outputs.id_number', 'last_verification_report.document.number', 'last_verification_report.document.expiration_date', ], ] ); $date_of_birth = $verification_session->verified_outputs->dob; $id_number = $verification_session->verified_outputs->id_number; $document_number = $verification_session->last_verification_report->document->number; $document_expiration_date = verification_session->last_verification_report->document->expiration_date; ``` #### Java ```java // Set your restricted key. Remember to switch to a live restricted key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "rk_test_..."; VerificationSessionRetrieveParams params = VerificationSessionRetrieveParams.builder() .addExpand("verified_outputs.dob") .addExpand("verified_outputs.id_number") .addExpand("last_verification_report.document.number") .addExpand("last_verification_report.document.expiration_date") .build(); VerificationSession verificationSession = VerificationSession.retrieve("{{SESSION_ID}}", params, null); VerificationSession.VerifiedOutputs.DateOfBirth dateOfBirth = verificationSession.getVerifiedOutputs().getDob(); String idNumber = verificationSession.getVerifiedOutputs().getIdNumber(); String documentNumber = verificationSession.getLastVerificationReportObject() .getDocument() .getNumber(); Date documentExpirationDate = verificationSession.getLastVerificationReportObject() .getDocument() .getExpirationDate() ``` #### Go ```go // Set your restricted key. Remember to switch to a live restricted key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.Key = "rk_test_..." params := &stripe.IdentityVerificationSessionParams{} params.AddExpand("verified_outputs.dob") params.AddExpand("verified_outputs.id_number") params.AddExpand("last_verification_report.document.number") params.AddExpand("last_verification_report.document.expiration_date") vs, _ := verificationsession.Get("{{SESSION_ID}}", params) date_of_birth := vs.VerifiedOutputs.Dob id_number := vs.VerifiedOutputs.IdNumber document_number := vs.LastVerificationReport.Document.Number document_expiration_date := vs.LastVerificationReport.Document.ExpirationDate ``` #### .NET ```dotnet // Set your restricted key. Remember to switch to a live restricted key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "rk_test_..."; var options = new VerificationSessionGetOptions(); options.AddExpand("verified_outputs.dob"); options.AddExpand("verified_outputs.id_number"); options.AddExpand("last_verification_report.document.number"); options.AddExpand("last_verification_report.document.expiration_date"); var service = new VerificationSessionService(); var verificationSession = service.Get("{{SESSION_ID}}", options); var dateOfBirth = verificationSession.VerifiedOutputs.Dob; var idNumber = verificationSession.VerifiedOutputs.IdNumber; var documentNumber = verificationSession.LastVerificationReport.Document.Number; var documentExpirationDate = verificationSession.LastVerificationReport.Document.Number; ``` ## Accessing collected images You can retrieve identity document and face images that you collect as part of a session using the [File Upload API](https://docs.stripe.com/file-upload.md). The following fields on a VerificationReport can hold a reference to a [File](https://docs.stripe.com/api/files.md) resource in the Stripe API: - [document.files](https://docs.stripe.com/api/identity/verification_reports/object.md#identity_verification_report_object-document-files) - images of the identity document - [selfie.document](https://docs.stripe.com/api/identity/verification_reports/object.md#identity_verification_report_object-selfie-document) - image of the photo ID front - [selfie.selfie](https://docs.stripe.com/api/identity/verification_reports/object.md#identity_verification_report_object-selfie-selfie) - image of the user’s face > Document and face images are very sensitive and some countries, such as Germany, have laws prohibiting ID Document images from being shared or kept longer than necessary. As much as possible, access image content with short-lived FileLinks, don’t make copies of the file contents, and [redact sessions](https://docs.stripe.com/identity/verification-sessions.md#redact) and collected images when you’re done using them for the purpose collected. To access the contents of the file, you need to authenticate using the previously created restricted key and [Create a FileLink](https://docs.stripe.com/api/file_links/create.md) with a short expiration and send the [url](https://docs.stripe.com/api/file_links/object.md#file_link_object-url) to the client: #### Node.js ```javascript // Set your restricted key. Remember to switch to a live restricted key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('rk_test_...'); // Get the VerificationReport const session = await stripe.identity.verificationSessions.retrieve( '{{SESSION_ID}}', { expand: ['last_verification_report'], } ); // Retrieve the File id const report = session.last_verification_report; const documentFrontFile = report.document.files[0]; // Create a short-lived FileLink const fileLink = await stripe.fileLinks.create({ file: documentFrontFile, expires_at: Math.floor(Date.now() / 1000) + 30, // link expires in 30 seconds }); // Access the FileLink URL to download file contents const fileUrl = fileLink.url; ``` #### Ruby ```ruby # Set your restricted key. Remember to switch to a live restricted key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = 'rk_test_...' # Get the VerificationReport verification_session = Stripe::Identity::VerificationSession.retrieve({ id: '{{SESSION_ID}}', expand: ['last_verification_report'], }) # Retrieve the File id verification_report = verification_session.last_verification_report document_front_file = verification_report.document.files[0] # Create a short-lived FileLink file_link = Stripe::FileLink.create({ file: document_front_file, expires_at: Time.now.to_i + 30, # link expires in 30 seconds }) # Access the FileLink URL to download file contents file_url = file_link.url ``` #### Python ```python # Set your restricted key. Remember to switch to a live restricted key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = 'rk_test_...' # Get the VerificationReport verification_session = stripe.identity.VerificationSession.retrieve( '{{SESSION_ID}}', expand=['last_verification_report'], ) # Retrieve the file id report = verification_session.last_verification_report document_front_file = report.document.files[0] # Create a short-lived FileLink file_link = stripe.FileLink.create( file=document_front_file, expires_at=time.time() + 30, # link expires in 30 seconds ) # Access the FileLink URL to download file contents file_url = file_link.url ``` #### PHP ```php // Set your restricted key. Remember to switch to a live restricted key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('rk_test_...'); $verification_session = $stripe->identity->verificationSessions->retrieve( '{{SESSION_ID}}', [ 'expand' => [ 'last_verification_report', ], ], ]); $verification_report = $verification_session->last_verification_report; $document_front_file = $verification_report->document->files[0]; $file_link = $stripe->fileLinks->create([ 'file' => $document_front_file, 'expires_at' => time() + 30, ]); $file_url = $file_link->url; ``` #### Java ```java // Set your restricted key. Remember to switch to a live restricted key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "rk_test_..."; VerificationSessionRetrieveParams params = VerificationSessionRetrieveParams.builder() .addExpand("last_verification_report") .build(); VerificationSession verificationSession = VerificationSession.retrieve("{{SESSION_ID}}", params, null); VerificationReport verificationReport = verificationSession.getLastVerificationReportObject(); String documentFrontFile = verificationReport.getDocument().getFiles().get(0); FileLinkCreateParams fileLinkParams = FileLinkCreateParams.builder() .setFile(documentFrontFile) .setExpiresAt(Instant.now().getEpochSecond() + 30L) .build(); FileLink fileLink = FileLink.create(fileLinkParams); String fileUrl = fileLink.getUrl(); ``` #### Go ```go // Set your restricted key. Remember to switch to a live restricted key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "rk_test_..." params := &stripe.IdentityVerificationSessionParams{} params.AddExpand("last_verification_report") vs, _ := verificationsession.Get( "{{SESSION_ID}}", params, ) verification_report := vs.LastVerificationReport document_front_file := verification_report.Document.Files[0]; filelinkparams := &stripe.FileLinkParams{ File: stripe.String(document_front_file), ExpiresAt: stripe.Int64(time.Now().Unix() + 30), } file_link, _ := filelink.New(filelinkparams) file_url := file_link.URL ``` #### .NET ```dotnet // Set your restricted key. Remember to switch to a live restricted key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "rk_test_..."; // Get the VerificationSession var options = new VerificationSessionGetOptions(); options.AddExpand("last_verification_report"); var service = new VerificationSessionService(); var verificationSession = service.Get("{{SESSION_ID}}", options); // Retrieve the File id var report = verificationSession.LastVerificationReport; var documentFrontFile = report.Document.Files[0]; var expiresAtSeconds = DateTimeOffset.Now.ToUnixTimeSeconds() + 30; var expiresAtDateTime = DateTimeOffset.FromUnixTimeSeconds(expiresAtSeconds).UtcDateTime; var fileLinkCreateOptions = new FileLinkCreateOptions { File = documentFrontFile, ExpiresAt = expiresAtDateTime, }; var fileLinkService = new FileLinkService(); var fileLink = fileLinkService.Create(fileLinkCreateOptions); // Access the FileLink URL to download file contents var fileUrl = fileLink.Url; ``` > FileLinks for document and selfie files must expire within 30 seconds. We recommend not downloading the file contents on your server, instead send the FileLink URL to the client to display the image. If you believe an attacker has accessed sensitive data collected by Identity, please [reach out to support](https://support.stripe.com/contact). ## Roll your keys if they’re compromised [Dashboard] Using restricted API keys that only have Identity permissions allows you to roll the keys in case of emergency without affecting other Stripe product integrations. We recommend that you regularly monitor your restricted key usage to ensure that no one has gained access to them. In the [Dashboard](https://dashboard.stripe.com/apikeys), you can use the overflow menu (**…**) to view request logs for a specific API key to view all the requests made from that key. If an API key is compromised, roll the key in the [Dashboard](https://dashboard.stripe.com/apikeys) to block it and generate a new one. Make sure to expire it immediately to prevent bad actors from retrieving sensitive information. > Rolling blocks the API key and generates a new one. We recommend reviewing your [security history](https://dashboard.stripe.com/security_history) for events related to this key. Any webhook endpoints created with this key will stay active, even after the key is rolled. If you believe an attacker has accessed sensitive data collected by Identity, please [reach out to support](https://support.stripe.com/contact). ## Communicate your sensitive data use and security measures Make sure your privacy policy includes information on your use of sensitive verification results. It may also help if you provide information about your security practices. **See also** - [Privacy considerations for handling ID verification data as a business](https://support.stripe.com/questions/privacy-considerations-for-handling-id-verification-data-as-a-business) - [FAQs to provide to your users](https://docs.stripe.com/identity/explaining-identity.md) ## Optional: Add IP restrictions for long-term access to results [Dashboard] Long term programmatic access to sensitive verification results increases the impact of leaking an API key. Consider if your use case really requires it. [Reach out to support](https://support.stripe.com/contact) if you need any help. Restricted API keys with **Access recent sensitive verification results** permissions allow programmatic access for verifications submitted in the last 48 hours. If you need programmatic access to verifications beyond 48 hours, you’ll need to add additional security to your restricted key by adding IP restrictions. 1. Go to the [API keys page](https://dashboard.stripe.com/apikeys) in the Dashboard. 1. In the overflow menu (**…**) click **Manage IP restrictions** for the restricted key you created in step 1. 1. Specify the IP addresses of your production servers. You can express these origins as simply an IP v4 address, or using CIDR ([Classless Inter-Domain Routing](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing)) notation for a whole range of IP addresses. Learn more about adding [IP Key restrictions](https://docs.stripe.com/keys-best-practices.md#ip-allowlist). 1. **Save** the key 1. Edit the key and add the **Access all sensitive verification results** permission. You can now access sensitive verification results for verifications submitted beyond the 48 hour mark. ## See also - [Expanding responses](https://docs.stripe.com/api/expanding_objects.md) - [API Keys](https://docs.stripe.com/keys.md) - [Security at Stripe](https://docs.stripe.com/security.md) --- # Source: https://docs.stripe.com/financial-accounts/connect/access.md # Get started with API access to Financial Accounts for platforms Test in a sandbox environment to experiment before going live. You can use Financial Accounts for platforms and Issuing in a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment to see what functionality you want to enable in your live integration. ## Get test access to Financial Accounts for platforms and Issuing Enable your Stripe account to request `issuing` and `treasury` (Financial Accounts for platforms) capabilities on connected accounts. To issue cards to your own company or employees, see the [Issuing documentation](https://docs.stripe.com/issuing.md). You can only offer Financial Accounts for platforms features [to connected accounts](https://docs.stripe.com/financial-accounts/connect/account-management/accounts-structure.md). 1. Create a [sandbox environment](https://docs.stripe.com/sandboxes/dashboard/manage.md#create-a-sandbox) and switch to it. 1. Enable Issuing and Financial Accounts for platforms on the sandbox in the Dashboard by clicking the activate button below. [Activate Issuing and Financial Accounts for platforms in a Sandbox](https://dashboard.stripe.com/setup/treasury/activate) > You must be an [account administrator](https://docs.stripe.com/get-started/account/teams/roles.md) to complete the Financial Accounts for platforms onboarding steps for a platform. ## Start with your sandbox There are a few ways to start testing the Issuing and Financial Accounts for platforms. ### Test with the Issuing and Financial Accounts for platforms sample application Use the [Issuing and Financial Accounts for platforms sample application](https://docs.stripe.com/financial-accounts/connect/examples/sample-app.md) to onboard your first test connected account, create a financial account and card, and make test transactions using your newly activated sandbox environment. ### Test from the Dashboard You must use the API or sample app to create financial accounts and cards linked to financial accounts. After you create a financial account, you can use the Dashboard to view activity, copy routing and account numbers, and move funds from your platform financial account balance into the financial account. After you create a card, you can use the Dashboard to make test authorizations. See [Use the Dashboard for Issuing with connect](https://docs.stripe.com/issuing/connect.md#using-dashboard-issuing). ### Test Financial Accounts for platforms only (without Issuing) To test Financial Accounts for platforms without Issuing, request the `treasury` capability on a connected account and don’t request `card_issuing`. When you activate Financial Accounts for platforms and Issuing through the link above, it gives your platform the ability to request both capabilities independently. ### Confirm test Issuing and Financial Accounts for platforms are enabled on your sandbox To confirm you’ve enabled Financial Accounts for platforms and Issuing on your sandbox, click **Connect** > **Financial accounts** in the Dashboard to access the [Financial Accounts page](https://dashboard.stripe.com/test/connect/financial-accounts). If you can’t access Financial Accounts, then you haven’t enabled access. ## Configure your account to go live Enabling Financial Accounts for platforms and Issuing through the link above lets you try out basic functionality in a testing environment. After you’re approved for a [supported business use case](https://support.stripe.com/questions/supported-business-use-cases-for-stripe-issuing), you can configure your live account for live Financial Accounts for platforms and Issuing. Your sandbox environment retains the previously created test financial accounts and cards. [Speak to sales](https://go.stripe.global/treasury-inquiry) to get approved for a supported business use case, and configure your live account for live Financial Accounts for platforms and Issuing. > Speak to sales before building a full API integration, because some functionality could change. --- # Source: https://docs.stripe.com/connect/account-capabilities.md # Account capabilities and configurations Learn about capabilities you can enable for accounts, the account configurations they belong to, and their requirements. Capabilities represent functionality that you can request for your connected accounts, such as accepting card payments or receiving transferred funds from your platform account. A capability must be active for a connected account to perform actions associated with that capability. > #### Testing capabilities > > Sandboxes and test mode might not enforce some capabilities. In certain cases, they can allow an account to perform capability-dependent actions even when the associated capability’s `status` isn’t `active`. Most capabilities require verification of certain information about the connected account’s business before Stripe enables them for that account. The capabilities you request for a connected account determine the information you’re required to collect for that account. To reduce onboarding effort, only request the capabilities that your accounts need. Requesting more capabilities means the onboarding flow must verify more information. You can start by completing the [platform profile](https://dashboard.stripe.com/connect/profile) to understand which capabilities might be appropriate for your platform. > For some capabilities, requesting them enables them permanently. Attempting to remove or unrequest a permanent capability returns an error. After creating an account, you can request additional capabilities and remove existing non-permanent capabilities. For connected accounts that [other platforms control](https://docs.stripe.com/connect/platform-controls-for-stripe-dashboard-accounts.md), you can’t unrequest capabilities. ## Supported capabilities Following is a list of available capabilities. Click an item to expand or collapse it. ### Transfers You can transfer funds to connected accounts that have the `transfers` capability. On-demand platforms often use it to pay their connected accounts. For example, a ride-hailing platform could use this capability so they can pay their drivers. The following diagram illustrates the flow of funds and the relationship between customers, the platform, and connected accounts. ![](https://b.stripecdn.com/docs-statics-srv/assets/capabilities-transfers.aced7a090e53052eb74ee8185e5919c9.svg) Relationship between customers, the platform, and connected accounts. When you use the `transfers` capability, your platform, not the connected account, processes charges. Therefore, a connected account’s customers’ bank statements display your platform’s statement descriptor, not the connected account’s. Payments using the `transfers` capability include [Destination charges](https://docs.stripe.com/connect/destination-charges.md) and [Separate charges and transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md). > Before the [2019-08-14](https://docs.stripe.com/upgrades.md#2019-08-14) API version, the `transfers` capability was referred to as `platform_payments`. If you’re using an API version older than 2019-08-14, use `platform_payments`. #### Cross-border transfers Stripe supports cross-border transfers on the payments balance between the United States, Canada, United Kingdom, EEA, and Switzerland. In other scenarios, your platform and any connected account must be in the same region. Attempting to transfer funds across unsupported borders or balances returns an error. See [Cross-border payouts](https://docs.stripe.com/connect/cross-border-payouts.md) for supported funds flows between other regions. You must only use transfers in combination with the permitted use cases for [charges](https://docs.stripe.com/connect/charges.md), [tops-ups](https://docs.stripe.com/connect/top-ups.md) and [fees](https://docs.stripe.com/connect/account-capabilities.md#collect-fees). We recommend using separate charges and transfers only when you’re responsible for negative balances of your connected accounts. ### Card payments Connected accounts with the `card_payments` capability can receive payments from your platform and directly process card and ACH payments. An e-commerce storefront with this capability, for example, can collect its own payments. The following diagram illustrates the flow of funds and the relationship between customers, connected accounts, and the platform: ![](https://b.stripecdn.com/docs-statics-srv/assets/capabilities-cardpayments.c3ef9c11049f87931c9a72e56d38559e.svg) Relationship between customers, connected accounts, and the platform. For an account to have the `card_payments` capability, you must request both `card_payments` and `transfers`. When a connected account has this capability, its customers’ bank statements display the connected account’s statement descriptor, not the platform’s. The `card_payments` capability applies to [all charge types](https://docs.stripe.com/connect/charges.md). ### US tax reporting The [US Internal Revenue Service](https://www.irs.gov/) (IRS) requires some platforms to file 1099 forms with the IRS between January and March, and to deliver the reporting of those filings to their connected accounts by January 31. To file the forms, those platforms must collect additional information from their connected accounts. > Stripe recommends that you consult a tax advisor to determine your tax filing and reporting requirements. If your platform has federal 1099 filing requirements and you decide to file through Stripe, you can use the `tax_reporting_us_1099_misc` and `tax_reporting_us_1099_k` capabilities to collect the necessary personal and business information from your connected accounts. ### 1099-MISC form Many types of payments require an IRS Form 1099-MISC, such as payments to non-employees or contractors, royalties, prizes, and so forth. The `tax_reporting_us_1099_misc` capability helps you collect the required information for Form 1099-MISC. For example, a creator platform could use the `tax_reporting_us_1099_misc` capability to [collect the necessary information](https://docs.stripe.com/connect/required-verification-information-taxes.md#required-information) from their content providers for tax filing season. ### 1099-K form A 1099-K form reports payments received from credit card transactions and third-party payment networks. Traditionally, third-party settlement organizations have used Form 1099-K to report their gross payment transactions in a calendar year. For example, an e-commerce platform uses the `tax_reporting_us_1099_k` capability to [collect the necessary tax filing information](https://docs.stripe.com/connect/required-verification-information-taxes.md#required-information) from each storefront. For more details on tax reporting for US-based connected accounts, see [Manage Tax Forms](https://docs.stripe.com/connect/tax-reporting.md). ### Payment methods Some [payment methods](https://docs.stripe.com/payments/payment-methods/overview.md) are enabled by the `card_payments` capability, while others are enabled by their own capability. If you’re charging and then paying out, check your Dashboard to see which payment methods you can use. To enable connected accounts to accept a payment method for direct charges or charges with `on_behalf_of`, you must request that payment method’s capability for those accounts. #### Account Dashboard access - Full Stripe Dashboard For connected accounts with access to the full Stripe Dashboard, including Standard accounts, most payment method capabilities are enabled by default. Those accounts can manage their own payment method capabilities. You can also request capabilities for them by [calling the capabilities update API](https://docs.stripe.com/api/capabilities/update.md), and list an account’s enabled capabilities by [calling the accounts API](https://docs.stripe.com/api/accounts/retrieve.md). In the following table, the **All business types supported** column indicates that all business types are supported unless prohibited by Stripe. The **Additional verification requirements** column refers to requirements in addition to those for the `card_payments` capability. | Payment method and associated capability | All business types supported | Available by default | Additional verification requirements | Country availability | Accounts v2 support | | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | | [ACH Direct Debit](https://docs.stripe.com/payments/ach-direct-debit.md) `us_bank_account_ach_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/ach-direct-debit.md). | Yes; v2 capability name is `ach_debit_payments` | | [Affirm](https://docs.stripe.com/payments/affirm.md) `affirm_payments` | No, see [prohibited businesses](https://docs.stripe.com/payments/affirm.md#prohibited-and-restricted-business-categories). | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/affirm.md). | Yes | | [Afterpay Clearpay](https://docs.stripe.com/payments/afterpay-clearpay.md) `afterpay_clearpay_payments` | No, see [prohibited businesses](https://docs.stripe.com/payments/afterpay-clearpay.md#prohibited-business-categories). | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/afterpay-clearpay.md). | Yes | | [Alipay](https://docs.stripe.com/payments/alipay.md) `alipay_payments` | No, see [prohibited businesses](https://support.stripe.com/questions/alipay-prohibited-businesses). | The payment method must be activated on the Dashboard settings page. Also, request [an invite](https://docs.stripe.com/payments/alipay.md) to create charges on behalf of other accounts. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/alipay.md). | No | | [Alma](https://docs.stripe.com/payments/alma.md) `alma_payments` | No, see [prohibited businesses](https://docs.stripe.com/payments/alma.md#prohibited-business-categories). | The capability must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/alma.md). | Yes | | [Amazon Pay](https://docs.stripe.com/payments/amazon-pay.md) `amazon_pay_payments` | Yes | The capability must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/amazon-pay.md). | Yes | | [Apple Pay](https://docs.stripe.com/apple-pay.md) Available with `card_payments` | Yes | With Checkout - Yes With Payment Element—The payment method must be configured on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/connect/account-capabilities.md#apple-pay-country-availability). | Yes | | [Bacs Direct Debit](https://docs.stripe.com/payments/payment-methods/bacs-debit.md) `bacs_debit_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/payment-methods/bacs-debit.md). | Yes | | [Bancontact](https://docs.stripe.com/payments/bancontact.md) `bancontact_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/bancontact.md). | Yes | | [BECS Debit](https://docs.stripe.com/payments/au-becs-debit.md) `au_becs_debit_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/au-becs-debit.md). | Yes | | [Billie](https://docs.stripe.com/payments/billie.md) `billie_payments` | No, see [prohibited businesses](https://docs.stripe.com/payments/billie.md#prohibited-and-restricted-business-categories). | The capability must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/billie.md). | Yes | | [BLIK](https://docs.stripe.com/payments/blik.md) `blik_payments` | Yes | The payment method must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/blik.md). | Yes | | [Boleto](https://docs.stripe.com/payments/boleto.md) `boleto_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/boleto.md). | Yes | | [Canadian pre-authorized debit](https://docs.stripe.com/payments/acss-debit.md) `acss_debit_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/acss-debit.md). | Yes | | [Cartes Bancaires](https://docs.stripe.com/payments/cartes-bancaires.md) `cartes_bancaires_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/cartes-bancaires.md). | Yes | | [Cash App Pay](https://docs.stripe.com/payments/cash-app-pay.md) `cashapp_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/cash-app-pay.md). | Yes | | [EPS](https://docs.stripe.com/payments/eps.md) `eps_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/eps.md). | Yes | | [FPX](https://docs.stripe.com/payments/fpx.md) `fpx_payments` | No, only businesses with a valid business registration number. | The capability must be activated on the Dashboard settings page. | Yes | Connected account must be in a [supported country](https://docs.stripe.com/payments/fpx.md). | Yes | | [Google Pay](https://docs.stripe.com/google-pay.md) Available with `card_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/connect/account-capabilities.md#google-pay-country-availability). | Yes | | [GrabPay](https://docs.stripe.com/payments/grabpay.md) `grabpay_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/grabpay.md). | Yes | | [iDEAL](https://docs.stripe.com/payments/ideal.md) `ideal_payments` | Yes | Yes | Yes, tax ID required for sole proprietors. | Connected account must be in a [supported country](https://docs.stripe.com/payments/ideal.md). | Yes | | [JCB Japan](https://support.stripe.com/questions/integrating-jcb-payments-for-connect-platforms-and-connected-accounts) `jcb_payments` | Yes | Yes | No | Connected account must be in Japan. | Yes | | [Klarna](https://docs.stripe.com/payments/klarna.md) `klarna_payments` | No, see [prohibited businesses](https://docs.stripe.com/payments/klarna/compliance.md#prohibited-business-categories). | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/klarna.md). | Yes | | [Konbini](https://docs.stripe.com/payments/konbini.md) `konbini_payments` | No, see [prohibited businesses](https://docs.stripe.com/payments/konbini.md#prohibited-business-categories). | The payment method must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/konbini.md). | Yes | | [Link](https://docs.stripe.com/payments/link.md) `link_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/link.md). | Yes | | [MobilePay](https://docs.stripe.com/payments/mobilepay.md) `mobilepay_payments` | No, see [prohibited businesses](https://docs.stripe.com/payments/mobilepay.md#prohibited-business-categories). | The payment method must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/mobilepay.md). | Yes | | [Multibanco](https://docs.stripe.com/sources/multibanco.md) `multibanco_payments` | Yes | The payment method must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/multibanco.md). | Yes | | [OXXO](https://docs.stripe.com/payments/oxxo.md) `oxxo_payments` | Yes | Yes, on first payment attempt. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/oxxo.md). | Yes | | [P24](https://docs.stripe.com/payments/p24.md) `p24_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/p24.md). | Yes | | [Pay by Bank](https://docs.stripe.com/payments/pay-by-bank.md) `pay_by_bank_payments` | Yes | The payment method must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/pay-by-bank.md). | Yes | | [PayNow](https://docs.stripe.com/payments/paynow.md) `paynow_payments` | No, see [prohibited businesses](https://docs.stripe.com/payments/paynow.md#prohibited-business-categories). | Yes, if MCC passes the PayNow prohibited business list. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/paynow.md). | Yes | | [Pix](https://docs.stripe.com/payments/pix.md) `pix_payments` | Yes | The capability must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/pix.md). | No | | [PromptPay](https://docs.stripe.com/payments/promptpay.md) `promptpay_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/promptpay.md). | Yes | | [Revolut Pay](https://docs.stripe.com/payments/revolut-pay.md) `revolut_pay_payments` | Yes | The capability must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/revolut-pay.md). | Yes | | [Satispay](https://docs.stripe.com/payments/satispay.md) `satispay_payments` | No, see [prohibited businesses](https://docs.stripe.com/payments/satispay.md#prohibited-and-restricted-business-categories). | The capability must be activated on the Dashboard settings page. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/satispay.md). | Yes | | [SEPA Bank Transfers](https://docs.stripe.com/payments/bank-transfers.md) `sepa_bank_transfer_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/bank-transfers.md). | Yes | | [SEPA Debit](https://docs.stripe.com/payments/sepa-debit.md) `sepa_debit_payments` | Yes | Yes | Yes | Connected account must be in a [supported country](https://docs.stripe.com/payments/sepa-debit.md). | Yes | | [Stablecoin payments](https://docs.stripe.com/payments/stablecoin-payments.md) `crypto_payments` | Yes | Yes | No | Connected account must be in the US. | Yes | | [USD Bank Transfers](https://docs.stripe.com/payments/bank-transfers.md) `us_bank_transfer_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/bank-transfers.md). | Yes | | [WeChat Pay](https://docs.stripe.com/payments/wechat-pay.md) `wechat_pay_payments` | No, see [prohibited businesses](https://pay.weixin.qq.com/index.php/public/wechatpay_en/proper_rule). | The payment method must be activated on the Dashboard settings page. Also, request [an invite](https://docs.stripe.com/payments/wechat-pay.md) to create charges on behalf of other accounts. | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/wechat-pay.md). | No | #### Account Dashboard access - Express or other Dashboard For connected accounts that don’t have access to the full Stripe Dashboard, which includes Express and Custom accounts, you must request payment method capabilities for those accounts. Some capabilities have business type restrictions, country restrictions, or additional information requirements for sole proprietors. In the following table, the **All business types supported** column indicates that all business types are supported unless prohibited by Stripe. The **Additional verification requirements** column refers to requirements in addition to those for the `card_payments` capability. | Payment method and associated capability | Generally available | All business types supported | Additional verification requirements | Country availability | Accounts v2 support | | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | | [ACH Direct Debit](https://docs.stripe.com/payments/ach-direct-debit.md) `us_bank_account_ach_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/ach-direct-debit.md). | Yes; v2 capability name is `ach_debit_payments` | | [Affirm](https://docs.stripe.com/payments/affirm.md) `affirm_payments` | Yes | No, see [prohibited businesses](https://support.stripe.com/questions/affirm-prohibited-businesses). | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/affirm.md). | Yes | | [Afterpay Clearpay](https://docs.stripe.com/payments/afterpay-clearpay.md) `afterpay_clearpay_payments` | Yes | No, see [prohibited businesses](https://docs.stripe.com/payments/afterpay-clearpay.md#prohibited-business-categories). | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/afterpay-clearpay.md). | Yes | | [Alipay](https://docs.stripe.com/payments/alipay.md) `alipay_payments` | No, request [an invite](https://docs.stripe.com/payments/alipay.md) to create charges on behalf of other accounts. | No, see [prohibited businesses](https://support.stripe.com/questions/alipay-prohibited-businesses). | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/alipay.md). | No | | [Apple Pay](https://docs.stripe.com/apple-pay.md) Available with `card_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/connect/account-capabilities.md#apple-pay-country-availability). | Yes | | [Bacs Direct Debit](https://docs.stripe.com/payments/payment-methods/bacs-debit.md) `bacs_debit_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/payment-methods/bacs-debit.md). | Yes | | [Bancontact](https://docs.stripe.com/payments/bancontact.md) `bancontact_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/bancontact.md). | Yes | | [BECS Debit](https://docs.stripe.com/payments/au-becs-debit.md) `au_becs_debit_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/au-becs-debit.md). | Yes | | [BLIK](https://docs.stripe.com/payments/blik.md) `blik_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/blik.md). | Yes | | [Canadian pre-authorized debit](https://docs.stripe.com/payments/acss-debit.md) `acss_debit_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/acss-debit.md). | Yes | | [Cartes Bancaires](https://docs.stripe.com/payments/cartes-bancaires.md) `cartes_bancaires_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/cartes-bancaires.md). | Yes | | [Cash App Pay](https://docs.stripe.com/payments/cash-app-pay.md) `cashapp_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/cash-app-pay.md). | Yes | | [EPS](https://docs.stripe.com/payments/eps.md) `eps_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/eps.md). | Yes | | [FPX](https://docs.stripe.com/payments/fpx.md) `fpx_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/fpx.md). | Yes | | [Google Pay](https://docs.stripe.com/google-pay.md) Available with `card_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/google-pay.md). | Yes | | [GrabPay](https://docs.stripe.com/payments/grabpay.md) `grabpay_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/grabpay.md). | Yes | | [iDEAL](https://docs.stripe.com/payments/ideal.md) `ideal_payments` | Yes | Yes | Yes, tax ID required for sole proprietors. | Connected account must be in a [supported country](https://docs.stripe.com/payments/ideal.md). | Yes | | [JCB Japan](https://support.stripe.com/questions/integrating-jcb-payments-for-connect-platforms-and-connected-accounts) `jcb_payments` | Yes | Yes | No | Connected account must be in Japan. | Yes | | [Klarna](https://docs.stripe.com/payments/klarna.md) `klarna_payments` | Yes | No, see [prohibited businesses](https://stripe.com/klarna/legal#restricted-business). | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/klarna.md). | Yes | | [Link](https://docs.stripe.com/payments/link.md) `link_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/link.md). | Yes | | Meta Pay `meta_pay_payments` | No | No | No | Connected account must be in the US. | No | | [MobilePay](https://docs.stripe.com/payments/mobilepay.md) `mobilepay_payments` | Yes | No, see [prohibited businesses](https://docs.stripe.com/payments/mobilepay.md#prohibited-business-categories). | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/mobilepay.md). | Yes | | [Multibanco](https://docs.stripe.com/sources/multibanco.md) `multibanco_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/multibanco.md). | Yes | | [OXXO](https://docs.stripe.com/payments/oxxo.md) `oxxo_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/oxxo.md). | Yes | | [P24](https://docs.stripe.com/payments/p24.md) `p24_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/p24.md). | Yes | | [Pay by Bank](https://docs.stripe.com/payments/pay-by-bank.md) `pay_by_bank_payments` | No | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/pay-by-bank.md). | Yes | | [PayNow](https://docs.stripe.com/payments/paynow.md) `paynow_payments` | Yes | No, see [prohibited businesses](https://docs.stripe.com/payments/paynow.md#prohibited-business-categories). | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/paynow.md). | Yes | | [Pix](https://docs.stripe.com/payments/pix.md) `pix_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/pix.md). | No | | [PromptPay](https://docs.stripe.com/payments/promptpay.md) `promptpay_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/promptpay.md). | Yes | | [SEPA Bank Transfers](https://docs.stripe.com/payments/bank-transfers.md) `sepa_bank_transfer_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/bank-transfers.md). | Yes | | [SEPA Debit](https://docs.stripe.com/payments/sepa-debit.md) `sepa_debit_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/sepa-debit.md). | Yes | | [Stablecoin payments](https://docs.stripe.com/payments/stablecoin-payments.md) `crypto_payments` | Yes | Yes | No | Connected account must be in the US. | Yes | | [USD Bank Transfers](https://docs.stripe.com/payments/bank-transfers.md) `us_bank_transfer_payments` | Yes | Yes | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/bank-transfers.md). | Yes | | [WeChat Pay](https://docs.stripe.com/payments/wechat-pay.md) `wechat_pay_payments` | No, request [an invite](https://docs.stripe.com/payments/wechat-pay.md) to create charges on behalf of other accounts. | No, see [prohibited businesses](https://pay.weixin.qq.com/index.php/public/wechatpay_en/proper_rule). | No | Connected account must be in a [supported country](https://docs.stripe.com/payments/wechat-pay.md). | No | Learn more about [payment method support for Connect](https://docs.stripe.com/payments/payment-methods/payment-method-connect-support.md). - AE - AT - AU - BE - BG - BR - CA - CH - CY - CZ - DE - DK - EE - ES - FI - FR - GB - GI - GR - HK - HR - HU - IE - IT - JP - LI - LT - LU - LV - MT - MX - NL - NO - NZ - PL - PT - RO - SE - SG - SI - SK - TH - US - AE - AT - AU - BE - BG - BR - CA - CH - CZ - DE - DK - EE - ES - FI - FR - GB - GI - GR - HK - HR - HU - IE - IT - JP - LI - LT - LU - LV - MX - MY - NL - NO - NZ - PL - PT - RO - SE - SG - SK - TH - US ### India international payments You must request the capability to support transactions from buyers located outside of India who use a currency different than INR. Complete the following during your onboarding process to enable international payments: 1. **Specify a transaction purpose code**. The `export_purpose_code` field describes the nature of a payment received in foreign currency. The complete list of transaction purpose codes is maintained by Reserve Bank of India (RBI). You can find the subset of transaction purpose codes that are supported by Stripe in the [Transaction Purpose Code Listing](https://docs.stripe.com/india-accept-international-payments.md#TransactionPurposeCode). 1. **Specify your importer/exporter code (IEC)**. The `export_license_id` field holds the value for the IEC code. This code is issued by the Indian Director General of Foreign Trade (DGFT) to India. You can apply for an IEC at the [DGFT website](https://dgft.gov.in/CP/). An IEC is required under certain conditions. - If you plan to accept Visa or Mastercard, an IEC is required only if you sell physical goods. Your `export_purpose_code` is for physical goods. - If you plan to accept [AMEX international payments](https://support.stripe.com/questions/american-express-card-support-for-india-based-businesses) for all export transactions, including selling physical goods and services. This is described by India’s Foreign Trade Policy. For more details, see [Accept International Payments from India](https://docs.stripe.com/india-accept-international-payments.md) ## Multiple capabilities Requesting multiple capabilities for a connected account is common, but involves the following considerations: - Capabilities operate independently of each other. - If a connected account has both `card_payments` and `transfers`, and the `status` of either one is `inactive`, then both capabilities are disabled. - You can request or unrequest most capabilities for a connected account at any time during the account’s lifecycle. Capabilities also allow you to collect information for multiple purposes at the same time. For example, you can collect both required tax information and the information required for a requested capability. ## Request capabilities for an Account Capabilities are set on the [Account](https://docs.stripe.com/api/accounts/object.md) object. To get the list of available capabilities for an Account, use the [list_capabilities](https://docs.stripe.com/api/capabilities/list.md?lang=curl) endpoint. Account creation and requesting capabilities differ for connected accounts in different configurations. - For connected accounts with access to the full Stripe Dashboard, including Standard accounts, some capabilities are requested automatically, based on their country. You can also request other capabilities for them. - For connected accounts with access to the Express Dashboard, including Express accounts, you can either request their capabilities or use the [onboarding configuration settings](https://dashboard.stripe.com/settings/connect/onboarding-options/countries) to automate capability requests. - For connected accounts without access to a Stripe-hosted Dashboard, including Custom accounts, you must request their capabilities. #### Typed Accounts ```curl curl https://api.stripe.com/v1/accounts \ -u "<>:" \ -d country=US \ -d type=custom \ -d "capabilities[card_payments][requested]"=true \ -d "capabilities[transfers][requested]"=true ``` ```cli stripe accounts create \ --country=US \ --type=custom \ -d "capabilities[card_payments][requested]"=true \ -d "capabilities[transfers][requested]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.accounts.create({ country: 'US', type: 'custom', capabilities: { card_payments: {requested: true}, transfers: {requested: true}, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.accounts.create({ "country": "US", "type": "custom", "capabilities": { "card_payments": {"requested": True}, "transfers": {"requested": True}, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->accounts->create([ 'country' => 'US', 'type' => 'custom', 'capabilities' => [ 'card_payments' => ['requested' => true], 'transfers' => ['requested' => true], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountCreateParams params = AccountCreateParams.builder() .setCountry("US") .setType(AccountCreateParams.Type.CUSTOM) .setCapabilities( AccountCreateParams.Capabilities.builder() .setCardPayments( AccountCreateParams.Capabilities.CardPayments.builder() .setRequested(true) .build() ) .setTransfers( AccountCreateParams.Capabilities.Transfers.builder().setRequested(true).build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().accounts().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.accounts.create({ country: 'US', type: 'custom', capabilities: { card_payments: { requested: true, }, transfers: { requested: true, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.AccountCreateParams{ Country: stripe.String("US"), Type: stripe.String(stripe.AccountTypeCustom), Capabilities: &stripe.AccountCreateCapabilitiesParams{ CardPayments: &stripe.AccountCreateCapabilitiesCardPaymentsParams{ Requested: stripe.Bool(true), }, Transfers: &stripe.AccountCreateCapabilitiesTransfersParams{ Requested: stripe.Bool(true), }, }, } result, err := sc.V1Accounts.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new AccountCreateOptions { Country = "US", Type = "custom", Capabilities = new AccountCapabilitiesOptions { CardPayments = new AccountCapabilitiesCardPaymentsOptions { Requested = true }, Transfers = new AccountCapabilitiesTransfersOptions { Requested = true }, }, }; var client = new StripeClient("<>"); var service = client.V1.Accounts; Account account = service.Create(options); ``` #### Controller properties ```curl curl https://api.stripe.com/v1/accounts \ -u "<>:" \ -d "controller[fees][payer]"=application \ -d "controller[losses][payments]"=application \ -d "controller[stripe_dashboard][type]"=none \ -d "controller[requirement_collection]"=application \ -d country=US \ -d "capabilities[card_payments][requested]"=true \ -d "capabilities[transfers][requested]"=true ``` ```cli stripe accounts create \ -d "controller[fees][payer]"=application \ -d "controller[losses][payments]"=application \ -d "controller[stripe_dashboard][type]"=none \ -d "controller[requirement_collection]"=application \ --country=US \ -d "capabilities[card_payments][requested]"=true \ -d "capabilities[transfers][requested]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.accounts.create({ controller: { fees: {payer: 'application'}, losses: {payments: 'application'}, stripe_dashboard: {type: 'none'}, requirement_collection: 'application', }, country: 'US', capabilities: { card_payments: {requested: true}, transfers: {requested: true}, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.accounts.create({ "controller": { "fees": {"payer": "application"}, "losses": {"payments": "application"}, "stripe_dashboard": {"type": "none"}, "requirement_collection": "application", }, "country": "US", "capabilities": { "card_payments": {"requested": True}, "transfers": {"requested": True}, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->accounts->create([ 'controller' => [ 'fees' => ['payer' => 'application'], 'losses' => ['payments' => 'application'], 'stripe_dashboard' => ['type' => 'none'], 'requirement_collection' => 'application', ], 'country' => 'US', 'capabilities' => [ 'card_payments' => ['requested' => true], 'transfers' => ['requested' => true], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountCreateParams params = AccountCreateParams.builder() .setController( AccountCreateParams.Controller.builder() .setFees( AccountCreateParams.Controller.Fees.builder() .setPayer(AccountCreateParams.Controller.Fees.Payer.APPLICATION) .build() ) .setLosses( AccountCreateParams.Controller.Losses.builder() .setPayments(AccountCreateParams.Controller.Losses.Payments.APPLICATION) .build() ) .setStripeDashboard( AccountCreateParams.Controller.StripeDashboard.builder() .setType(AccountCreateParams.Controller.StripeDashboard.Type.NONE) .build() ) .setRequirementCollection( AccountCreateParams.Controller.RequirementCollection.APPLICATION ) .build() ) .setCountry("US") .setCapabilities( AccountCreateParams.Capabilities.builder() .setCardPayments( AccountCreateParams.Capabilities.CardPayments.builder() .setRequested(true) .build() ) .setTransfers( AccountCreateParams.Capabilities.Transfers.builder().setRequested(true).build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().accounts().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.accounts.create({ controller: { fees: { payer: 'application', }, losses: { payments: 'application', }, stripe_dashboard: { type: 'none', }, requirement_collection: 'application', }, country: 'US', capabilities: { card_payments: { requested: true, }, transfers: { requested: true, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.AccountCreateParams{ Controller: &stripe.AccountCreateControllerParams{ Fees: &stripe.AccountCreateControllerFeesParams{ Payer: stripe.String(stripe.AccountControllerFeesPayerApplication), }, Losses: &stripe.AccountCreateControllerLossesParams{ Payments: stripe.String(stripe.AccountControllerLossesPaymentsApplication), }, StripeDashboard: &stripe.AccountCreateControllerStripeDashboardParams{ Type: stripe.String(stripe.AccountControllerStripeDashboardTypeNone), }, RequirementCollection: stripe.String(stripe.AccountControllerRequirementCollectionApplication), }, Country: stripe.String("US"), Capabilities: &stripe.AccountCreateCapabilitiesParams{ CardPayments: &stripe.AccountCreateCapabilitiesCardPaymentsParams{ Requested: stripe.Bool(true), }, Transfers: &stripe.AccountCreateCapabilitiesTransfersParams{ Requested: stripe.Bool(true), }, }, } result, err := sc.V1Accounts.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new AccountCreateOptions { Controller = new AccountControllerOptions { Fees = new AccountControllerFeesOptions { Payer = "application" }, Losses = new AccountControllerLossesOptions { Payments = "application" }, StripeDashboard = new AccountControllerStripeDashboardOptions { Type = "none" }, RequirementCollection = "application", }, Country = "US", Capabilities = new AccountCapabilitiesOptions { CardPayments = new AccountCapabilitiesCardPaymentsOptions { Requested = true }, Transfers = new AccountCapabilitiesTransfersOptions { Requested = true }, }, }; var client = new StripeClient("<>"); var service = client.V1.Accounts; Account account = service.Create(options); ``` Information requirements vary depending on the capability, but they often relate to identity verification or other information specific to a payment type. When your connected account is successfully created, you can [retrieve a list](https://docs.stripe.com/api/accounts/retrieve.md) of its requirements: ```curl curl https://api.stripe.com/v1/accounts/{{CONNECTEDACCOUNT_ID}} \ -u "<>:" ``` ```cli stripe accounts retrieve {{CONNECTEDACCOUNT_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.accounts.retrieve('{{CONNECTEDACCOUNT_ID}}') ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.accounts.retrieve("{{CONNECTEDACCOUNT_ID}}") ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->accounts->retrieve('{{CONNECTEDACCOUNT_ID}}', []); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountRetrieveParams params = AccountRetrieveParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().accounts().retrieve("{{CONNECTEDACCOUNT_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.accounts.retrieve('{{CONNECTEDACCOUNT_ID}}'); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.AccountRetrieveParams{} result, err := sc.V1Accounts.GetByID( context.TODO(), "{{CONNECTEDACCOUNT_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.Accounts; Account account = service.Get("{{CONNECTEDACCOUNT_ID}}"); ``` In the response, the `requirements` hash specifies the required information. The values for `payouts_enabled` and `charges_enabled` indicate whether payouts and charges are enabled for the account. ## Capabilities for existing connected accounts The following sections describe how to preview information requirements or manage capabilities for existing connected accounts using the [Capabilities API](https://docs.stripe.com/api/capabilities.md). ### Preview information requirements You can preview what information is needed from your connected account for a particular capability either before or after that capability has been requested. When you request capabilities, `account.updated` *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) fire and the account’s requirements can change. To enable a requirement faster and avoid disabling the account, preview the requirements and collect any required information before requesting the capability. The following example [lists](https://docs.stripe.com/api/capabilities/retrieve.md) the requirements for the `card_payments` capability for a specific account. ```curl curl https://api.stripe.com/v1/accounts/{{CONNECTEDACCOUNT_ID}}/capabilities/card_payments \ -u "<>:" ``` ```cli stripe capabilities retrieve {{CONNECTEDACCOUNT_ID}} card_payments ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") capability = client.v1.accounts.capabilities.retrieve( '{{CONNECTEDACCOUNT_ID}}', 'card_payments', ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. capability = client.v1.accounts.capabilities.retrieve( "{{CONNECTEDACCOUNT_ID}}", "card_payments", ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $capability = $stripe->accounts->retrieveCapability( '{{CONNECTEDACCOUNT_ID}}', 'card_payments', [] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountCapabilityRetrieveParams params = AccountCapabilityRetrieveParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Capability capability = client.v1().accounts().capabilities().retrieve( "{{CONNECTEDACCOUNT_ID}}", "card_payments", params ); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const capability = await stripe.accounts.retrieveCapability( '{{CONNECTEDACCOUNT_ID}}', 'card_payments' ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CapabilityRetrieveParams{ Account: stripe.String("{{CONNECTEDACCOUNT_ID}}"), } result, err := sc.V1Capabilities.Retrieve(context.TODO(), "card_payments", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.Accounts.Capabilities; Capability capability = service.Get("{{CONNECTEDACCOUNT_ID}}", "card_payments"); ``` In the response, check the `requirements` hash to see what information is needed: ```json { "id": "card_payments", "object": "capability", "account": ""{{CONNECTED_ACCOUNT_ID}}"", "requested": false, "requested_at": null, "requirements": { "past_due": [], "currently_due": ["company.tax_id", ...], "eventually_due": [...], "disabled_reason": ..., "current_deadline": ..., }, "status": "unrequested" } ``` The value for `status` identifies whether the capability has been requested. When the value is [requested](https://docs.stripe.com/connect/account-capabilities.md#requesting-unrequesting), the account’s requirements are active. In addition to previewing a capability’s requirements before requesting it, you can use the same endpoint to view a capability’s current requirements. That can help you stay informed when requirements change. ### Request and unrequest capabilities To request a capability for an account, set the capability’s `requested` value to `true` by [updating the account](https://docs.stripe.com/api/capabilities/update.md). If the request succeeds, the API returns `requested: true` in the response. To unrequest a capability for an account, set the capability’s `requested` value to `false` by [updating the account](https://docs.stripe.com/api/capabilities/update.md). If the capability can’t be removed, the call returns an error. If the call succeeds, the API returns `requested: false` in the response. You can also [request and remove an account’s capabilities](https://docs.stripe.com/connect/dashboard/managing-individual-accounts.md#updating-capabilities) from the Dashboard. If a capability can’t be removed, its **Remove** button is disabled. The example below requests the `transfers` capability for a specific connected account: ```curl curl https://api.stripe.com/v1/accounts/{{CONNECTEDACCOUNT_ID}}/capabilities/transfers \ -u "<>:" \ -d requested=true ``` ```cli stripe capabilities update {{CONNECTEDACCOUNT_ID}} transfers \ --requested=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") capability = client.v1.accounts.capabilities.update( '{{CONNECTEDACCOUNT_ID}}', 'transfers', {requested: true}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. capability = client.v1.accounts.capabilities.update( "{{CONNECTEDACCOUNT_ID}}", "transfers", {"requested": True}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $capability = $stripe->accounts->updateCapability( '{{CONNECTEDACCOUNT_ID}}', 'transfers', ['requested' => true] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountCapabilityUpdateParams params = AccountCapabilityUpdateParams.builder().setRequested(true).build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Capability capability = client.v1().accounts().capabilities().update( "{{CONNECTEDACCOUNT_ID}}", "transfers", params ); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const capability = await stripe.accounts.updateCapability( '{{CONNECTEDACCOUNT_ID}}', 'transfers', { requested: true, } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CapabilityUpdateParams{ Requested: stripe.Bool(true), Account: stripe.String("{{CONNECTEDACCOUNT_ID}}"), } result, err := sc.V1Capabilities.Update(context.TODO(), "transfers", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new AccountCapabilityUpdateOptions { Requested = true }; var client = new StripeClient("<>"); var service = client.V1.Accounts.Capabilities; Capability capability = service.Update( "{{CONNECTEDACCOUNT_ID}}", "transfers", options); ``` The example below requests multiple capabilities for a specific connected account: ```curl curl https://api.stripe.com/v1/accounts/{{CONNECTEDACCOUNT_ID}} \ -u "<>:" \ -d "capabilities[bancontact_payments][requested]"=true \ -d "capabilities[eps_payments][requested]"=true \ -d "capabilities[ideal_payments][requested]"=true \ -d "capabilities[p24_payments][requested]"=true \ -d "capabilities[sepa_debit_payments][requested]"=true ``` ```cli stripe accounts update {{CONNECTEDACCOUNT_ID}} \ -d "capabilities[bancontact_payments][requested]"=true \ -d "capabilities[eps_payments][requested]"=true \ -d "capabilities[ideal_payments][requested]"=true \ -d "capabilities[p24_payments][requested]"=true \ -d "capabilities[sepa_debit_payments][requested]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.accounts.update( '{{CONNECTEDACCOUNT_ID}}', { capabilities: { bancontact_payments: {requested: true}, eps_payments: {requested: true}, ideal_payments: {requested: true}, p24_payments: {requested: true}, sepa_debit_payments: {requested: true}, }, }, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.accounts.update( "{{CONNECTEDACCOUNT_ID}}", { "capabilities": { "bancontact_payments": {"requested": True}, "eps_payments": {"requested": True}, "ideal_payments": {"requested": True}, "p24_payments": {"requested": True}, "sepa_debit_payments": {"requested": True}, }, }, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->accounts->update( '{{CONNECTEDACCOUNT_ID}}', [ 'capabilities' => [ 'bancontact_payments' => ['requested' => true], 'eps_payments' => ['requested' => true], 'ideal_payments' => ['requested' => true], 'p24_payments' => ['requested' => true], 'sepa_debit_payments' => ['requested' => true], ], ] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountUpdateParams params = AccountUpdateParams.builder() .setCapabilities( AccountUpdateParams.Capabilities.builder() .setBancontactPayments( AccountUpdateParams.Capabilities.BancontactPayments.builder() .setRequested(true) .build() ) .setEpsPayments( AccountUpdateParams.Capabilities.EpsPayments.builder() .setRequested(true) .build() ) .setIdealPayments( AccountUpdateParams.Capabilities.IdealPayments.builder() .setRequested(true) .build() ) .setP24Payments( AccountUpdateParams.Capabilities.P24Payments.builder() .setRequested(true) .build() ) .setSepaDebitPayments( AccountUpdateParams.Capabilities.SepaDebitPayments.builder() .setRequested(true) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().accounts().update("{{CONNECTEDACCOUNT_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.accounts.update( '{{CONNECTEDACCOUNT_ID}}', { capabilities: { bancontact_payments: { requested: true, }, eps_payments: { requested: true, }, ideal_payments: { requested: true, }, p24_payments: { requested: true, }, sepa_debit_payments: { requested: true, }, }, } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.AccountUpdateParams{ Capabilities: &stripe.AccountUpdateCapabilitiesParams{ BancontactPayments: &stripe.AccountUpdateCapabilitiesBancontactPaymentsParams{ Requested: stripe.Bool(true), }, EPSPayments: &stripe.AccountUpdateCapabilitiesEPSPaymentsParams{ Requested: stripe.Bool(true), }, IDEALPayments: &stripe.AccountUpdateCapabilitiesIDEALPaymentsParams{ Requested: stripe.Bool(true), }, P24Payments: &stripe.AccountUpdateCapabilitiesP24PaymentsParams{ Requested: stripe.Bool(true), }, SEPADebitPayments: &stripe.AccountUpdateCapabilitiesSEPADebitPaymentsParams{ Requested: stripe.Bool(true), }, }, } result, err := sc.V1Accounts.Update( context.TODO(), "{{CONNECTEDACCOUNT_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new AccountUpdateOptions { Capabilities = new AccountCapabilitiesOptions { BancontactPayments = new AccountCapabilitiesBancontactPaymentsOptions { Requested = true, }, EpsPayments = new AccountCapabilitiesEpsPaymentsOptions { Requested = true }, IdealPayments = new AccountCapabilitiesIdealPaymentsOptions { Requested = true }, P24Payments = new AccountCapabilitiesP24PaymentsOptions { Requested = true }, SepaDebitPayments = new AccountCapabilitiesSepaDebitPaymentsOptions { Requested = true, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Accounts; Account account = service.Update("{{CONNECTEDACCOUNT_ID}}", options); ``` ## Deprecated capabilities Capabilities described in the following sections are deprecated. If possible, don’t request them for new accounts. If you have existing accounts that use deprecated capabilities, we recommend that you update them to use other capabilities instead. ### legacy_payments The `legacy_payments` capability enables charges, payouts, and transfers. Newer accounts enable those actions using the `card_payments` and `transfers` capabilities, which support more flexible configurations. We recommend that you take the following steps: 1. Update your connected account onboarding process to request the appropriate combination of `card_payments` and `transfers` instead of `legacy_payments`. 1. Update your existing connected accounts to request the appropriate combination of `card_payments` and `transfers`. 1. Update any code that checks the status of `legacy_payments` to check the status of either `legacy_payments` or the appropriate new capability. For example, update code that relies on an account’s ability to make card payments to run when either `legacy_payments` or `card_payments` is active. Similarly, update code that relies on an account’s ability to accept transfers to run when either `legacy_payments` or `transfers` is active. The updated code works throughout the process of transitioning to the new capabilities, regardless of when the new capabilities become active. 1. After the new capabilities are active for all of your connected accounts, remove references to `legacy_payments` from your code. > You can’t unrequest the `legacy_payments` capability. Stripe will notify you in advance before we remove it. If you do business in Canada, Stripe automatically requests `card_payments` and `transfers` for your accounts that use `legacy_payments`, to comply with [updated requirements](https://docs.stripe.com/connect/upcoming-requirements-updates.md?program=ca-2023). During the process, you might see the following values in your connected accounts’ API responses. | Before requesting new capabilities | New capabilities requested | New requirements completed | | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ``` capabilities: { legacy_payments: "active" }, charges_enabled: true, payouts_enabled: true ``` | ``` capabilities: { card_payments: "inactive", legacy_payments: "active", transfers: "inactive" }, charges_enabled: true, payouts_enabled: true ``` | ``` capabilities: { card_payments: "active", legacy_payments: "active", transfers: "active" }, charges_enabled: true, payouts_enabled: true ``` | > During the transition, `card_payments` and `transfers` requirements might appear in `past_due`. However, if `legacy_payments` is active, then charges, transfers, and payouts remain enabled. ## See also - [Create a charge](https://docs.stripe.com/connect/charges.md) --- # Source: https://docs.stripe.com/invoicing/taxes/account-tax-ids.md # Account tax IDs Store and render your tax IDs with Stripe Invoicing. Need another tax ID type? Request additional tax ID types by emailing [Stripe support](https://support.stripe.com/contact?subject=Request). Displaying your tax IDs on *invoice* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) documents is a common regulatory requirement. With Stripe, you can add up to 25 tax IDs to your account. Both the account and [customer tax IDs](https://docs.stripe.com/invoicing/customer/tax-ids.md) display in the header of invoice and credit note PDFs. In the [Invoice template](https://dashboard.stripe.com/settings/billing/invoice), you can: - Select default tax IDs to appear on every invoice and credit note PDF. - Define a list of tax IDs to appear on a specific invoice. > You can’t add, change, or remove account tax IDs after an invoice is finalized. ## Managing account tax IDs You can add and delete tax IDs using the [invoice settings](https://dashboard.stripe.com/settings/billing/invoice) page in the Dashboard. After you add a tax ID in the Dashboard, you can set it as the default tax ID for every invoice and credit note PDF. Tax IDs are immutable—you can’t change the country and ID after you save the tax ID to your account. Additionally, you can add and delete tax IDs with the [create](https://docs.stripe.com/api/tax_ids/create.md) and [delete](https://docs.stripe.com/api/tax_ids/delete.md) endpoints. ### Adding and removing IDs #### Dashboard Visit the [invoice settings](https://dashboard.stripe.com/settings/billing/invoice) page. Click the **Tax** tab and add a new tax ID or remove an existing tax ID: ![Manage tax IDs in the Stripe Dashboard.](https://b.stripecdn.com/docs-statics-srv/assets/manage-add.f10a7efcaf2ce75e42bc986ff3954c0b.png) Manage account tax IDs in the Dashboard #### API You can add and delete tax IDs using the tax ID [create](https://docs.stripe.com/api/tax_ids/create.md) and [delete](https://docs.stripe.com/api/tax_ids/delete.md) endpoints. > To update a tax ID, delete the old ID and create ​​another one. The following example creates a tax ID: ```curl curl https://api.stripe.com/v1/tax_ids \ -u "<>:" \ -d type=eu_vat \ -d value=DE123456789 ``` The following example deletes a tax ID: ```curl curl -X DELETE https://api.stripe.com/v1/tax_ids/txi_123 \ -u "<>:" ``` ### Setting default tax IDs On the [invoice settings](https://dashboard.stripe.com/settings/billing/invoice) page, click the **Tax** tab and locate the tax ID you want to set as the default. Click the overflow menu (⋯), select **Set as default**, and click **Save**. ![Set default tax ID in the Stripe Dashboard.](https://b.stripecdn.com/docs-statics-srv/assets/manage-default.c36bf6e90db0825b107b5b6d375396cf.png) Set default account tax ID in the Dashboard ​​After you set a tax ID as the default, you can see a label in the tax information box: ![A default tax ID in the Stripe Dashboard.](https://b.stripecdn.com/docs-statics-srv/assets/manage-default-set.a1c4d9a7605eabbe0491fb64cf031397.png) A default account tax ID in the Dashboard ## Displaying tax IDs on invoices Stripe automatically pulls your [default tax IDs](https://docs.stripe.com/invoicing/taxes/account-tax-ids.md#default-tax-ids) during invoice finalization. To override the default and display multiple tax IDs on invoices, you can set tax IDs in the Dashboard or by using the API. To learn more about taxes and invoices, see [Taxes](https://docs.stripe.com/invoicing/taxes.md). #### Dashboard You can set a list of tax IDs in the Dashboard using the Invoice Editor. ​​You can’t modify account tax IDs after an Invoice has been finalized. In the Invoice Editor, scroll down to the **Advanced Options** section. Click the checkboxes to toggle which tax IDs ​​to display on that invoice. To remove tax IDs from the invoice, uncheck the boxes. ![Tax ID invoice settings in the Stripe Dashboard](https://b.stripecdn.com/docs-statics-srv/assets/invoice-editor.1e64187379099e87ac0eb00a4a1c0e15.png) Advanced Options section in the Invoice Editor #### Customer v1 After you add a tax ID to your account, you can use the API to specify up to 25 tax IDs with the `account_tax_ids` parameter for creating [invoices](https://docs.stripe.com/api/invoices/create.md#create_invoice-account_tax_ids), [subscriptions](https://docs.stripe.com/api/subscriptions/create.md#create_subscription-invoice_settings-account_tax_ids), and [subscription schedules](https://docs.stripe.com/api/subscription_schedules/create.md#create_subscription_schedule-default_settings-invoice_settings-account_tax_ids). You must pass a list of object IDs to the `account_tax_ids` parameter. The following example sets `account_tax_ids` during invoice creation: ```curl curl https://api.stripe.com/v1/invoices \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "account_tax_ids[0]"=txi_123 \ -d "account_tax_ids[1]"=txi_456 ``` ​​You can use the update endpoints for [invoices](https://docs.stripe.com/api/invoices/update.md#update_invoice-account_tax_ids), [subscriptions](https://docs.stripe.com/api/subscriptions/update.md#update_subscription-invoice_settings-account_tax_ids), and [subscription schedules](https://docs.stripe.com/api/subscription_schedules/update.md#update_subscription_schedule-default_settings-invoice_settings-account_tax_ids) to add, change, or remove account tax IDs. The following example sets `account_tax_ids` on an existing subscription: ```curl curl https://api.stripe.com/v1/subscriptions/{{SUBSCRIPTION_ID}} \ -u "<>:" \ -d "invoice_settings[account_tax_ids][0]"=txi_123 \ -d "invoice_settings[account_tax_ids][1]"=txi_456 ``` #### Accounts v2 After you add a tax ID to your account, you can use the API to specify up to 25 tax IDs with the `account_tax_ids` parameter for creating [invoices](https://docs.stripe.com/api/invoices/create.md#create_invoice-account_tax_ids), [subscriptions](https://docs.stripe.com/api/subscriptions/create.md#create_subscription-invoice_settings-account_tax_ids), and [subscription schedules](https://docs.stripe.com/api/subscription_schedules/create.md#create_subscription_schedule-default_settings-invoice_settings-account_tax_ids). You must pass a list of object IDs to the `account_tax_ids` parameter. The following example sets `account_tax_ids` during invoice creation: ```curl curl https://api.stripe.com/v1/invoices \ -u "<>:" \ -d customer_account="{{CUSTOMERACCOUNT_ID}}" \ -d "account_tax_ids[0]"=txi_123 \ -d "account_tax_ids[1]"=txi_456 ``` ​​You can use the update endpoints for [invoices](https://docs.stripe.com/api/invoices/update.md#update_invoice-account_tax_ids), [subscriptions](https://docs.stripe.com/api/subscriptions/update.md#update_subscription-invoice_settings-account_tax_ids), and [subscription schedules](https://docs.stripe.com/api/subscription_schedules/update.md#update_subscription_schedule-default_settings-invoice_settings-account_tax_ids) to add, change, or remove account tax IDs. The following example sets `account_tax_ids` on an existing subscription: ```curl curl https://api.stripe.com/v1/subscriptions/{{SUBSCRIPTION_ID}} \ -u "<>:" \ -d "invoice_settings[account_tax_ids][0]"=txi_123 \ -d "invoice_settings[account_tax_ids][1]"=txi_456 ``` ## Supported tax ID types Currently, Stripe Invoicing supports the following tax ID types in the following regions: | Country | Enum | Description | Example | Impact in Tax Calculation* | | ------- | ---------- | ------------------------------------------------------------------------------------------------------- | --------------------- | -------------------------- | | AD | ad_nrt | Andorran NRT number | A-123456-Z | No | | AE | ae_trn | United Arab Emirates TRN | 123456789012345 | Yes | | AL | al_tin | Albania Tax Identification Number | J12345678N | Yes | | AM | am_tin | Armenia Tax Identification Number | 02538904 | Yes | | AO | ao_tin | Angola Tax Identification Number | 5123456789 | No | | AR | ar_cuit | Argentinian tax ID number | 12-3456789-01 | No | | AT | eu_vat | European VAT number | ATU12345678 | Yes | | AU | au_abn | Australian Business Number (AU ABN) | 12345678912 | Yes | | AU | au_arn | Australian Taxation Office Reference Number | 123456789123 | No | | AW | aw_tin | Aruba Tax Identification Number | 12345678 | Yes | | AZ | az_tin | Azerbaijan Tax Identification Number | 0123456789 | Yes | | BA | ba_tin | Bosnia and Herzegovina Tax Identification Number | 123456789012 | Yes | | BB | bb_tin | Barbados Tax Identification Number | 1123456789012 | No | | BD | bd_bin | Bangladesh Business Identification Number | 123456789-0123 | Yes | | BE | eu_vat | European VAT number | BE0123456789 | Yes | | BF | bf_ifu | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | 12345678A | Yes | | BG | bg_uic | Bulgaria Unified Identification Code | 123456789 | No | | BG | eu_vat | European VAT number | BG0123456789 | Yes | | BH | bh_vat | Bahraini VAT Number | 123456789012345 | Yes | | BJ | bj_ifu | Benin Tax Identification Number (Identifiant Fiscal Unique) | 1234567890123 | Yes | | BO | bo_tin | Bolivian tax ID | 123456789 | No | | BR | br_cnpj | Brazilian CNPJ number | 01.234.456/5432-10 | No | | BR | br_cpf | Brazilian CPF number | 123.456.789-87 | No | | BS | bs_tin | Bahamas Tax Identification Number | 123.456.789 | No | | BY | by_tin | Belarus TIN Number | 123456789 | Yes | | CA | ca_bn | Canadian BN | 123456789 | No | | CA | ca_gst_hst | Canadian GST/HST number | 123456789RT0002 | Yes | | CA | ca_pst_bc | Canadian PST number (British Columbia) | PST-1234-5678 | No | | CA | ca_pst_mb | Canadian PST number (Manitoba) | 123456-7 | No | | CA | ca_pst_sk | Canadian PST number (Saskatchewan) | 1234567 | No | | CA | ca_qst | Canadian QST number (Québec) | 1234567890TQ1234 | Yes | | CD | cd_nif | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | A0123456M | No | | CH | ch_uid | Switzerland UID number | CHE-123.456.789 HR | No | | CH | ch_vat | Switzerland VAT number | CHE-123.456.789 MWST | Yes | | CL | cl_tin | Chilean TIN | 12.345.678-K | Yes | | CM | cm_niu | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | M123456789000L | No | | CN | cn_tin | Chinese tax ID | 123456789012345678 | No | | CO | co_nit | Colombian NIT number | 123.456.789-0 | No | | CR | cr_tin | Costa Rican tax ID | 1-234-567890 | No | | CV | cv_nif | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | 213456789 | No | | CY | eu_vat | European VAT number | CY12345678Z | Yes | | CZ | eu_vat | European VAT number | CZ1234567890 | Yes | | DE | de_stn | German Tax Number (Steuernummer) | 1234567890 | No | | DE | eu_vat | European VAT number | DE123456789 | Yes | | DK | eu_vat | European VAT number | DK12345678 | Yes | | DO | do_rcn | Dominican RCN number | 123-4567890-1 | No | | EC | ec_ruc | Ecuadorian RUC number | 1234567890001 | No | | EE | eu_vat | European VAT number | EE123456789 | Yes | | EG | eg_tin | Egyptian Tax Identification Number | 123456789 | Yes | | ES | es_cif | Spanish NIF number (previously Spanish CIF number) | A12345678 | No | | ES | eu_vat | European VAT number | ESA1234567Z | Yes | | ET | et_tin | Ethiopia Tax Identification Number | 1234567890 | Yes | | EU | eu_oss_vat | European One Stop Shop VAT number for non-Union scheme | EU123456789 | No | | FI | eu_vat | European VAT number | FI12345678 | Yes | | FR | eu_vat | European VAT number | FRAB123456789 | Yes | | GB | eu_vat | Northern Ireland VAT number | XI123456789 | Yes | | GB | gb_vat | United Kingdom VAT number | GB123456789 | Yes | | GE | ge_vat | Georgian VAT | 123456789 | Yes | | GN | gn_nif | Guinea Tax Identification Number (Número de Identificação Fiscal) | 123456789 | Yes | | GR | eu_vat | European VAT number | EL123456789 | Yes | | HK | hk_br | Hong Kong BR number | 12345678 | No | | HR | eu_vat | European VAT number | HR12345678912 | Yes | | HR | hr_oib | Croatian Personal Identification Number | 12345678901 | No | | HU | eu_vat | European VAT number | HU12345678 | Yes | | HU | hu_tin | Hungary tax number (adószám) | 12345678-1-23 | No | | ID | id_npwp | Indonesian NPWP number | 012.345.678.9-012.345 | No | | IE | eu_vat | European VAT number | IE1234567AB | Yes | | IL | il_vat | Israel VAT | 000012345 | No | | IN | in_gst | Indian GST number | 12ABCDE3456FGZH | Yes | | IS | is_vat | Icelandic VAT | 123456 | Yes | | IT | eu_vat | European VAT number | IT12345678912 | Yes | | JP | jp_cn | Japanese Corporate Number (*Hōjin Bangō*) | 1234567891234 | No | | JP | jp_rn | Japanese Registered Foreign Businesses' Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | 12345 | No | | JP | jp_trn | Japanese Tax Registration Number (*Tōroku Bangō*) | T1234567891234 | Yes | | KE | ke_pin | Kenya Revenue Authority Personal Identification Number | P000111111A | No | | KG | kg_tin | Kyrgyzstan Tax Identification Number | 12345678901234 | No | | KH | kh_tin | Cambodia Tax Identification Number | 1001-123456789 | Yes | | KR | kr_brn | Korean BRN | 123-45-67890 | Yes | | KZ | kz_bin | Kazakhstani Business Identification Number | 123456789012 | Yes | | LA | la_tin | Laos Tax Identification Number | 123456789-000 | No | | LI | li_uid | Liechtensteinian UID number | CHE123456789 | No | | LI | li_vat | Liechtensteinian VAT number | 12345 | Yes | | LT | eu_vat | European VAT number | LT123456789123 | Yes | | LU | eu_vat | European VAT number | LU12345678 | Yes | | LV | eu_vat | European VAT number | LV12345678912 | Yes | | MA | ma_vat | Morocco VAT Number | 12345678 | Yes | | MD | md_vat | Moldova VAT Number | 1234567 | Yes | | ME | me_pib | Montenegro PIB Number | 12345678 | No | | MK | mk_vat | North Macedonia VAT Number | MK1234567890123 | Yes | | MR | mr_nif | Mauritania Tax Identification Number (Número de Identificação Fiscal) | 12345678 | No | | MT | eu_vat | European VAT number | MT12345678 | Yes | | MX | mx_rfc | Mexican RFC number | ABC010203AB9 | No | | MY | my_frp | Malaysian FRP number | 12345678 | No | | MY | my_itn | Malaysian ITN | C 1234567890 | No | | MY | my_sst | Malaysian SST number | A12-3456-78912345 | No | | NG | ng_tin | Nigerian Tax Identification Number | 12345678-0001 | No | | NL | eu_vat | European VAT number | NL123456789B12 | Yes | | NO | no_vat | Norwegian VAT number | 123456789MVA | Yes | | NO | no_voec | Norwegian VAT on e-commerce number | 1234567 | No | | NP | np_pan | Nepal PAN Number | 123456789 | Yes | | NZ | nz_gst | New Zealand GST number | 123456789 | Yes | | OM | om_vat | Omani VAT Number | OM1234567890 | Yes | | PE | pe_ruc | Peruvian RUC number | 12345678901 | Yes | | PH | ph_tin | Philippines Tax Identification Number | 123456789012 | Yes | | PL | eu_vat | European VAT number | PL1234567890 | Yes | | PL | pl_nip | Polish NIP number | 1234567890 | No | | PT | eu_vat | European VAT number | PT123456789 | Yes | | RO | eu_vat | European VAT number | RO1234567891 | Yes | | RO | ro_tin | Romanian tax ID number | 1234567890123 | No | | RS | rs_pib | Serbian PIB number | 123456789 | No | | RU | ru_inn | Russian INN | 1234567891 | Yes | | RU | ru_kpp | Russian KPP | 123456789 | Yes | | SA | sa_vat | Saudi Arabia VAT | 123456789012345 | Yes | | SE | eu_vat | European VAT number | SE123456789123 | Yes | | SG | sg_gst | Singaporean GST | M12345678X | Yes | | SG | sg_uen | Singaporean UEN | 123456789F | No | | SI | eu_vat | European VAT number | SI12345678 | Yes | | SI | si_tin | Slovenia tax number (davčna številka) | 12345678 | No | | SK | eu_vat | European VAT number | SK1234567891 | Yes | | SN | sn_ninea | Senegal NINEA Number | 12345672A2 | No | | SR | sr_fin | Suriname FIN Number | 1234567890 | Yes | | SV | sv_nit | El Salvadorian NIT number | 1234-567890-123-4 | No | | TH | th_vat | Thai VAT | 1234567891234 | Yes | | TJ | tj_tin | Tajikistan Tax Identification Number | 123456789 | Yes | | TR | tr_tin | Turkish Tax Identification Number | 0123456789 | Yes | | TW | tw_vat | Taiwanese VAT | 12345678 | Yes | | TZ | tz_vat | Tanzania VAT Number | 12345678A | Yes | | UA | ua_vat | Ukrainian VAT | 123456789 | Yes | | UG | ug_tin | Uganda Tax Identification Number | 1014751879 | Yes | | US | us_ein | United States EIN | 12-3456789 | No | | UY | uy_ruc | Uruguayan RUC number | 123456789012 | Yes | | UZ | uz_tin | Uzbekistan TIN Number | 123456789 | No | | UZ | uz_vat | Uzbekistan VAT Number | 123456789012 | Yes | | VE | ve_rif | Venezuelan RIF number | A-12345678-9 | No | | VN | vn_tin | Vietnamese tax ID number | 1234567890 | No | | ZA | za_vat | South African VAT number | 4123456789 | Yes | | ZM | zm_tin | Zambia Tax Identification Number | 1004751879 | No | | ZW | zw_tin | Zimbabwe Tax Identification Number | 1234567890 | No | \*Stripe Tax won't apply tax if this tax ID is provided, in line with the relevant laws. ## See also - [Connected account tax IDs on invoices](https://docs.stripe.com/connect/invoices.md#account-tax-ids) --- # Source: https://docs.stripe.com/revenue-recognition/revenue-settings/accounting-period-control.md # Revenue Recognition accounting period control Learn how to configure accounting periods for Stripe Revenue Recognition. Accounting period control allows you to manage and customize your accounting calendar. By default, your accounting calendar and accounting periods follow calendar months. You can switch to the 4-4-5 calendar for custom accounting periods with a specified start date. You can also control how to close accounting periods. You can either manually close the books after reviewing your data and completing any adjustments each month, or you can let Stripe automate closing the books. You can also reopen past accounting periods using accounting period control. Use this method when you first start using revenue recognition because it allows you to make adjustments to past data without creating corrections in the current period. For example, when you apply [rules](https://docs.stripe.com/revenue-recognition/rules.md) to fit revenue recognition with your own business model, it’s likely to change the history of closed accounting periods. You can decide on whether to reopen the closed accounting periods or make adjustments in the current accounting period. ## Setting accounting periods You can find the accounting periods section on [the Revenue Recognition controls](https://dashboard.stripe.com/settings/revenue-recognition) page. ## Select the mode for accounting periods To get started, select the `mode` for your accounting periods. The default is `automatic`. | Mode | Descriptions | | -------------- | ----------------------------------------------------------------------- | | Calendar month | Aligns with calendar months. | | 4-4-5 | Divides the year into 4 quarters, each with 3 periods of 4, 4, 5 weeks. | ## Choose the start date in 4-4-5 mode When configuring the `4-4-5` accounting periods, you need to choose a `start date`. From this date forward, the accounting periods transition to the `4-4-5` format, while any periods prior to the `start date` continue to follow the monthly period. You can choose your desired `start date` and click the preview link to view your 4-4-5 accounting periods. For example, when you choose the `start date` of Jan 1, 2025, your accounting periods look like the following example, and your current accounting period is highlighted: ![Accounting periods controls 4-4-5 preview](https://b.stripecdn.com/docs-statics-srv/assets/accounting-period-445-calendar-preview.9c28b7401b3a0ec7c61ce49c311dcae0.png) Additionally, to accommodate leap years, we add an extra week to the last period every sixth year, ensuring that the calendar remains in alignment. ## Setting how to close accounting periods You can find the close books section on [the Revenue Recognition controls page](https://dashboard.stripe.com/settings/revenue-recognition). ## Select the mode for closing books To get started, select the `mode` for your close books. The default is `automatic`. | Mode | Descriptions | | --------- | ---------------------------------------------------------------- | | Automatic | Accounting periods automatically close at the end of each month. | | Manual | You control when to close the accounting periods. | ## Choose the latest closed accounting period in manual mode When you set `latest closed accounting period`, you close the selected accounting period along with all previous accounting periods, and you open all following periods. You can choose one of the periods in the past 24 months, and you can also choose `no closed accounting periods`. For example, when you choose the `latest closed accounting period` to be February 2025 in `manual` mode, the accounting period looks like the following example: | | | | --------------- | -------- | | Before Jan 2025 | Jan 2025 | Feb 2025 | Mar 2025 | Apr 2025 | May 2025 | Jun 2025 | | Closed | Closed | Closed | Open | Open | Open | Open | ## How accounting period and close books control works ### Manage your accounting calendar Accounting period control enables you to manage your accounting calendar by allowing you to choose between the default `monthly calendar` and the `4-4-5` accounting calendar. When you adjust the accounting period control, you can also reopen previously closed accounting periods using `close book control`. It allows you to make the adjustments without creating corrections in the current period. ### Control the closing process for your accounting period cycle The close books control allows you to configure the closing process with your own workflow for the accounting period cycle. You can choose the `manual` mode, and check all terms and fix the human errors before closing the accounting periods manually, or you can automate closing your revenue recognition book using the `automatic` mode. #### Getting started with revenue recognition If you’re new to revenue recognition, use the close books control to get started. For example, when you apply [rules](https://docs.stripe.com/revenue-recognition/rules.md) to fit revenue recognition with your own business model, you can set `manual` mode with `no closed accounting periods`. In this way, all the changes go into the original accounting periods, which can help you understand your books. You can open accounting periods after setting [revenue recognition rules](https://docs.stripe.com/revenue-recognition/rules.md), unless you need to issue corrections. In that case, you must close the accounting period before setting any rules. Adjustments for accounting periods take up to 24 hours to complete. When completed, you can see the setting in monthly summary charts and CSV-only reports in the Dashboard. For example, when you choose the `latest closed accounting period` to be February 2025 in `manual` mode, you can see it in the charts and reports. ![Revenue chart with manual mode and latest closed accounting period](https://b.stripecdn.com/docs-statics-srv/assets/accounting-period-control-revenue-chart.d6ab06169fb7d15f27f2e7cfe5a2282e.png) ![Income statement report with manual mode and latest closed accounting period](https://b.stripecdn.com/docs-statics-srv/assets/accounting-period-control-income-statement-report.da2f6a5fb6491e4e4da58c115c7089f7.png) --- # Source: https://docs.stripe.com/financial-accounts/connect/account-management/accounts-structure.md # Accounts structure Learn how the account components of Financial Accounts for platforms interact. Use this guide to understand the technical components of Financial Accounts for platforms, specifically the different account types. ## Account types Your platform must have Stripe *Connect* (Connect is Stripe's solution for multi-party businesses, such as marketplace or software platforms, to route payments between sellers, customers, and other recipients) to use Financial Accounts for platforms. In its most basic form, a Connect integration includes a platform account with many connected accounts, each owned by a seller or service provider that uses the platform. Both the platform account and its connected accounts are [Account](https://docs.stripe.com/api/accounts.md) objects in the Stripe API. > #### Accounts v2 API compatibility > > The Accounts v2 API doesn’t support Financial Accounts workflows. If you have accounts created with Accounts v2, you can use Accounts v1 to manage the `treasury` and `card_issuing` capabilities. For details, see [Use Accounts as customers](https://docs.stripe.com/connect/use-accounts-as-customers.md). Financial Accounts for platforms only supports connected accounts that don’t use a Stripe-hosted dashboard and where your platform is responsible for requirements collection and loss liability, including Custom connected accounts. Learn how to [create connected accounts](https://docs.stripe.com/connect/interactive-platform-guide.md?connect-charge-type=direct&connect-loss-liability-owner=platform) that work with Financial Accounts for platforms. As a platform with connected accounts, you’re responsible for maintaining a minimum API version, communicating terms of service updates to your connected accounts, handling information requests from them, and providing them with support. Because your platform is ultimately responsible for the losses your connected accounts incur, you’re also responsible for vetting them for fraud. To learn more, read the [Financial Accounts for platforms fraud guide](https://docs.stripe.com/financial-accounts/connect/examples/fraud-guide.md). ![Flow chart with lines connecting a platform with three different connected accounts.](https://b.stripecdn.com/docs-statics-srv/assets/connected-accounts.7443ee88f52a49904439afc21ded676e.png) A Connect platform with connected accounts Financial Accounts for platforms includes another type of Stripe account, a financial account. When you onboard your platform to Financial Accounts for platforms, Stripe automatically creates and assigns a `FinancialAccount` object to your platform account. As the platform, you request the `treasury` capability when requesting the capabilities you need for your connected accounts. After you request it, Stripe updates the connected account’s `Account` object to include additional requirements in its [requirements hash](https://docs.stripe.com/api/accounts/object.md#account_object-requirements). You can create financial accounts for your connected accounts, but until you gather the requirements from your connected account owners, the financial accounts aren’t accessible. For more information on using financial accounts, see [Working with financial accounts](https://docs.stripe.com/financial-accounts/connect/account-management/financial-accounts.md). ## Account balances Each account in Stripe Connect (both platform and connected accounts) has an [account balance](https://docs.stripe.com/connect/account-balances.md) that tracks pending and available funds for that account. With Financial Accounts for platforms, each of these accounts can also have a financial account, which has a balance of its own. You can use Financial Accounts for platforms to transfer funds between the platform account and financial account, but their respective balances always remain separate. However, you can’t transfer funds from a platform end-user’s financial account to their connected account. For more information on platform and connected account balances, see [Understanding Connect account balances](https://docs.stripe.com/connect/account-balances.md). For more information on financial account balances, see [Working with balances and transactions](https://docs.stripe.com/financial-accounts/connect/account-management/working-with-balances-and-transactions.md). ![Flow chart with a line connecting a platform account with a connected account. For each account, two lines connect both a payments account balance and a financial account balance. A double arrow with a dollar sign shows funds flow between each accounts balances and a one direction arrow with a dollar sign flow from the platform financial account balance to the connected account financial account balance.](https://b.stripecdn.com/docs-statics-srv/assets/fund-flow.6fb714d66e6c95a45f14066001c290bc.png) Flow of funds between accounts ## Flow of funds between accounts Although the payments balance and financial account balances are separate, Financial Accounts for platforms supports the flow of funds between the two. Financial Accounts for platforms also enables you to transfer funds from your platform financial account to the financial accounts attached to your platform’s connected accounts. You can use [Payouts](https://docs.stripe.com/api/payouts.md) to send funds from your payment balance to your financial account or to the financial accounts attached to your platform’s connected accounts. To move money between two financial accounts, Financial Accounts for platforms uses [OutboundPayment](https://docs.stripe.com/api/treasury/outbound_payments.md) objects. Transfers affect funds on the Stripe Account Balance, so if you want to move funds between two financial accounts, you must use OutboundPayments. --- # Source: https://docs.stripe.com/connect/accounts.md # Connect account types Learn about older connected account configurations. When using *Connect* (Connect is Stripe's solution for multi-party businesses, such as marketplace or software platforms, to route payments between sellers, customers, and other recipients), you create a *connected account* (A person or business accepting payments or receiving payouts on a Connect platform) for each business or individual that signs up to access your platform’s services. You can configure your platform and connected accounts to fit your business model, distributing specific responsibilities between your platform, Stripe, and your connected accounts. > #### Newer Connect integrations > > The information on this page applies only to platforms that already use legacy connected account types. If you’re setting up a new Connect platform, or your integration uses the Accounts v2 API, see the [Interactive platform guide](https://docs.stripe.com/connect/interactive-platform-guide.md). If your existing integration uses the Accounts v1 API, see [Design an advanced integration](https://docs.stripe.com/connect/design-an-integration.md). If your existing connected accounts are configured as a type, you can migrate your platform to support new connected accounts using [the Accounts v2 API](https://docs.stripe.com/connect/accounts-v2/migrate-integration.md) or [v1 Accounts with controller properties](https://docs.stripe.com/connect/migrate-to-controller-properties.md). During and after migration, your platform can continue to support your existing connected accounts without interruption. Connect supports the following account types: - [Standard](https://docs.stripe.com/connect/standard-accounts.md) - [Express](https://docs.stripe.com/connect/express-accounts.md) - [Custom](https://docs.stripe.com/connect/custom-accounts.md) ## Choose an account type You must consider several factors when choosing an account type. Integration effort and connected account user experience are especially important because they can affect engineering resource expenditure and conversion rates. After you create a connected account, you can’t change its type. [Extensions](https://docs.stripe.com/building-extensions.md) building on Connect must use OAuth to connect to Standard connected accounts. Stripe recommends that you [use controller properties](https://docs.stripe.com/connect/migrate-to-controller-properties.md) instead of account types. If you want to use account types, we recommend Express or Standard connected accounts because they require less integration effort. For more control over your connected accounts, consider using Custom connected accounts. To learn which account type we recommend for your business, refer to your [platform profile](https://dashboard.stripe.com/connect/settings/profile). There’s an additional cost for using Express or Custom connected accounts. | | Standard | Express | Custom | | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------- | | **Integration effort** | Lowest | Low | Significantly higher | | **Integration method** | API or OAuth | API | API | | **Fraud and dispute liability** | Connected account | Platform | Platform | | **Platform can specify payout timing?** | Yes, with [Platform controls](https://docs.stripe.com/connect/platform-controls-for-stripe-dashboard-accounts.md) | Yes | Yes | | **Onboarding** | Stripe | Stripe | Platform or Stripe | | **Identity information gathering** | Stripe | Stripe | Platform or Stripe | | **Connected account access to the Stripe Dashboard** | Full Dashboard | Express Dashboard | None | | **Supported charge types** | Direct only | - Destination - Separate with transfers - Direct | - Destination - Separate with transfers - Direct | | **Connected account support provided by** | Platform and Stripe | Platform and Stripe | Platform | | **Automatic updates for new compliance requirements** | Yes | Yes | No | | **Support new countries without integration changes** | Yes | Yes | No | | **Ideal for platforms** | With experienced online businesses as connected accounts | Any type | With significant engineering resources to dedicate to a fully white-labeled experience | With Standard connected accounts, the connected account is responsible for fraud and disputes when using [direct charges](https://docs.stripe.com/connect/charges.md#types), but that can vary when using [destination charges](https://docs.stripe.com/connect/charges.md#types). ## Express connected accounts With *Express* connected accounts, Stripe handles the onboarding and identity verification processes. The platform has the ability to specify [charge types](https://docs.stripe.com/connect/charges.md) and set the connected account’s [payout settings](https://docs.stripe.com/connect/payouts-connected-accounts.md) programmatically. The platform is responsible for handling disputes and refunds, which is similar to a Custom connected account. Although your connected account has interactions with Stripe, they primarily interact with your platform, particularly for the core payment processing functionality. For Express connected account holders, Stripe provides an Express Dashboard (a lighter version of the Dashboard) that allows them to manage their personal information and see *payouts* (A payout is the transfer of funds to an external account, usually a bank account, in the form of a deposit) to their bank. Use Express connected accounts when you: - Want to get started quickly (letting Stripe handle account onboarding, management, and identity verification) - Want to use [destination charges](https://docs.stripe.com/connect/destination-charges.md) or [separate charges and transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md) - Want significant control over interactions with your connected accounts Some examples of platforms that use Express connected accounts are home-rental marketplaces, such as Airbnb, and ride-hailing services, such as Lyft. Global compliance requirements do evolve and change over time. With Express, Stripe proactively collects information when requirements change. For best practices on how to communicate to your connected accounts when that happens, visit the [guide for Express accounts](https://support.stripe.com/questions/best-practices-for-connect-platforms-communicating-updates-to-verification-requirements-with-standard-or-express-connected-accounts). ### Express connected account availability Select one of the available countries when you create an Express connected account. You can’t change the country later. Some countries are available only when using [cross-border payouts](https://docs.stripe.com/connect/cross-border-payouts.md). To know when Express connected accounts are available in your country, [contact Stripe](connect@stripe.com). - AE - AG - AL - AM - AR - AT - AU - BA - BE - BG - BH - BJ - BN - BO - BS - BW - CA - CH - CI - CL - CO - CR - CY - CZ - DE - DK - DO - EC - EE - EG - ES - ET - FI - FR - GB - GH - GM - GR - GT - GY - HK - HU - IE - IL - IS - IT - JM - JO - JP - KE - KH - KR - KW - LC - LK - LT - LU - LV - MA - MC - MD - MG - MK - MN - MO - MT - MU - MX - NA - NG - NL - NO - NZ - OM - PA - PE - PH - PK - PL - PT - PY - QA - RO - RS - RW - SA - SE - SG - SI - SK - SN - SV - TH - TN - TR - TT - TW - TZ - US - UY - UZ - VN - ZA ## Standard connected accounts A *Standard* connected account is a conventional Stripe account where the connected account has a direct relationship with Stripe, is able to log in to the [Dashboard](https://dashboard.stripe.com), and can process charges on their own. Use Standard connected accounts when you: - Want to get started quickly and don’t need a lot of control over interactions with your connected accounts - Want to use [direct charges](https://docs.stripe.com/connect/direct-charges.md) - Have connected accounts that are familiar with running online businesses or that already have a Stripe account - Prefer that Stripe handles direct communication with the connected account for account issues (for example, to request more information for identity verification purposes) Some examples of platforms that use Standard connected accounts are store builders, such as Shopify, and Software as a Service (SaaS) platforms, such as an online invoicing and payment service. Global compliance requirements do evolve and change over time. With Standard connected accounts, Stripe proactively collects information when requirements change. For best practices on how to communicate to your connected accounts when that happens, visit the [guide for Standard accounts](https://support.stripe.com/questions/best-practices-for-connect-platforms-communicating-updates-to-verification-requirements-with-standard-or-express-connected-accounts). > #### Country can't be changed > > After you create a Standard connected account, you can’t change its country. ## Custom connected accounts A *Custom* connected account is almost completely invisible to the account holder. You—the platform—are responsible for all interactions with your connected accounts, including collecting any information Stripe needs. You have the ability to change all of the account’s [settings](https://docs.stripe.com/connect/updating-service-agreements.md), including the payout [bank or debit card account](https://docs.stripe.com/connect/payouts-connected-accounts.md), programmatically. Custom connected account holders don’t have access to the Dashboard, and Stripe doesn’t contact them directly. Use Custom connected accounts when you: - Want complete control over interactions with your connected accounts - Can build the significant infrastructure required to collect connected account information, deploy a custom dashboard, and handle support - Want to handle all communication with your connected accounts, involving no direct contact between them and Stripe Creating and managing Custom connected accounts requires a larger integration effort than the other account types. To learn more, see [Using Connect with Custom accounts](https://docs.stripe.com/connect/custom-accounts.md). Global compliance requirements do evolve and change over time. For best practices on how to communicate to your connected accounts when requirements change, see the [guide for Custom accounts](https://support.stripe.com/questions/best-practices-for-connect-platforms-communicating-updates-to-verification-requirements-with-custom-connected-accounts). If you decide to use Custom connected accounts, Stripe recommends that you use [Connect Onboarding for Custom accounts](https://docs.stripe.com/connect/custom/hosted-onboarding.md) to collect onboarding and verification information from your connected accounts. That decreases your integration effort and eliminates the need to update your onboarding form when requirements change. ### Custom connected account availability Select one of the available countries when you create a Custom connected account. You can’t change the country later. Some countries are available only when using [cross-border payouts](https://docs.stripe.com/connect/cross-border-payouts.md). To request notification when Custom connected accounts are available in your country, [contact Stripe](connect@stripe.com). - AE - AG - AL - AM - AR - AT - AU - BA - BE - BG - BH - BJ - BN - BO - BS - BW - CA - CH - CI - CL - CO - CR - CY - CZ - DE - DK - DO - EC - EE - EG - ES - ET - FI - FR - GB - GH - GM - GR - GT - GY - HK - HU - IE - IL - IS - IT - JM - JO - JP - KE - KH - KR - KW - LC - LK - LT - LU - LV - MA - MC - MD - MG - MK - MN - MO - MT - MU - MX - NA - NG - NL - NO - NZ - OM - PA - PE - PH - PK - PL - PT - PY - QA - RO - RS - RW - SA - SE - SG - SI - SK - SN - SV - TH - TN - TR - TT - TW - TZ - US - UY - UZ - VN - ZA ## See also - [Express connected accounts](https://docs.stripe.com/connect/express-accounts.md) - [Standard connected accounts](https://docs.stripe.com/connect/standard-accounts.md) - [Custom connected accounts](https://docs.stripe.com/connect/custom-accounts.md) - [Account capabilities](https://docs.stripe.com/connect/account-capabilities.md) --- # Source: https://docs.stripe.com/financial-connections/ach-direct-debit-payments.md # Collect a bank account to use ACH Direct Debit payments with account data Use account data such as balances with your payments integration. Not sure about which Financial Connections integration to use? See our [overview of integration options](https://docs.stripe.com/financial-connections/use-cases.md). Stripe offers a number of ways to accept ACH Direct Debit payments from your users. All of these methods require that you [verify](https://docs.stripe.com/payments/ach-direct-debit.md#verification) the user’s account before you can debit their account. You can use Financial Connections to perform instant bank account verification along with features such as balance or ownership checks. When using Financial Connections for your ACH flows, you can: - Reduce your payment failure rate from closed or inactive accounts - Improve payments conversion by keeping users on session, instead of forcing them to leave your payments flow to locate their accounts and routing numbers - Save development time by eliminating the need to create a custom bank account collection form - Enable the collection of additional bank account data, such as balances and ownership information ## Before you begin Financial Connections is the default verification method for all hosted ACH payment flows, such as Checkout or the Payment Element. If you use a hosted flow, skip directly to [accessing additional account data](https://docs.stripe.com/financial-connections/ach-direct-debit-payments.md#access). Set up your integration to [collect ACH payments](https://docs.stripe.com/payments/ach-direct-debit/accept-a-payment.md?platform=web&ui=stripe-hosted) if you haven’t already done so. ## Enable Financial Connections The `verification_method` parameter on various API resources controls whether Financial Connections is enabled for bank account verification. Financial Connections with microdeposit fallback is the default. > Bank accounts that your customers link through manual entry and microdeposits won’t have access to additional bank account data like balances, ownership, and transactions. | Verification method | Description | | --------------------- | ------------------------------------------------------------------------------------------------------ | | `automatic` (default) | Financial Connections with the option to manually enter bank account information and use microdeposits | | `instant` | Financial Connections only, with no manual entry and microdeposit fallback | | `microdeposits` | Manual entry and microdeposits only | This option is available on the following APIs: Additional steps, such as NACHA mandate collection, are required for businesses that don’t use a Stripe-hosted integration such as Payment Element, Checkout, or Hosted Invoicing. See [this section of the ACH guide](https://docs.stripe.com/payments/ach-direct-debit/accept-a-payment.md?platform=web&ui=direct-api#web-collect-details). - [PaymentIntent](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-payment_method_options-us_bank_account-verification_method) - [SetupIntent](https://docs.stripe.com/api/setup_intents/create.md#create_setup_intent-payment_method_options-us_bank_account-verification_method) - [CheckoutSession](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_method_options-us_bank_account-verification_method) - [Invoice](https://docs.stripe.com/api/invoices/create.md#create_invoice-payment_settings-payment_method_options-us_bank_account-verification_method) - [Subscription](https://docs.stripe.com/api/subscriptions/create.md#create_subscription-payment_settings-payment_method_options-us_bank_account-verification_method) - [Payment Element](https://docs.stripe.com/js/elements_object/create_without_intent#stripe_elements_no_intent-options-paymentMethodOptions-us_bank_account-verification_method) ## Create a customer [Recommended] We recommend that you create a *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) with an email address and phone number to represent your user, that you then attach to your payment. Attaching a `Customer` object allows you to [list previously linked accounts ](https://docs.stripe.com/api/financial_connections/accounts/list.md) later. By providing the email address and phone number on the `Customer` object, Financial Connections can improve the authentication flow by simplifying sign-in or sign-up for your user, depending on whether they’re a returning [Link](https://support.stripe.com/questions/link-for-financial-connections-support-for-businesses) user. ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ -d email={{CUSTOMER_EMAIL}} \ -d phone={{CUSTOMER_PHONE}} ``` ```cli stripe customers create \ --email={{CUSTOMER_EMAIL}} \ --phone={{CUSTOMER_PHONE}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer = client.v1.customers.create({ email: '{{CUSTOMER_EMAIL}}', phone: '{{CUSTOMER_PHONE}}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer = client.v1.customers.create({ "email": "{{CUSTOMER_EMAIL}}", "phone": "{{CUSTOMER_PHONE}}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $customer = $stripe->customers->create([ 'email' => '{{CUSTOMER_EMAIL}}', 'phone' => '{{CUSTOMER_PHONE}}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CustomerCreateParams params = CustomerCreateParams.builder() .setEmail("{{CUSTOMER_EMAIL}}") .setPhone("{{CUSTOMER_PHONE}}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Customer customer = client.v1().customers().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const customer = await stripe.customers.create({ email: '{{CUSTOMER_EMAIL}}', phone: '{{CUSTOMER_PHONE}}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerCreateParams{ Email: stripe.String("{{CUSTOMER_EMAIL}}"), Phone: stripe.String("{{CUSTOMER_PHONE}}"), } result, err := sc.V1Customers.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CustomerCreateOptions { Email = "{{CUSTOMER_EMAIL}}", Phone = "{{CUSTOMER_PHONE}}", }; var client = new StripeClient("<>"); var service = client.V1.Customers; Customer customer = service.Create(options); ``` ## Request access to additional account data To access additional account data on Financial Connections Accounts, first make sure you’ve submitted your Financial Connections application by checking [Financial Connections settings in the Dashboard](https://dashboard.stripe.com/settings/financial-connections). To view this page, activate your account. How you configure which types of account data you have access to depends on your integration. #### Dynamic payment methods If you use Stripe’s [dynamic payment method feature](https://docs.stripe.com/payments/payment-methods/dynamic-payment-methods.md) to collect ACH payments for non-Connect use cases, you can configure requested Financial Connections data directly from the [ACH Dashboard settings page](https://dashboard.stripe.com/test/settings/payment_methods). Account and routing number is always required for ACH debits—other data types are optional. > We recommend configuring permissions in the Dashboard because it allows you to change which data you collect without any code changes. To override the Dashboard configuration, specify Financial Connections permissions directly in the API. To do this for PaymentIntents: ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=2000 \ -d currency=usd \ -d customer="{{CUSTOMER_ID}}" \ -d "automatic_payment_methods[enabled]"=true \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=payment_method \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=ownership \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=transactions ``` ```cli stripe payment_intents create \ --amount=2000 \ --currency=usd \ --customer="{{CUSTOMER_ID}}" \ -d "automatic_payment_methods[enabled]"=true \ -d "payment_method_options[us_bank_account][financial_connections][permissions][0]"=payment_method \ -d "payment_method_options[us_bank_account][financial_connections][permissions][1]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][2]"=ownership \ -d "payment_method_options[us_bank_account][financial_connections][permissions][3]"=transactions ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 2000, currency: 'usd', customer: '{{CUSTOMER_ID}}', automatic_payment_methods: {enabled: true}, payment_method_options: { us_bank_account: { financial_connections: { permissions: ['payment_method', 'balances', 'ownership', 'transactions'], }, }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 2000, "currency": "usd", "customer": "{{CUSTOMER_ID}}", "automatic_payment_methods": {"enabled": True}, "payment_method_options": { "us_bank_account": { "financial_connections": { "permissions": ["payment_method", "balances", "ownership", "transactions"], }, }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 2000, 'currency' => 'usd', 'customer' => '{{CUSTOMER_ID}}', 'automatic_payment_methods' => ['enabled' => true], 'payment_method_options' => [ 'us_bank_account' => [ 'financial_connections' => [ 'permissions' => ['payment_method', 'balances', 'ownership', 'transactions'], ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(2000L) .setCurrency("usd") .setCustomer("{{CUSTOMER_ID}}") .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder().setEnabled(true).build() ) .setPaymentMethodOptions( PaymentIntentCreateParams.PaymentMethodOptions.builder() .setUsBankAccount( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.builder() .setFinancialConnections( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.builder() .addPermission( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.PAYMENT_METHOD ) .addPermission( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.BALANCES ) .addPermission( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.OWNERSHIP ) .addPermission( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.TRANSACTIONS ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 2000, currency: 'usd', customer: '{{CUSTOMER_ID}}', automatic_payment_methods: { enabled: true, }, payment_method_options: { us_bank_account: { financial_connections: { permissions: ['payment_method', 'balances', 'ownership', 'transactions'], }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(2000), Currency: stripe.String(stripe.CurrencyUSD), Customer: stripe.String("{{CUSTOMER_ID}}"), AutomaticPaymentMethods: &stripe.PaymentIntentCreateAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, PaymentMethodOptions: &stripe.PaymentIntentCreatePaymentMethodOptionsParams{ USBankAccount: &stripe.PaymentIntentCreatePaymentMethodOptionsUSBankAccountParams{ FinancialConnections: &stripe.PaymentIntentCreatePaymentMethodOptionsUSBankAccountFinancialConnectionsParams{ Permissions: []*string{ stripe.String(stripe.PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionPaymentMethod), stripe.String(stripe.PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionBalances), stripe.String(stripe.PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionOwnership), stripe.String(stripe.PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionTransactions), }, }, }, }, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 2000, Currency = "usd", Customer = "{{CUSTOMER_ID}}", AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, PaymentMethodOptions = new PaymentIntentPaymentMethodOptionsOptions { UsBankAccount = new PaymentIntentPaymentMethodOptionsUsBankAccountOptions { FinancialConnections = new PaymentIntentPaymentMethodOptionsUsBankAccountFinancialConnectionsOptions { Permissions = new List { "payment_method", "balances", "ownership", "transactions", }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` #### Payment method types If you pass `payment_method_types` in the API directly, you must explicitly specify which Financial Connections data permissions you want in every API call. To do this for [CheckoutSession](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-payment_method_options-us_bank_account-financial_connections-permissions): ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ --data-urlencode success_url="https://example.com/success" \ -d "line_items[0][price]"={PRICE_ID} \ -d "line_items[0][quantity]"=1 \ -d "payment_method_options[us_bank_account][financial_connections][permissions][0]"=payment_method \ -d "payment_method_options[us_bank_account][financial_connections][permissions][1]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][2]"=ownership \ -d "payment_method_options[us_bank_account][financial_connections][permissions][3]"=transactions ``` ```cli stripe checkout sessions create \ --customer="{{CUSTOMER_ID}}" \ --success-url="https://example.com/success" \ -d "line_items[0][price]"={PRICE_ID} \ -d "line_items[0][quantity]"=1 \ -d "payment_method_options[us_bank_account][financial_connections][permissions][0]"=payment_method \ -d "payment_method_options[us_bank_account][financial_connections][permissions][1]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][2]"=ownership \ -d "payment_method_options[us_bank_account][financial_connections][permissions][3]"=transactions ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer: '{{CUSTOMER_ID}}', success_url: 'https://example.com/success', line_items: [ { price: '{PRICE_ID}', quantity: 1, }, ], payment_method_options: { us_bank_account: { financial_connections: { permissions: ['payment_method', 'balances', 'ownership', 'transactions'], }, }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer": "{{CUSTOMER_ID}}", "success_url": "https://example.com/success", "line_items": [{"price": "{PRICE_ID}", "quantity": 1}], "payment_method_options": { "us_bank_account": { "financial_connections": { "permissions": ["payment_method", "balances", "ownership", "transactions"], }, }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer' => '{{CUSTOMER_ID}}', 'success_url' => 'https://example.com/success', 'line_items' => [ [ 'price' => '{PRICE_ID}', 'quantity' => 1, ], ], 'payment_method_options' => [ 'us_bank_account' => [ 'financial_connections' => [ 'permissions' => ['payment_method', 'balances', 'ownership', 'transactions'], ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .setSuccessUrl("https://example.com/success") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{PRICE_ID}") .setQuantity(1L) .build() ) .setPaymentMethodOptions( SessionCreateParams.PaymentMethodOptions.builder() .setUsBankAccount( SessionCreateParams.PaymentMethodOptions.UsBankAccount.builder() .setFinancialConnections( SessionCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.builder() .addPermission( SessionCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.PAYMENT_METHOD ) .addPermission( SessionCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.BALANCES ) .addPermission( SessionCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.OWNERSHIP ) .addPermission( SessionCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.TRANSACTIONS ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer: '{{CUSTOMER_ID}}', success_url: 'https://example.com/success', line_items: [ { price: '{PRICE_ID}', quantity: 1, }, ], payment_method_options: { us_bank_account: { financial_connections: { permissions: ['payment_method', 'balances', 'ownership', 'transactions'], }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), SuccessURL: stripe.String("https://example.com/success"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{PRICE_ID}"), Quantity: stripe.Int64(1), }, }, PaymentMethodOptions: &stripe.CheckoutSessionCreatePaymentMethodOptionsParams{ USBankAccount: &stripe.CheckoutSessionCreatePaymentMethodOptionsUSBankAccountParams{ FinancialConnections: &stripe.CheckoutSessionCreatePaymentMethodOptionsUSBankAccountFinancialConnectionsParams{ Permissions: []*string{ stripe.String(stripe.CheckoutSessionPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionPaymentMethod), stripe.String(stripe.CheckoutSessionPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionBalances), stripe.String(stripe.CheckoutSessionPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionOwnership), stripe.String(stripe.CheckoutSessionPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionTransactions), }, }, }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Customer = "{{CUSTOMER_ID}}", SuccessUrl = "https://example.com/success", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{PRICE_ID}", Quantity = 1 }, }, PaymentMethodOptions = new Stripe.Checkout.SessionPaymentMethodOptionsOptions { UsBankAccount = new Stripe.Checkout.SessionPaymentMethodOptionsUsBankAccountOptions { FinancialConnections = new Stripe.Checkout.SessionPaymentMethodOptionsUsBankAccountFinancialConnectionsOptions { Permissions = new List { "payment_method", "balances", "ownership", "transactions", }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Use data with your ACH integration After you’ve been approved for additional bank account data access such balances or ownership, you can use this data to improve ACH payments performance. For example, you can use balance data to reduce the risk of insufficient funds failures. See related data guides for examples: - [Balances](https://docs.stripe.com/financial-connections/balances.md): check account balance prior to payment initiation to reduce *NSFs* (A shorthand way of referring to the Non-sufficient Funds ACH return code R01). - [Ownership](https://docs.stripe.com/financial-connections/ownership.md): pull account owners and compare against your internal data models to catch potential fraud. - [Transactions](https://docs.stripe.com/financial-connections/transactions.md): pull an account’s transaction history to check when the customer’s paycheck might land. > The Risk Intelligence API is a preview feature that provides additional aggregate data to help manage risk, such as average account balance over the past 30/60/90 days, total number of credit transactions over the past 30/60/90 days, and more. If you’re interested in using this preview feature, [email us](mailto:financial-connections-beta+risk-intelligence@stripe.com) for access. ### Finding the Financial Connections Account ID To initiate data refreshes and retrieve data on a Financial Connections account, you first need to get the account’s ID from the linked payment method by expanding the PaymentIntent’s `payment_method` property: ```curl curl -G https://api.stripe.com/v1/payment_intents/{{PAYMENT_INTENT}} \ -u "<>:" \ -d "expand[]"=payment_method ``` ```cli stripe payment_intents retrieve {{PAYMENT_INTENT}} \ -d "expand[0]"=payment_method ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.retrieve( '{{PAYMENT_INTENT}}', {expand: ['payment_method']}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.retrieve( "{{PAYMENT_INTENT}}", {"expand": ["payment_method"]}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->retrieve( '{{PAYMENT_INTENT}}', ['expand' => ['payment_method']] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentRetrieveParams params = PaymentIntentRetrieveParams.builder().addExpand("payment_method").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().retrieve("{{PAYMENT_INTENT}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.retrieve( '{{PAYMENT_INTENT}}', { expand: ['payment_method'], } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentRetrieveParams{} params.AddExpand("payment_method") result, err := sc.V1PaymentIntents.Retrieve(context.TODO(), "{{PAYMENT_INTENT}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentGetOptions { Expand = new List { "payment_method" }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Get("{{PAYMENT_INTENT}}", options); ``` The Financial Connections account ID is on the expanded payment method’s [`us_bank_account` hash](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-us_bank_account). If you allow [manual entry fallback](https://docs.stripe.com/financial-connections/ach-direct-debit-payments.md#enable) and the user manually entered their account information, this field is `null`. ```json { "id": "pi_3OK3g4FitzZY8Nvm11121Lhb", "object": "payment_intent", "payment_method": { "us_bank_account": {"financial_connections_account": "fca_1OK123bitUAA8SvmruWkck76" } // ... other fields on the Payment Method } // ... other fields on the Payment Intent } ``` --- # Source: https://docs.stripe.com/invoicing/ach-direct-debit.md # Invoicing and ACH Direct Debit Configure, create, and process invoices using ACH Direct Debit. To reduce costs, many merchants make card payment methods unavailable above a certain *invoice* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) total amount, and prefer payment from bank methods like ACH Direct Debit. This guide provides step-by-step instructions on how to configure, create, and process invoices to use the [ACH Direct Debit](https://docs.stripe.com/payments/ach-direct-debit.md) payment method. Stripe users in the United States can accept **ACH Direct Debit** from end customers with US bank accounts using the Automated Clearing House (ACH) payments system operated by [Nacha](https://www.nacha.org/content/ach-network). A *Connect* (Connect is Stripe's solution for multi-party businesses, such as marketplace or software platforms, to route payments between sellers, customers, and other recipients) platform that integrates ACH Direct Debit has more [advanced options available](https://docs.stripe.com/invoicing/ach-direct-debit.md#fee-splitting). To begin, determine whether: - Your customers [enter bank account information](https://docs.stripe.com/invoicing/ach-direct-debit.md#default-payment-method) to pay their invoices. - You [collect and verify bank account information upfront](https://docs.stripe.com/invoicing/ach-direct-debit.md#precollected-bank-information) and automatically process invoices. > If you give a customer an invoice link to pay a one-off invoice, Stripe automatically saves their bank information allowing reuse on future invoices. You can also add the bank customer’s information directly through the customer details page. ## Set up ACH Direct Debit You can either set ACH Direct Debit as a default payment method, or add it when you [create an invoice](https://docs.stripe.com/invoicing/dashboard.md#create-invoice). #### Dashboard To set ACH Direct Debit as a default payment method type: 1. On the [Billing settings](https://dashboard.stripe.com/settings/billing/invoice) page, under **Invoicing settings** > **Default payment methods**, click **Edit payment methods**. 1. On the **Billing Payments** page, under **Bank debits**, click **Turn on** to enable **ACH Direct Debit** as a default payment method. Your customers can pay an invoice by using the [Hosted Invoice Page](https://docs.stripe.com/invoicing/hosted-invoice-page.md) to enter their bank account information or select the default payment method. If there isn’t a default payment method, the invoice includes all available payment methods. #### API To set ACH Direct Debit as the default payment method type, add `us_bank_account` to the `payment_method_types` array under the optional [payment_settings](https://docs.stripe.com/api/invoices/object.md#invoice_object-payment_settings-payment_method_types) parameter. This results in an invoice that a customer can only pay by using ACH Direct Debit—regardless of the other available default payment methods. If you want to include additional payment methods, add them to the `payment_method_types` array. Your customer can then use ACH Direct Debit along with the other added payment methods. For [payment method options](https://docs.stripe.com/api/invoices/object.md#invoice_object-payment_settings-payment_method_options-us_bank_account), such as requesting additional linked account data, see the [ACH guide](https://docs.stripe.com/payments/ach-direct-debit.md). ```missingLanguage payment_settings: { payment_method_types:[`us_bank_account`] }, ``` ## Pre-collected bank information You can collect bank account information for future payments with **ACH Direct Debit**. After you add a customer’s ACH details, they must verify their payment information with microdeposits, which can take up to 2 days. #### Dashboard To pre-collect a customer’s bank information: 1. On the [Customers](https://dashboard.stripe.com/customers) page, select a customer name. 1. On the customer page, under **Payment methods**, click the plus (**+**) symbol, and select **Add US bank account**. 1. On the **Add a US bank account** page, enter the payment details, and click **Add US bank account**. 1. After verification, click the overflow menu (⋯) next to the payment method, and select **Set as default**. Whenever you create a new invoice for your customer, select **Charge immediately** to automatically charge the default payment method on file. For a finalized invoice, you can also click **Charge customer** on the invoice details page, and select the saved ACH Direct Debit payment method to initiate the transaction. #### API Every finalized invoice has an associated payment intent. You can [confirm a PaymentIntent](https://docs.stripe.com/api/payment_intents/confirm.md) to process the invoice. ## Payment completions For any invoice with ACH Direct Debit enabled as a payment method, your customer can enter their bank account information on the Hosted Invoice Page to start a debit payment. Your customer must do the following to complete payment: 1. On the Hosted Invoice Page, select **US bank account**. 1. Search for and select the bank. 1. Initiate login with the bank and agree to the terms of service. 1. Select the bank account and click **Connect account**. 1. After successfully connecting the account, click **Back** to go to the invoice. 1. Click **Pay** and agree to the terms of service. ## Enhanced fee splitting (Connect) Payment methods (such as credit and debit cards) have a fixed percentage charged over the whole amount. But low cost payment methods (such as **ACH Direct Debit**) are usually capped. For platforms looking to dynamically reflect this fee arrangement to their businesses, Stripe recommends that you separate your charges and transfers (as opposed to using the basic `application_fee_amount` parameter). With separate charges and transfers, your platform can transfer the business’ share of funds minus the appropriate fee amount based on the payment method type. ## Test the integration You can test customer bank account entry through instant verification or microdeposits. ### Instant verification You can instantly verify a bank account in a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes). Refresh the page to view the paid invoice. 1. Create an invoice in a sandbox. 1. Under **Payment collection**, select **Request payment in full** > **Manage payment methods**. 1. In the **Payment methods for this invoice** dialog, enable **ACH direct debit**, and click **Save**. 1. Enter the invoice details, and click **Send invoice**. 1. On the invoice details page, under **Details**, click the **Payment page** link. 1. On the Hosted Invoice Page, select **US bank account** > **Test Institution**. 1. Initiate login with the bank and agree to the terms of service. 1. Select the bank account and click **Connect account**. 1. After successfully connecting the account, click **Back** to go to the invoice. 1. Click **Pay** and agree to the terms of service. ### Microdeposits You can manually verify bank accounts using microdeposits. In live mode, it takes several days for the transaction to complete. But in a sandbox, the transaction clears immediately and the invoice is paid. 1. Create an invoice in a sandbox. 1. Under **Payment collection**, select **Request payment in full** > **Manage payment methods**. 1. In the **Payment methods for this invoice** dialog, enable **ACH Direct Debit**, and click **Save**. 1. Enter the invoice details, and click **Send invoice**. 1. On the invoice details page, under **Details**, click the **Payment page** link. 1. On the Hosted Invoice Page, select **US bank account**, and then click **Pay**. 1. Click **Enter bank details manually instead** to verify the bank account with microdeposits. 1. In the **Enter bank details** dialog, click **Use test account** to use a [test routing number and bank account](https://docs.stripe.com/payments/ach-direct-debit/accept-a-payment.md#test-account-numbers). 1. After successfully adding the account, click **Back** to go to the invoice. Next, finish initiating microdeposits in your Stripe account. You can expect an email with instructions within 1-2 business days. ## See also - [Payment methods](https://docs.stripe.com/invoicing/payment-methods.md) - [Hosted invoice page](https://docs.stripe.com/invoicing/hosted-invoice-page.md) - [Invoicing API](https://docs.stripe.com/api/invoices.md) --- # Source: https://docs.stripe.com/get-started/account/add-funds.md # Add funds to your Stripe balance Cover increased refunds and chargebacks by adding funds to your balance. To add funds to pay out to connected accounts, [add funds to your platform balance](https://docs.stripe.com/connect/top-ups.md). To maintain stability in your business when your account has a negative balance or when you expect an increase in customer refunds or disputes, you can add funds directly to your Stripe balance using a wire or bank transfer. For businesses using automatic payouts, we recommend that you set a [minimum balance](https://docs.stripe.com/payouts/minimum-balances-for-automatic-payouts.md) to ensure timely processing of refunds. ## Payment method availability In several markets, funds are added to a Stripe VBAN (which helps reconciliation speed) using a local bank credit transfer. These include: AMER (United States), EMEA (United Kingdom, EUR Currency markets) and APAC (Japan). In other markets, funds are added using a wire transfer, which follows slightly different times and processes. Only wire transfers are available in the following regions and countries: AMER (Canada), EMEA (Non-EUR Currency markets: BG, CZ, HU, LI, GI, RO), APAC (AU, NZ, SG, HK, IN, TH, MY), and LatAm (BR, MX). Stripe VBAN isn’t available in these regions and countries. ## Payments balance In the US, UK, and JP, you can add funds directly to the payments balance. We recommend this option for most businesses because it avoids transiting funds through a separate balance. For businesses using automatic payouts, funds added to the payments balance in excess of the [minimum balance](https://docs.stripe.com/payouts/minimum-balances-for-automatic-payouts.md) are paid out in the next payout. You can configure your payout schedule and minimum balance settings in your [Payout settings](https://dashboard.stripe.com/settings/payouts). ## Refunds and disputes balance You can also add funds to the **Future refunds or disputes balance** ([refund_and_dispute_prefunding](https://docs.stripe.com/api/balance/balance_object.md#balance_object-refund_and_dispute_prefunding)), which is a separate balance. These funds are never included in an automatic payout, but you can initiate a manual payout at any time. Stripe first attempts to process refunds and disputes from your available payments balance. If your payments balance is insufficient, Stripe uses these reserved funds. If these reserved funds are also insufficient, then your payments balance might go negative. > #### Payouts reconciliation > > For businesses using automatic payouts, balance transactions for refunds and disputes funded from the **Future refunds or disputes balance** aren’t included in [payouts reconciliation reports](https://docs.stripe.com/payouts/reconciliation.md). ## Financial account In the US and UK, you can add funds to a [financial account](https://docs.stripe.com/financial-accounts.md) in the Stripe Dashboard. A financial account lets you store funds, send and receive money, convert currencies, and create spend cards. ## Add funds This section outlines the steps to send funds from your bank using the Dashboard to add them to your Stripe balance. ### Before you send funds You can send funds from an external bank account to fund your financial account. In the US, you can send funds with an ACH transfer or wire. With ACH, funds are available in about 3 days after you initiate the transfer from your bank. With wire transfers, funds are available within the day. Additional charges apply if funding with a wire. 1. On the [Balances](https://dashboard.stripe.com/balances) page, click **Add funds**. 1. Select the balance to add money to. 1. Select **Manually transfer** from your bank and click **Next**. 1. Use the account details to send money through ACH, RTP, a wire, or other local payment from your bank. ### After you send funds 1. After your bank has sent the funds, navigate back to the Balances page, and click **Add to balance**. 1. If the modal prompts you for a receipt, upload a screenshot or document that confirms your bank transferred the funds. To fund your Stripe balance faster, you might need to provide a screenshot or PDF of your bank’s transfer or wire confirmation. 1. Click **Confirm transfer**. ## View your funds After Stripe receives the funds, we show the added funds in the [Balances](https://dashboard.stripe.com/balance/overview) page. You also receive a [balance.available](https://docs.stripe.com/api/events/types.md#event_types-balance.available) webhook. The following example event shows a balance snapshot with details of `refund_and_dispute_prefunding` balances: #### balance-available ```json { "id": "{{EVENT_ID}}", "object": "event", "type": "balance.available", "data": { "object": { "object": "balance", //... "available": [ { "amount": 1000, "currency": "usd", "source_types" : { "bank_account": 100, "card": 900, }, }, { "amount": 0, "currency": "eur", "source_types" : { "bank_account": 0, "card": 0, }, } ], "pending": [ //... ],"refund_and_dispute_prefunding": { "available": [ { "amount": 1000, "currency": "usd", }, { "amount": 0, "currency": "eur", } ], "pending": [ { "amount": 1000, "currency": "usd", }, { "amount": 0, "currency": "eur", } ], } // ... } } } ``` ## Settlement timing This table provides the expected timing for fund settlement based on the region and payment transfer method, and can help you understand how long it typically takes for payments to process. | Region and currency | Payment transfer method | Estimated speed | | ------------------- | ----------------------- | ---------------------------------------------------------------- | | USA (USD) | Wire transfer | 1-5 days | | USA (USD) | ACH Credit Transfer | 1-3 days | | USA (USD) | ACH Debit Transfer | 5 days | | EU (EUR) | SEPA Credit Transfer | 1-2 days | | UK (GBP) | FPS | 2 hours - 1 day | | UK (GBP) | BACS | 2-3 days | | Other currencies | Wire transfer | 1-7 days (if you provide the correct wire information to Stripe) | Depending on your account configuration, you might not have access to all the methods mentioned above immediately after launching. If you’re a new user and haven’t completed a substantial amount of top-ups to Stripe, the timing for fund availability might initially be delayed longer than indicated; however, your initial speed will eventually align with the outlined speeds. ## See also - [Add funds to your platform balance](https://docs.stripe.com/connect/top-ups.md) - [Manage prorations for modified subscriptions](https://docs.stripe.com/billing/subscriptions/prorations.md) --- # Source: https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md # Add funds to your card program Learn about your options to fund card spend. To enable card spend, Stripe Issuing users must fund an Issuing balance. Your default funding option is to use an external bank account. Depending on your integration and region, you have the option to pull or push funds from an external bank account to your Issuing balance. If you use Stripe to process payments, you can fund your Issuing balance from your Stripe acquiring balance or from your external bank account. There are four funding types available: [pull-funded top ups](https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md#pull-funded-top-ups), [push-funded top-ups](https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md#push-funded-top-ups), [Stripe balance transfers](https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md#stripe-balance-transfers), and [Connect balance transfers](https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md#connect-balance-transfers). This page provides information to help you decide which type works better for your integration. ## Fund your card program Determining how to fund your card program is a core part of your Stripe Issuing integration. To avoid insufficient funds declines when making purchases on issued cards, your account needs to have sufficient funds in the Issuing Balance. As a best practice, you should: 1. Add funds to cover planned spending. 1. Create alerts that tell you [when your Issuing balance is low](https://docs.stripe.com/issuing/funding/balance.md#enable-notifications-about-your-balance). 1. Review funding options to efficiently move money into your Issuing balance. The default way to fund your card spend is a top-up from an external bank account: - In the US, the default is a [pull-funded top-up](https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md#pull-funded-top-ups) - In the UK and Europe, the default is a [push-funded top-up](https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md#push-funded-top-ups) ## Compare funding options | | [Pull-funded top-ups](https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md#pull-funded-top-ups) | [Push-funded top-ups](https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md#push-funded-top-ups) | [Stripe balance transfers](https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md#stripe-balance-transfers) (preview) | [Connect balance transfers](https://docs.stripe.com/issuing/adding-funds-to-your-card-program.md#connect-balance-transfers) (preview) | | ---------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | Overview | Funds your Issuing balance from an external bank account. | Funds your Issuing balance from an external bank account, but you don’t need to add your external bank account to Stripe. | Moves funds to your Issuing balance from your Stripe balance. | Transfers funds to or from the Issuing balance of a connected account from the platform’s Issuing balance. | | Best for | Users who want to build their own logic around when they want to top up. | Users focused on capital efficiency. | Users that also use Stripe to process their payments. | Users that have a Connect integration and plan to programmatically fund connected accounts. | | Fund origination | External bank account | External bank account | Stripe balance (Payments) | Platform Issuing balance (Connect) | | Settlement time | Up to 5 business days. Expedited top-ups might be available. | Depends on the *payment rails* (A financial network that provides the technological infrastructure to electronically move money from a payer to a payee) used. Your first few top-ups might have additional delays. | Instant in the US. Within 1 business day in the UK and Europe. | Instant in all available regions. | | Availability | - US | - US (preview) - UK - Europe | - US - UK - Europe | - US - UK - Europe | ### Pull-funded top-ups - US Pull-funded top-ups fund your Issuing balance from an external bank account. This is the default funding method in the US, and is sufficient as the sole funding method. Funds can take up to 5 business days to become available. In some cases, expedited top-ups are available. If you have a [direct](https://docs.stripe.com/issuing/funding/balance.md?push-pull-preference=pull) or [Connect](https://docs.stripe.com/issuing/connect/funding.md?issuing-funding-type=us-pull-funding) integration, you can initiate pull-funded top-ups using the [create top-up](https://docs.stripe.com/api/topups/create.md) endpoint or in the Dashboard. A platform’s connected accounts can initiate pull-funded top-ups using the API only. Pull-funded top-ups are best for users who want to build their own logic around when they want to top up. For example, you can build a flow to use the Balances API to view your current balances and automatically trigger a pull-funded top-up if your Issuing balance goes below a certain threshold. For US users, this is the easiest funding method to start with, especially when using the Dashboard. ### Push-funded top-ups - EU - GB - US Push-funded top-ups also fund your Issuing balance from an external bank account. However, unlike pull-funded top-ups, you don’t need to add your external bank account to Stripe. Instead, push-funded top-ups use an account or routing number to push funds to your Issuing balance using: - Same-day wire or ACH credit transfer (US) (preview) - BACS / FPS (UK) - Sepa Credit Transfer (Europe) You can find routing information in the [Dashboard](https://docs.stripe.com/issuing/funding/balance.md?issuing-currency=usd#access-account-information-for-push-funding-in-the-dashboard) or by making a `create` or `list` call to the [Funding Instruction](https://docs.stripe.com/api/issuing/funding_instructions.md) endpoint. However, connected accounts can only view routing information by calling [List Funding Instructions](https://docs.stripe.com/api/issuing/funding_instructions/list.md). - US (preview): See the documentation for push-funded top-ups for [Connect](https://docs.stripe.com/issuing/connect/funding.md?issuing-funding-type=us-push-funding) or [direct](https://docs.stripe.com/issuing/funding/balance.md?push-pull-preference=push) integrations. - UK and Europe: See the documentation for push-funded top-ups for Connect ([UK](https://docs.stripe.com/issuing/connect/funding.md?issuing-funding-type=uk-push-funding), [Europe](https://docs.stripe.com/issuing/connect/funding.md?issuing-funding-type=euro-push-funding)) and [direct](https://docs.stripe.com/issuing/funding/balance.md?push-pull-preference=push) integrations. This is the default funding method for in the UK and Europe. Push-funded top-ups are sufficient as the sole funding method. Funding speed depends on the *payment rails* (A financial network that provides the technological infrastructure to electronically move money from a payer to a payee) that transfer the funds. There might be additional delays for your first few top-ups. Push-funded top-ups are best for users focused on capital efficiency, since this funding method allows platforms to fund their Issuing balance on the same day. Platforms can then hold more funds in an interest-bearing account outside of Stripe and quickly move those funds into their Issuing balance as needed. Push-funded top-ups are also good for users who have originating banks with APIs that support automated integrations. Some users also prefer not to connect an external bank account to their Issuing balance. ### Stripe balance transfers (preview) - EU - GB - US Balance transfers move funds to your Issuing balance from your Stripe balance, which contains your payments proceeds. This funding method requires you to use Stripe to process payments. Optional in the US, UK, and Europe. Funds settle instantly in the US and within 1 business day in the UK and Europe. Users with a [direct](https://docs.stripe.com/issuing/funding/balance.md?push-pull-preference) or [Connect](https://docs.stripe.com/issuing/connect/funding.md?issuing-funding-type=us-pull-funding) integration can initiate Stripe balance transfers using the balance transfer API endpoint or in the Dashboard. A platform’s connected accounts can only initiate Stripe balance transfers to Issuing balance using the API. If you need to pay out excess funds in the Issuing balance, you can initiate a [Payout](https://docs.stripe.com/api/payouts/create.md). Balance transfers are best for users that also use Stripe to process their payments since it allows the user to use their acquiring balance to fund their Issuing balance. ### Connect balance transfers (preview) - EU - GB - US Transfers funds to or from the Issuing balance of a connected account from the platform’s Issuing balance. This funding method requires Stripe Connect. Optional in the US, UK, and Europe. Funds settle instantly in all available regions. Connect balance transfers are best for users that have a [Connect integration](https://docs.stripe.com/issuing/connect/funding.md?issuing-funding-type=us-pull-funding) and plan to programmatically fund connected accounts, since this funding mechanism allows the platform to instantly pre-fund any connected account’s Issuing balance to the right level to avoid transaction declines. ## Using funding methods in practice Businesses on Stripe Issuing can operate a card program with the default funding method and nothing more. But if your business has additional Stripe integrations such as Connect, you can benefit by using multiple funding methods. For example, suppose you’re an e-commerce platform providing an expense management card to each of the online shops on your platform. In this case, build a [Connect integration](https://docs.stripe.com/issuing/connect.md) where each shop on your platform represents a connected account. Shops on your platform can accept payments and fund cards by transferring balances, all on Stripe. If your merchants also collect funds from users outside of Stripe, they can use push-funded top-ups from an external bank account. When you’re ready, allocate collected funds by transferring funds from your platform Issuing balance to the Issuing balance of specific connected accounts. Taking a US platform as an example, your funding setup could look like this: Diagram of fund set up with bank to platform Issuing balance (See full diagram at https://docs.stripe.com/issuing/adding-funds-to-your-card-program) You could also enable your shops, represented as connected accounts, to directly accept payments and move funds into their account to pay for their expenses. Diagram of fund set up with bank to connect account Issuing balance (See full diagram at https://docs.stripe.com/issuing/adding-funds-to-your-card-program) --- # Source: https://docs.stripe.com/payments/mobile/address-element.md # Source: https://docs.stripe.com/elements/address-element.md # Address Element Use the Address Element to collect complete billing and shipping addresses. The Address Element is an embeddable UI component for accepting complete addresses. Use it to collect shipping addresses, or when you need a complete billing address, such as for tax purposes. | Option | Description | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Theme** | Use the dropdown to choose a theme or customize the theme with the [Elements Appearance API](https://docs.stripe.com/elements/address-element.md#appearance). | | **Desktop and mobile size** | Use the dropdown to set the max pixel width of the parent element that the Address Element is mounted to. You can set it to 750px (desktop) or 320px (mobile). | | **Customer location** | Use the dropdown to choose a location for accepting complete addresses. Changing the location localizes the UI language and displays locally relevant payment methods. | | **Phone number** | Enable this option to allow phone number collection when an address is entered or when using an existing contact. | | **Autocomplete** | Enable this option to decrease checkout time, reduce validation errors, and increase checkout conversion with built-in address autocomplete. Stripe supports 236 regional address formats, including right-to-left address formats. | | **Contacts** | Enable this option to add a new address or change an existing address or phone number. | ## Get started You can use the Address Element with either the Embedded components integration (Elements with Checkout Sessions API) or the Advanced integration (Elements with Payment Intents API). [Compare the features and availability](https://docs.stripe.com/payments/online-payments.md#compare-features-and-availability) to see which integration suits your use case. [Collect addresses (Elements with Checkout Sessions API)](https://docs.stripe.com/payments/advanced/collect-addresses.md?payment-ui=embedded-components): Use the Embedded components integration to collect addresses. [Collect addresses (Advanced integration)](https://docs.stripe.com/payments/advanced/collect-addresses.md?payment-ui=elements): Use the Advanced integration to collect addresses. [Clone a sample app (Advanced integration)](https://github.com/stripe-samples/link) ## Create an Address Element When you create an Address Element, specify whether to use it in shipping or billing mode. #### Shipping mode In shipping mode, the element does two things: - Collect a shipping address. - Offer the customer the option to use it as a billing address too. ```javascript const stripe = Stripe('<>'); const appearance = { /* appearance */ }; const options = { mode: 'shipping' }; const elements = stripe.elements({ clientSecret, appearance }); // In a working integration, this is a value your backend passes with details such as the amount of a payment. See full sample for details. const addressElement = elements.create('address', options); addressElement.mount('#address-element'); ``` #### Billing mode In billing mode, the element only collects a billing address. ```javascript const stripe = Stripe('<>'); const appearance = { /* appearance */ }; const options = { mode: 'billing' }; const elements = stripe.elements({ clientSecret, appearance }); // In a working integration, this is a value your backend passes with details such as the amount of a payment. See full sample for details. const addressElement = elements.create('address', options); addressElement.mount('#address-element'); ``` ### Use Address Element with other elements You can collect both shipping and billing addresses by using multiple Address Elements, one of each mode, on your page. If you need to collect both shipping and billing addresses and only want to use one Address Element, use the Address Element in Shipping mode and use the [Payment Element](https://docs.stripe.com/payments/payment-element.md) to collect only the necessary billing address details. When you use the Address Element with other elements, you can expect some automatic behavior when confirming the PaymentIntent or SetupIntent. The Address Element validates completeness upon confirming the PaymentIntent or SetupIntent and then displays errors for each field if there are any validation errors. ## Use an address The Address Element automatically works with the [Payment](https://docs.stripe.com/payments/payment-element.md) or Express Checkout Element. When a customer provides an address and a payment method, Stripe combines them into a single *PaymentIntent* (The Payment Intents API tracks the lifecycle of a customer checkout flow and triggers additional authentication steps when required by regulatory mandates, custom Radar fraud rules, or redirect-based payment methods) with the address in the correct field. ### Automatic behavior The element’s default behavior depends on its mode. #### Shipping mode In shipping mode, the address is stored in these fields: - It appears in the [shipping](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-shipping) field. - If the customer indicates it is also the billing address, it also appears in the [billing_details](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-payment_method_data-billing_details) field. To enable combining information, create all elements from the same `Elements` object, as in this example: ```javascript const stripe = Stripe('<>'); const appearance = { /* appearance */ }; const options = { mode: 'shipping' }; const paymentElementOptions = { layout: 'accordion'}; const elements = stripe.elements({ clientSecret }); // In a working integration, this is a value your backend passes with details such as the amount of a payment. See full sample for details. const addressElement = elements.create('address', options); const paymentElement = elements.create('payment', paymentElementOptions); addressElement.mount('#address-element'); paymentElement.mount('#payment-element'); ``` #### Billing mode In billing mode, the address is stored in the [billing_details](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-payment_method_data-billing_details) field. To enable combining information, create all elements from the same `Elements` object, as in this example: ```javascript const stripe = Stripe('<>'); const appearance = { /* appearance */ }; const options = { mode: 'billing' }; const paymentElementOptions = { layout: 'accordion'}; const elements = stripe.elements({ clientSecret }); // In a working integration, this is a value your backend passes with details such as the amount of a payment. See full sample for details. const addressElement = elements.create('address', options); const paymentElement = elements.create('payment', paymentElementOptions); addressElement.mount('#address-element'); paymentElement.mount('#payment-element'); ``` ### Custom behavior Normally, the Address Element’s default behavior is enough. But in a complex payment flow, you might need to write custom responses to the customer’s input. For information, see [Listen for address input](https://docs.stripe.com/payments/advanced/collect-addresses.md). ## Autocomplete If your customer selects a supported country for their address, then they see the autocomplete options. The Address Element can autocomplete addresses for the following countries: - AU - BE - BR - CA - CH - DE - ES - FR - GB - IE - IN - IT - JP - MX - MY - NL - NO - NZ - PH - PL - RU - SE - SG - TR - US - ZA If you use the Address Element and the Payment Element together, Stripe enables autocomplete with no configuration required. This is done using a Stripe-provided Google Maps API key. > By using autocomplete, you agree to comply with the [Google Maps Platform Acceptable Use Policy](https://cloud.google.com/maps-platform/terms/aup). If you violate this policy, we might disable autocomplete, or take any other action as necessary. If you use the Address Element alone, you must use your own [Google Maps API Places Library key](https://developers.google.com/maps/documentation/javascript/places), which is managed separately from your Stripe account. Pass the key in the [autocomplete.apiKey](https://docs.stripe.com/js/elements_object/create_address_element#address_element_create-options-autocomplete-apiKey) option. ## Autofill with Link [Link](https://docs.stripe.com/payments/link.md) saves and autofills payment and shipping information for the options you’ve enabled. For example, if the Link customer has a saved phone number, Stripe autofills the phone number only if phone number collection is enabled. When a returning Link customer authenticates, Stripe autofills their shipping information in the Address element. ![Create a payment form using multiple Elements](https://b.stripecdn.com/docs-statics-srv/assets/link-with-elements.f60af275f69b6e6e73c766d1f9928457.png) Create a payment form using multiple Elements To enable autofill, create all elements from the same `Elements` object, as in this example: ```javascript const stripe = Stripe('<>'); const appearance = { /* appearance */ }; const options = { mode: 'shipping' }; const paymentElementOptions = { layout: 'accordion'}; const elements = stripe.elements({ clientSecret }); // In a working integration, this is a value your backend passes with details such as the amount of a payment. See full sample for details. const linkAuthElement = elements.create('linkAuthentication'); const addressElement = elements.create('address', options); const paymentElement = elements.create('payment', paymentElementOptions); linkAuthElement.mount('#link-auth-element'); addressElement.mount('#address-element'); paymentElement.mount('#payment-element'); ``` ## Appearance You can use the Appearance API to control the style of all elements. Choose a theme or update specific details. ![Examples of light and dark modes for the address element.](https://b.stripecdn.com/docs-statics-srv/assets/address_appearance_example.c7884ea763b05e5881d65ed2b2afadbc.png) For instance, choose the “flat” theme and override the primary text color. ```javascript const stripe = Stripe('<>'); const appearance = { theme: 'flat', variables: { colorPrimaryText: '#262626' } }; const options = { /* options */ }; const elements = stripe.elements({ clientSecret, appearance }); // In a working integration, this is a value your backend passes with details such as the amount of a payment. See full sample for details. const addressElement = elements.create('address', options); addressElement.mount('#address-element'); ``` See the Appearance API documentation for the [Elements with Checkout Sessions API integration](https://docs.stripe.com/payments/checkout/customization/appearance.md?payment-ui=embedded-components) or the [Advanced integration](https://docs.stripe.com/elements/appearance-api.md) for a full list of themes and variables. --- # Source: https://docs.stripe.com/payments/checkout/adjustable-quantity.md # Make line item quantities adjustable Enable your customers to adjust the quantity of items during checkout. # Stripe-hosted page > This is a Stripe-hosted page for when payment-ui is stripe-hosted. View the full page at https://docs.stripe.com/payments/checkout/adjustable-quantity?payment-ui=stripe-hosted. The line items for each [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) keep track of what your customer is purchasing. You can configure the Checkout Session so customers can adjust line item quantities during checkout. ## Create a Checkout Session with an adjustable quantity Set `adjustable_quantity` on your `line_items` when creating a Checkout Session to enable your customers to update the quantity of an item during checkout. You can customize the default settings for the minimum and maximum quantities allowed by setting `adjustable_quantity.minimum` and `adjustable_quantity.maximum`. By default, an item’s minimum adjustable quantity is `0` and the maximum adjustable quantity is `99`. You can specify a value of up to `999999` for `adjustable_quantity.maximum`. When using adjustable quantities with a `line_items[].quantity` value greater than `99` (the default adjustable maximum), set `adjustable_quantity.maximum` to be greater than or equal to that item’s quantity. If you use adjustable quantities, change your configuration so that it uses `adjustable_quantity.maximum` when creating the Checkout Session to reserve inventory quantity instead of the `line_items` quantity. Checkout prevents the customer from removing an item if it is the only item remaining. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][tax_behavior]"=exclusive \ -d "line_items[0][adjustable_quantity][enabled]"=true \ -d "line_items[0][adjustable_quantity][minimum]"=1 \ -d "line_items[0][adjustable_quantity][maximum]"=10 \ -d "line_items[0][quantity]"=1 \ -d "automatic_tax[enabled]"=true \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][tax_behavior]"=exclusive \ -d "line_items[0][adjustable_quantity][enabled]"=true \ -d "line_items[0][adjustable_quantity][minimum]"=1 \ -d "line_items[0][adjustable_quantity][maximum]"=10 \ -d "line_items[0][quantity]"=1 \ -d "automatic_tax[enabled]"=true \ --mode=payment \ --success-url="https://example.com/success" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, tax_behavior: 'exclusive', }, adjustable_quantity: { enabled: true, minimum: 1, maximum: 10, }, quantity: 1, }, ], automatic_tax: {enabled: true}, mode: 'payment', success_url: 'https://example.com/success', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, "tax_behavior": "exclusive", }, "adjustable_quantity": {"enabled": True, "minimum": 1, "maximum": 10}, "quantity": 1, }, ], "automatic_tax": {"enabled": True}, "mode": "payment", "success_url": "https://example.com/success", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, 'tax_behavior' => 'exclusive', ], 'adjustable_quantity' => [ 'enabled' => true, 'minimum' => 1, 'maximum' => 10, ], 'quantity' => 1, ], ], 'automatic_tax' => ['enabled' => true], 'mode' => 'payment', 'success_url' => 'https://example.com/success', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .setTaxBehavior(SessionCreateParams.LineItem.PriceData.TaxBehavior.EXCLUSIVE) .build() ) .setAdjustableQuantity( SessionCreateParams.LineItem.AdjustableQuantity.builder() .setEnabled(true) .setMinimum(1L) .setMaximum(10L) .build() ) .setQuantity(1L) .build() ) .setAutomaticTax(SessionCreateParams.AutomaticTax.builder().setEnabled(true).build()) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, tax_behavior: 'exclusive', }, adjustable_quantity: { enabled: true, minimum: 1, maximum: 10, }, quantity: 1, }, ], automatic_tax: { enabled: true, }, mode: 'payment', success_url: 'https://example.com/success', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), TaxBehavior: stripe.String("exclusive"), }, AdjustableQuantity: &stripe.CheckoutSessionCreateLineItemAdjustableQuantityParams{ Enabled: stripe.Bool(true), Minimum: stripe.Int64(1), Maximum: stripe.Int64(10), }, Quantity: stripe.Int64(1), }, }, AutomaticTax: &stripe.CheckoutSessionCreateAutomaticTaxParams{ Enabled: stripe.Bool(true), }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, TaxBehavior = "exclusive", }, AdjustableQuantity = new Stripe.Checkout.SessionLineItemAdjustableQuantityOptions { Enabled = true, Minimum = 1, Maximum = 10, }, Quantity = 1, }, }, AutomaticTax = new Stripe.Checkout.SessionAutomaticTaxOptions { Enabled = true }, Mode = "payment", SuccessUrl = "https://example.com/success", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Handle completed transactions After the payment completes, you can make a request for the finalized [line items](https://docs.stripe.com/api/checkout/sessions/line_items.md) and their quantities. If your customer removes a line item, it is also removed from the line items response. See the [Fulfillment guide](https://docs.stripe.com/checkout/fulfillment.md) to learn how to create an event handler to handle completed Checkout Sessions. > To test your event handler, [install the Stripe CLI](https://docs.stripe.com/stripe-cli.md) and use `stripe listen --forward-to localhost:4242/webhook` to [forward events to your local server](https://docs.stripe.com/webhooks.md#test-webhook). #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = "<>" require 'sinatra' # You can find your endpoint's secret in your webhook settings endpoint_secret = 'whsec_...' post '/webhook' do event = nil # Verify webhook signature and extract the event # See https://stripe.com/docs/webhooks#verify-events for more information. begin sig_header = request.env['HTTP_STRIPE_SIGNATURE'] payload = request.body.read event = Stripe::Webhook.construct_event(payload, sig_header, endpoint_secret) rescue JSON::ParserError => e # Invalid payload return status 400 rescue Stripe::SignatureVerificationError => e # Invalid signature return status 400 end if event['type'] == 'checkout.session.completed' checkout_session = event['data']['object'] line_items = Stripe::Checkout::Session.list_line_items(checkout_session['id'], {limit: 100}) # Fulfill the purchase... begin fulfill_order(checkout_session, line_items) rescue NotImplementedError => e return status 400 end end status 200 end def fulfill_order(checkout_session, line_items) # TODO: Remove error and implement... raise NotImplementedError.new(<<~MSG) Given the Checkout Session "#{checkout_session.id}" load your internal order from the database here. Then you can reconcile your order's quantities with the final line item quantity purchased. You can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids. MSG end ``` #### Python ```python import stripe # Using Django from django.http import HttpResponse # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' # You can find your endpoint's secret in your webhook settings endpoint_secret = 'whsec_...' @csrf_exempt def my_webhook_view(request): payload = request.body sig_header = request.META['HTTP_STRIPE_SIGNATURE'] event = None try: event = stripe.Webhook.construct_event( payload, sig_header, endpoint_secret ) except ValueError as e: # Invalid payload return HttpResponse(status=400) except stripe.error.SignatureVerificationError as e: # Invalid signature return HttpResponse(status=400) # Handle the checkout.session.completed event if event['type'] == 'checkout.session.completed': session = event['data']['object'] line_items = stripe.checkout.Session.list_line_items(session['id'], limit=100) # Fulfill the purchase... try: fulfill_order(session, line_items) except NotImplementedError as e: return HttpResponse(status=400) # Passed signature verification return HttpResponse(status=200) def fulfill_order(session, line_items): # TODO: Remove error and implement... raise NotImplementedError("Given the Checkout Session \"" + session['id'] + "\", load your internal order from the database here.\nThen you can reconcile your order's quantities with the final line item quantity purchased.\nYou can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids.") ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('<>'); // You can find your endpoint's secret in your webhook settings $endpoint_secret = 'whsec_...'; $payload = @file_get_contents('php://input'); $sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE']; $event = null; try { $event = \Stripe\Webhook::constructEvent( $payload, $sig_header, $endpoint_secret ); } catch(\UnexpectedValueException $e) { // Invalid payload http_response_code(400); exit(); } catch(\Stripe\Exception\SignatureVerificationException $e) { // Invalid signature http_response_code(400); exit(); } function fulfill_order($session, $line_items) { // TODO: Remove error and implement... throw new Exception("given the Checkout Session $session->id, load your internal order from the database here.\nThen you can reconcile your order's quantities with the final line item quantity purchased.\nYou can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids.") } // Handle the checkout.session.completed event if ($event->type == 'checkout.session.completed') { $session = $event->data->object; $line_items = \Stripe\Checkout\Session::allLineItems($session->id, ['limit' => 100]); // Fulfill the purchase... try { fulfill_order($session, $line_items); } catch(\Exception $e) { http_response_code(400); exit(); } } http_response_code(200); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; // You can find your endpoint's secret in your webhook settings String endpointSecret = "whsec_..."; public void fulfillOrder(Session session, LineItemCollection lineItems) { // TODO: Remove error and implement... String error = String.format("Given the Checkout Session \"%s\" load your internal order from the database here.\nThen you can reconcile your order's quantities with the final line item quantity purchased. You can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids.", session.getId()); throw new UnsupportedOperationException(error); } // Using the Spark framework public Object handle(Request request, Response response) { String payload = request.body(); String sigHeader = request.headers("Stripe-Signature"); Event event = null; try { event = Webhook.constructEvent(payload, sigHeader, endpointSecret); } catch (JsonSyntaxException e) { // Invalid payload response.status(400); return ""; } catch (SignatureVerificationException e) { // Invalid signature response.status(400); return ""; } // Handle the checkout.session.completed event if ("checkout.session.completed".equals(event.getType())) { Session session = (Session) event.getDataObjectDeserializer().getObject(); Map params = new HashMap<>(); params.put("limit", 100); LineItemCollection lineItems = session.listLineItems(params); // Fulfill the purchase... try { fulfillOrder(session, lineItems); } catch (NotImplementedException e) { response.status(400); return ""; } } response.status(200); return ""; } ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); // Find your endpoint's secret in your Dashboard's webhook settings const endpointSecret = 'whsec_...'; // Using Express const app = require('express')(); // Use body-parser to retrieve the raw body as a buffer const bodyParser = require('body-parser'); const fulfillOrder = (session, lineItems) => { // TODO: Remove error and implement... throw new Error(` Given the Checkout Session ${session.id}, load your internal order from the database here. Then you can reconcile your order's quantities with the final line item quantity purchased. You can use \`checkout_session.metadata\` and \`price.metadata\` to store and later reference your internal order and item ids.` ); } app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => { const payload = request.body; const sig = request.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(payload, sig, endpointSecret); } catch (err) { return response.status(400).send(`Webhook Error: ${err.message}`); } // Handle the checkout.session.completed event if (event.type === 'checkout.session.completed') { const session = event.data.object; stripe.checkout.sessions.listLineItems( session.id, { limit: 100 }, function(err, lineItems) { // Fulfill the purchase... try { fulfillOrder(session, lineItems); } catch (err) { return response.status(400).send(`Fulfillment Error: ${err.message}`); } } ); } response.status(200).end(); }); app.listen(4242, () => console.log('Running on port 4242')); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func fulfillOrder(session stripe.CheckoutSession) error { params := &stripe.CheckoutSessionListLineItemParams{ ID: stripe.String(session.Id), } // Grab the line items for the session params.Filters.AddFilter("limit", "", "100") i := session.ListLineItems(params) for i.Next() { // Access the line item using i.LineItem() } // TODO: Remove error and implement... return fmt.Errorf("given the Checkout Session %q, load your internal order from the database here.\nThen you can reconcile your order's quantities with the final line item quantity purchased.\nYou can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids.", session.Id) } http.HandleFunc("/webhook", func(w http.ResponseWriter, req *http.Request) { const maxBodyBytes = int64(65536) req.Body = http.MaxBytesReader(w, req.Body, maxBodyBytes) body, err := ioutil.ReadAll(req.Body) if err != nil { fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err) w.WriteHeader(http.StatusServiceUnavailable) return } // Pass the request body and Stripe-Signature header to ConstructEvent, along with the webhook signing key // You can find your endpoint's secret in your webhook settings endpointSecret := "whsec_..."; event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), endpointSecret) if err != nil { fmt.Fprintf(os.Stderr, "Error verifying webhook signature: %v\n", err) w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature return } // Handle the checkout.session.completed event if event.Type == "checkout.session.completed" { var session stripe.CheckoutSession err := json.Unmarshal(event.Data.Raw, &session) if err != nil { fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err) w.WriteHeader(http.StatusBadRequest) return } // Fulfill the purchase... if err := fulfillOrder(session); err != nil { fmt.Fprintf(os.Stderr, "Error fulfilling order: %v\n", err) w.WriteHeader(http.StatusBadRequest) return } } w.WriteHeader(http.StatusOK) }) ``` #### .NET ```dotnet using System; using System.IO; using Microsoft.AspNetCore.Mvc; using Stripe; // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; namespace workspace.Controllers { [Route("api/[controller]")] public class StripeWebHook : Controller { // You can find your endpoint's secret in your webhook settings const string secret = "whsec_..."; [HttpPost] public async Task Index() { var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync(); try { var stripeEvent = EventUtility.ConstructEvent( json, Request.Headers["Stripe-Signature"], secret ); // Handle the checkout.session.completed event // If on SDK version < 46, use class Events instead of EventTypes if (stripeEvent.Type == EventTypes.CheckoutSessionCompleted) { var session = stripeEvent.Data.Object as Checkout.Session; // Fulfill the purchase... try { this.FulfillOrder(session); } catch (NotImplementedException ex) { return BadRequest(); } } return Ok(); } catch (StripeException e) { return BadRequest(); } } private void FulfillOrder(Checkout.Session session) { var options = new SessionListLineItemsOptions { Limit = 100, }; var service = new SessionService(); StripeList lineItems = service.ListLineItems(session.Id, options); // TODO: Remove error and implement... throw new NotImplementedException($"Given the Checkout Session \"{session.Id}\" load your internal order from the database here.\n Then you can reconcile your order's quantities with the final line item quantity purchased. You can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids."); } } } ``` # Embedded form > This is a Embedded form for when payment-ui is embedded-form. View the full page at https://docs.stripe.com/payments/checkout/adjustable-quantity?payment-ui=embedded-form. The line items for each [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) keep track of what your customer is purchasing. You can configure the Checkout Session so customers can adjust line item quantities during checkout. ## Create a Checkout Session with an adjustable quantity Set `adjustable_quantity` on your `line_items` when creating a Checkout Session to enable your customers to update the quantity of an item during checkout. You can customize the default settings for the minimum and maximum quantities allowed by setting `adjustable_quantity.minimum` and `adjustable_quantity.maximum`. By default, an item’s minimum adjustable quantity is `0` and the maximum adjustable quantity is `99`. You can specify a value of up to `999999` for `adjustable_quantity.maximum`. When using adjustable quantities with a `line_items[].quantity` value greater than `99` (the default adjustable maximum), set `adjustable_quantity.maximum` to be greater than or equal to that item’s quantity. If you use adjustable quantities, change your configuration so that it uses `adjustable_quantity.maximum` when creating the Checkout Session to reserve inventory quantity instead of the `line_items` quantity. Checkout prevents the customer from removing an item if it is the only item remaining. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][tax_behavior]"=exclusive \ -d "line_items[0][adjustable_quantity][enabled]"=true \ -d "line_items[0][adjustable_quantity][minimum]"=1 \ -d "line_items[0][adjustable_quantity][maximum]"=10 \ -d "line_items[0][quantity]"=1 \ -d "automatic_tax[enabled]"=true \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][tax_behavior]"=exclusive \ -d "line_items[0][adjustable_quantity][enabled]"=true \ -d "line_items[0][adjustable_quantity][minimum]"=1 \ -d "line_items[0][adjustable_quantity][maximum]"=10 \ -d "line_items[0][quantity]"=1 \ -d "automatic_tax[enabled]"=true \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, tax_behavior: 'exclusive', }, adjustable_quantity: { enabled: true, minimum: 1, maximum: 10, }, quantity: 1, }, ], automatic_tax: {enabled: true}, mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, "tax_behavior": "exclusive", }, "adjustable_quantity": {"enabled": True, "minimum": 1, "maximum": 10}, "quantity": 1, }, ], "automatic_tax": {"enabled": True}, "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, 'tax_behavior' => 'exclusive', ], 'adjustable_quantity' => [ 'enabled' => true, 'minimum' => 1, 'maximum' => 10, ], 'quantity' => 1, ], ], 'automatic_tax' => ['enabled' => true], 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .setTaxBehavior(SessionCreateParams.LineItem.PriceData.TaxBehavior.EXCLUSIVE) .build() ) .setAdjustableQuantity( SessionCreateParams.LineItem.AdjustableQuantity.builder() .setEnabled(true) .setMinimum(1L) .setMaximum(10L) .build() ) .setQuantity(1L) .build() ) .setAutomaticTax(SessionCreateParams.AutomaticTax.builder().setEnabled(true).build()) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, tax_behavior: 'exclusive', }, adjustable_quantity: { enabled: true, minimum: 1, maximum: 10, }, quantity: 1, }, ], automatic_tax: { enabled: true, }, mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), TaxBehavior: stripe.String("exclusive"), }, AdjustableQuantity: &stripe.CheckoutSessionCreateLineItemAdjustableQuantityParams{ Enabled: stripe.Bool(true), Minimum: stripe.Int64(1), Maximum: stripe.Int64(10), }, Quantity: stripe.Int64(1), }, }, AutomaticTax: &stripe.CheckoutSessionCreateAutomaticTaxParams{ Enabled: stripe.Bool(true), }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, TaxBehavior = "exclusive", }, AdjustableQuantity = new Stripe.Checkout.SessionLineItemAdjustableQuantityOptions { Enabled = true, Minimum = 1, Maximum = 10, }, Quantity = 1, }, }, AutomaticTax = new Stripe.Checkout.SessionAutomaticTaxOptions { Enabled = true }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Handle completed transactions After the payment completes, you can make a request for the finalized [line items](https://docs.stripe.com/api/checkout/sessions/line_items.md) and their quantities. If your customer removes a line item, it is also removed from the line items response. See the [Fulfillment guide](https://docs.stripe.com/checkout/fulfillment.md) to learn how to create an event handler to handle completed Checkout Sessions. > To test your event handler, [install the Stripe CLI](https://docs.stripe.com/stripe-cli.md) and use `stripe listen --forward-to localhost:4242/webhook` to [forward events to your local server](https://docs.stripe.com/webhooks.md#test-webhook). #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = "<>" require 'sinatra' # You can find your endpoint's secret in your webhook settings endpoint_secret = 'whsec_...' post '/webhook' do event = nil # Verify webhook signature and extract the event # See https://stripe.com/docs/webhooks#verify-events for more information. begin sig_header = request.env['HTTP_STRIPE_SIGNATURE'] payload = request.body.read event = Stripe::Webhook.construct_event(payload, sig_header, endpoint_secret) rescue JSON::ParserError => e # Invalid payload return status 400 rescue Stripe::SignatureVerificationError => e # Invalid signature return status 400 end if event['type'] == 'checkout.session.completed' checkout_session = event['data']['object'] line_items = Stripe::Checkout::Session.list_line_items(checkout_session['id'], {limit: 100}) # Fulfill the purchase... begin fulfill_order(checkout_session, line_items) rescue NotImplementedError => e return status 400 end end status 200 end def fulfill_order(checkout_session, line_items) # TODO: Remove error and implement... raise NotImplementedError.new(<<~MSG) Given the Checkout Session "#{checkout_session.id}" load your internal order from the database here. Then you can reconcile your order's quantities with the final line item quantity purchased. You can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids. MSG end ``` #### Python ```python import stripe # Using Django from django.http import HttpResponse # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' # You can find your endpoint's secret in your webhook settings endpoint_secret = 'whsec_...' @csrf_exempt def my_webhook_view(request): payload = request.body sig_header = request.META['HTTP_STRIPE_SIGNATURE'] event = None try: event = stripe.Webhook.construct_event( payload, sig_header, endpoint_secret ) except ValueError as e: # Invalid payload return HttpResponse(status=400) except stripe.error.SignatureVerificationError as e: # Invalid signature return HttpResponse(status=400) # Handle the checkout.session.completed event if event['type'] == 'checkout.session.completed': session = event['data']['object'] line_items = stripe.checkout.Session.list_line_items(session['id'], limit=100) # Fulfill the purchase... try: fulfill_order(session, line_items) except NotImplementedError as e: return HttpResponse(status=400) # Passed signature verification return HttpResponse(status=200) def fulfill_order(session, line_items): # TODO: Remove error and implement... raise NotImplementedError("Given the Checkout Session \"" + session['id'] + "\", load your internal order from the database here.\nThen you can reconcile your order's quantities with the final line item quantity purchased.\nYou can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids.") ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('<>'); // You can find your endpoint's secret in your webhook settings $endpoint_secret = 'whsec_...'; $payload = @file_get_contents('php://input'); $sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE']; $event = null; try { $event = \Stripe\Webhook::constructEvent( $payload, $sig_header, $endpoint_secret ); } catch(\UnexpectedValueException $e) { // Invalid payload http_response_code(400); exit(); } catch(\Stripe\Exception\SignatureVerificationException $e) { // Invalid signature http_response_code(400); exit(); } function fulfill_order($session, $line_items) { // TODO: Remove error and implement... throw new Exception("given the Checkout Session $session->id, load your internal order from the database here.\nThen you can reconcile your order's quantities with the final line item quantity purchased.\nYou can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids.") } // Handle the checkout.session.completed event if ($event->type == 'checkout.session.completed') { $session = $event->data->object; $line_items = \Stripe\Checkout\Session::allLineItems($session->id, ['limit' => 100]); // Fulfill the purchase... try { fulfill_order($session, $line_items); } catch(\Exception $e) { http_response_code(400); exit(); } } http_response_code(200); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; // You can find your endpoint's secret in your webhook settings String endpointSecret = "whsec_..."; public void fulfillOrder(Session session, LineItemCollection lineItems) { // TODO: Remove error and implement... String error = String.format("Given the Checkout Session \"%s\" load your internal order from the database here.\nThen you can reconcile your order's quantities with the final line item quantity purchased. You can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids.", session.getId()); throw new UnsupportedOperationException(error); } // Using the Spark framework public Object handle(Request request, Response response) { String payload = request.body(); String sigHeader = request.headers("Stripe-Signature"); Event event = null; try { event = Webhook.constructEvent(payload, sigHeader, endpointSecret); } catch (JsonSyntaxException e) { // Invalid payload response.status(400); return ""; } catch (SignatureVerificationException e) { // Invalid signature response.status(400); return ""; } // Handle the checkout.session.completed event if ("checkout.session.completed".equals(event.getType())) { Session session = (Session) event.getDataObjectDeserializer().getObject(); Map params = new HashMap<>(); params.put("limit", 100); LineItemCollection lineItems = session.listLineItems(params); // Fulfill the purchase... try { fulfillOrder(session, lineItems); } catch (NotImplementedException e) { response.status(400); return ""; } } response.status(200); return ""; } ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); // Find your endpoint's secret in your Dashboard's webhook settings const endpointSecret = 'whsec_...'; // Using Express const app = require('express')(); // Use body-parser to retrieve the raw body as a buffer const bodyParser = require('body-parser'); const fulfillOrder = (session, lineItems) => { // TODO: Remove error and implement... throw new Error(` Given the Checkout Session ${session.id}, load your internal order from the database here. Then you can reconcile your order's quantities with the final line item quantity purchased. You can use \`checkout_session.metadata\` and \`price.metadata\` to store and later reference your internal order and item ids.` ); } app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => { const payload = request.body; const sig = request.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(payload, sig, endpointSecret); } catch (err) { return response.status(400).send(`Webhook Error: ${err.message}`); } // Handle the checkout.session.completed event if (event.type === 'checkout.session.completed') { const session = event.data.object; stripe.checkout.sessions.listLineItems( session.id, { limit: 100 }, function(err, lineItems) { // Fulfill the purchase... try { fulfillOrder(session, lineItems); } catch (err) { return response.status(400).send(`Fulfillment Error: ${err.message}`); } } ); } response.status(200).end(); }); app.listen(4242, () => console.log('Running on port 4242')); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func fulfillOrder(session stripe.CheckoutSession) error { params := &stripe.CheckoutSessionListLineItemParams{ ID: stripe.String(session.Id), } // Grab the line items for the session params.Filters.AddFilter("limit", "", "100") i := session.ListLineItems(params) for i.Next() { // Access the line item using i.LineItem() } // TODO: Remove error and implement... return fmt.Errorf("given the Checkout Session %q, load your internal order from the database here.\nThen you can reconcile your order's quantities with the final line item quantity purchased.\nYou can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids.", session.Id) } http.HandleFunc("/webhook", func(w http.ResponseWriter, req *http.Request) { const maxBodyBytes = int64(65536) req.Body = http.MaxBytesReader(w, req.Body, maxBodyBytes) body, err := ioutil.ReadAll(req.Body) if err != nil { fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err) w.WriteHeader(http.StatusServiceUnavailable) return } // Pass the request body and Stripe-Signature header to ConstructEvent, along with the webhook signing key // You can find your endpoint's secret in your webhook settings endpointSecret := "whsec_..."; event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), endpointSecret) if err != nil { fmt.Fprintf(os.Stderr, "Error verifying webhook signature: %v\n", err) w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature return } // Handle the checkout.session.completed event if event.Type == "checkout.session.completed" { var session stripe.CheckoutSession err := json.Unmarshal(event.Data.Raw, &session) if err != nil { fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err) w.WriteHeader(http.StatusBadRequest) return } // Fulfill the purchase... if err := fulfillOrder(session); err != nil { fmt.Fprintf(os.Stderr, "Error fulfilling order: %v\n", err) w.WriteHeader(http.StatusBadRequest) return } } w.WriteHeader(http.StatusOK) }) ``` #### .NET ```dotnet using System; using System.IO; using Microsoft.AspNetCore.Mvc; using Stripe; // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; namespace workspace.Controllers { [Route("api/[controller]")] public class StripeWebHook : Controller { // You can find your endpoint's secret in your webhook settings const string secret = "whsec_..."; [HttpPost] public async Task Index() { var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync(); try { var stripeEvent = EventUtility.ConstructEvent( json, Request.Headers["Stripe-Signature"], secret ); // Handle the checkout.session.completed event // If on SDK version < 46, use class Events instead of EventTypes if (stripeEvent.Type == EventTypes.CheckoutSessionCompleted) { var session = stripeEvent.Data.Object as Checkout.Session; // Fulfill the purchase... try { this.FulfillOrder(session); } catch (NotImplementedException ex) { return BadRequest(); } } return Ok(); } catch (StripeException e) { return BadRequest(); } } private void FulfillOrder(Checkout.Session session) { var options = new SessionListLineItemsOptions { Limit = 100, }; var service = new SessionService(); StripeList lineItems = service.ListLineItems(session.Id, options); // TODO: Remove error and implement... throw new NotImplementedException($"Given the Checkout Session \"{session.Id}\" load your internal order from the database here.\n Then you can reconcile your order's quantities with the final line item quantity purchased. You can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids."); } } } ``` --- # Source: https://docs.stripe.com/disputes/prevention/advanced-fraud-detection.md # Advanced fraud detection Learn about tools developers can use to maximize Stripe's ability to prevent fraudulent payments. [Stripe.js](https://docs.stripe.com/js.md) is Stripe’s JavaScript library designed to enable businesses to securely collect sensitive payment information from the customer’s browser. The [Stripe In-App Payments](https://docs.stripe.com/payments/mobile.md) provides the native iOS and Android counterparts to Stripe.js. Stripe.js and the mobile SDKs provide advanced fraud detection by looking at signals about device characteristics and user activity that help distinguish between legitimate and fraudulent transactions. These signals power Stripe’s fraud prevention systems, such as *Radar* (Stripe Radar helps detect and block fraud for any type of business using machine learning that trains on data across millions of global companies. It’s built into Stripe and requires no additional setup to get started). The signals are transmitted to Stripe’s back end by periodically making requests to the `m.stripe.com` endpoint. Also, on each page where you load Stripe.js, it may load hCaptcha. hCaptcha is a type of CAPTCHA that helps stop fraud and provides additional signals to Stripe while being low friction for legitimate customers. To opt out of use of hCAPTCHA integration, reach out to [Stripe Support](https://support.stripe.com/contact/login). Our goal is to maximize payments from legitimate customers while minimizing fraud. Fraud can be one of the most challenging aspects of running an online business. Even businesses that don’t typically see significant amounts of fraud can see sudden, unexpected, and costly attacks. Stripe prevents more than 500 million USD in payment fraud for Stripe businesses every month. To do that, we collect and analyze information that helps us identify bad actors and bots, including both transactional data (such as amount, customer shipping address, date, and so on) and advanced fraud detection signals (device and activity signals). The details of what we collect and how we use it are disclosed in our [privacy policy](https://stripe.com/privacy) and [cookie policy](https://stripe.com/cookies-policy/legal). ## Types of signals ### Device characteristics Device characteristics are signals about a customer’s browser, screen, or device. They help Stripe identify configurations consistent with anomalous browsing behavior, as well as compare this behavior to similar patterns observed across other businesses on Stripe’s network. Combinations of these parameters that are rare or unlikely to reflect a real user’s computing environment can expose fraudulent transactions. ### Activity indicators Advanced fraud detection signals also include activity indicators from actual shoppers that help us distinguish legitimate shoppers from fraudulent purchasers and bots. For example, bots tend to move through a website and checkout form much faster than a real person would; card numbers are also frequently copy-pasted rather than typed. These signals include mouse activity indicators and how long a user spends on different pages when shopping, which are both predictive of bot-like behavior across the duration of a session. Stripe gathers data about the contents of the page only if they correspond to input fields in Stripe Elements. For example, Stripe might collect an email address to prefill Link signup and login. If the Stripe Element doesn’t have an email field, Stripe won’t collect that information from the contents of the page. This information is never saved. Signals corresponding to user activity are scoped to a single shopping session on a single site or app and aren’t linked across different shopping sessions, sites, or apps. ## When signals are collected The more activity Stripe’s fraud engines can observe, the better Stripe’s fraud prevention will be. Stripe therefore encourages including Stripe.js on every page of the shopping experience, not just the checkout page. This level of Stripe.js coverage gives Stripe the richest possible set of such signals to distinguish fraudulent purchasers from real customers. If Stripe.js isn’t used at all, the business must take on the full responsibility of *PCI compliance* (Any party involved in processing, transmitting, or storing credit card data must comply with the rules specified in the Payment Card Industry (PCI) Data Security Standards. PCI compliance is a shared responsibility and applies to both Stripe and your business), and additional fraud risk. The iOS and Android SDK collect advanced fraud detection signals for an app when the SDK object is instantiated. The data is only transmitted to Stripe during a tokenization request. ## Data privacy This advanced fraud detection signal data is never used for advertising and won’t be rented, sold, or given to advertisers, as outlined in our [privacy policy](https://stripe.com/privacy). Stripe only uses this data for fraud detection and security purposes, and retains it for as long as it’s useful for the purposes of fraud detection and security. Internally, this data is subject to strict access control policies enforced by Stripe, and restricted to a small number of Stripe employees working on fraud prevention and security. ## Disable advanced fraud detection Stripe users can decide to disable the collection of advanced fraud detection signals on their own websites and apps. Doing so increases their risk of fraud, especially [card testing](https://docs.stripe.com/disputes/prevention/fraud-types.md#card-testing). Stripe will continue to collect fraud detection signals on Stripe domains, like on [Stripe Checkout](https://docs.stripe.com/payments/checkout.md) payment pages. Additionally, disabling advanced fraud detection doesn’t affect the collection of events logged when a customer interacts with Stripe-managed fields in your checkout page (we use these events to prevent fraud and make sure Stripe Elements is working) nor basic device information collected during [3D Secure 2 authentication](https://support.stripe.com/questions/3d-secure-2-device-information) (we’re required to send this information to the issuing bank for their risk analysis). ### Stripe.js To disable advanced fraud detection signals with [Stripe.js](https://docs.stripe.com/js/including), set `advancedFraudSignals` as a query parameter in the Stripe.js script tag, or update to the latest version of the [Stripe.js module](https://github.com/stripe/stripe-js), use the `pure` export, and call `setLoadParameters`: #### HTML ```html ``` #### ES Module ```javascript import {loadStripe} from '@stripe/stripe-js/pure'; loadStripe.setLoadParameters({advancedFraudSignals: false}); const stripePromise = await loadStripe('<>'); ``` ### iOS SDK To disable advanced fraud detection signals with the [Stripe iOS SDK](https://github.com/stripe/stripe-ios), update to iOS SDK v19.1.1 or later. When configuring the Stripe SDK, set the `advancedFraudSignalsEnabled` property: #### Swift ```swift StripeAPI.defaultPublishableKey = "<>" StripeAPI.setAdvancedFraudSignalsEnabled(false) ``` #### Objective-C ```objc [StripeAPI setDefaultPublishableKey:@"<>"]; [StripeAPI setAdvancedFraudSignalsEnabled: NO]; ``` ### Android SDK To disable advanced fraud detection signals with the [Android SDK](https://github.com/stripe/stripe-android), update to Android SDK v14.4.0 or later. When configuring the Stripe SDK, set the `advancedFraudSignalsEnabled` property before instantiating or accessing any Stripe SDK objects: #### Kotlin ```kotlin class MyApp : Application() { override fun onCreate() { super.onCreate() Stripe.advancedFraudSignalsEnabled = false PaymentConfiguration.init( applicationContext, "<>" ) } } ``` #### Java ```java public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); Stripe.setAdvancedFraudSignalsEnabled(false); PaymentConfiguration.init( getApplicationContext(), "<>" ); } } ``` --- # Source: https://docs.stripe.com/payments/advanced.md # Build an advanced payments integration Learn how to create a custom payments integration using Stripe Elements and the Checkout Sessions API or the Payment Intents API. Instructions for LLMs: Stripe now recommends using Checkout Sessions API with the Payment Element over Payment Intents. Do not use the Payment Intent API unless the user explicitly asks. Learn more about Elements with Checkout Sessions API: https://docs.stripe.com/payments/quickstart-checkout-sessions. With Checkout Sessions (`ui_mode: "custom"`) and the Payment Element, the `client_secret` initializes Checkout itself (`stripe.initCheckout`, or use CheckoutProvider with React) and you confirm the payment client side differently. If using React, make sure you import from `@stripe/react-stripe-js/checkout`, use `CheckoutProvider` with client secret, and confirm using `checkout.confirm`. If using HTML, make sure you use `checkout = stripe.initCheckout({clientSecret: promise}); checkout.createPaymentElement(); paymentElement = checkout.createPaymentElement(); paymentElement.mount("#payment-element");` and confirm with `loadActionsResult = await checkout.loadActions(); actions = loadActionsResult.actions; error = await actions.confirm();`. Use the [Stripe Elements](https://docs.stripe.com/payments/elements.md) user interface with the [Checkout Sessions API](https://docs.stripe.com/api/checkout/sessions.md) or the [Payment Intents API](https://docs.stripe.com/api/payment_intents.md) to create a fully customized payments integration. To understand which API is better for your business, [compare the Checkout Sessions and Payment Intents APIs](https://docs.stripe.com/payments/checkout-sessions-and-payment-intents-comparison.md). ## Build a custom integration with full UI control Use [Stripe Elements](https://docs.stripe.com/payments/elements.md) to start building your own custom integration to accept payments. [Start building your payments integration](https://docs.stripe.com/payments/quickstart-checkout-sessions.md) ## Features and availability |   | [**Checkout Sessions API**](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=checkout) | [**Payment Intents API**](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=paymentintents) | | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | | **UI** | [Elements](https://docs.stripe.com/payments/elements.md) | [Elements](https://docs.stripe.com/payments/elements.md) | | **API** | [Checkout Sessions](https://docs.stripe.com/api/checkout/sessions.md) | [PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) | | **Integration effort** | Low coding | Most coding | | **Hosting** | Embed on your site | Embed on your site | | **UI customization** | Extensive customization with [Appearance API](https://docs.stripe.com/elements/appearance-api.md) | Extensive customization with [Appearance API](https://docs.stripe.com/elements/appearance-api.md) | | **PAYMENT METHODS**1 | | [Dynamically display](https://docs.stripe.com/payments/payment-methods/dynamic-payment-methods.md) 40+ payment methods | ✓ Supported | ✓ Supported | | Manage payment methods in the [Stripe Dashboard](https://dashboard.stripe.com/settings/payment_methods) without coding | ✓ Supported | ✓ Supported | | **[Faster checkout with Link](https://docs.stripe.com/payments/link.md)** | ✓ Supported | ✓ Supported | | **[Custom payment methods](https://docs.stripe.com/payments/payment-methods/custom-payment-methods.md)** | - Unsupported | ✓ Supported | 1For detailed support for each payment method, see [learn more about payment methods](https://docs.stripe.com/payments/payment-methods/overview.md). ### Compare payment scenario support See how Stripe supports different payment scenarios by each integration path. |   | [**Checkout Sessions API**](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=checkout) | [**Payment Intents API**](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=paymentintents) | | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | | [Set up future payments](https://docs.stripe.com/payments/save-and-reuse.md) | ✓ Supported | ✓ Supported | | [Save payment details during payment](https://docs.stripe.com/payments/save-and-reuse.md) | ✓ Supported | ✓ Supported | | [Place a hold on a payment method](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md) | ✓ Supported | ✓ Supported | | [Finalize payments on your server](https://docs.stripe.com/payments/finalize-payments-on-the-server.md) | ✓ Supported | ✓ Supported | | [Multi-step payment flow](https://docs.stripe.com/payments/build-a-two-step-confirmation.md) | - Unsupported | ✓ Supported | | [FLEXIBLE PAYMENT SCENARIOS](https://docs.stripe.com/payments/flexible-payments.md)1 | | [Multicapture](https://docs.stripe.com/payments/multicapture.md) | ✓ Supported | ✓ Supported | | [Overcapture](https://docs.stripe.com/payments/overcapture.md) | ✓ Supported | ✓ Supported | | [Extended authorization](https://docs.stripe.com/payments/extended-authorization.md) | ✓ Supported | ✓ Supported | | [Incremental authorization](https://docs.stripe.com/payments/incremental-authorization.md) | ✓ Supported | ✓ Supported | 1 Only available on [IC+ pricing](https://support.stripe.com/questions/understanding-blended-interchange-pricing). ## Customize checkout [Customize look and feel](https://docs.stripe.com/elements/appearance-api.md): Customize the appearance and behavior of your checkout page. [Manage payment methods](https://docs.stripe.com/payments/advanced/payment-methods/manage.md): Present the most applicable payment methods for each customer and each location. [One-click checkout options](https://docs.stripe.com/elements/express-checkout-element.md): Show multiple one-click payment buttons with a single component. [Send email receipts](https://docs.stripe.com/payments/advanced/receipts.md): Send payment or refund receipts automatically. ## Collect different payment details [Collect additional information](https://docs.stripe.com/payments/advanced/collect-additional-info.md): Collect shipping and other customer info during checkout. [Collect taxes](https://docs.stripe.com/tax/custom.md): Use Stripe Tax APIs to implement tax calculations in your custom integration. [Flexible payment scenarios](https://docs.stripe.com/payments/flexible-payments.md): Support complex payment flows through flexible and customizable acquiring features. ## Choose when you collect payment [Subscriptions](https://docs.stripe.com/billing/subscriptions/build-subscriptions.md?payment-ui=elements): Create and manage subscriptions to accept recurring payments. [Set up future payments](https://docs.stripe.com/payments/save-and-reuse.md?platform=web&ui=elements): Save payment details and charge your customers later. [Save payment details during payment](https://docs.stripe.com/payments/save-during-payment.md?platform=web&ui=elements): Save payment details during a payment. --- # Source: https://docs.stripe.com/payments/affirm.md # Affirm payments Offer your US and Canadian customers flexible financing while getting paid upfront with Affirm. [Affirm](https://www.affirm.com/) is a popular payment method in the US and Canada that gives your customers a way to split purchases over a series of payments. Pay in 4 interest-free installments or in monthly installments of up to 36 months. For information on payment method transaction fees, refer to [pricing details](https://stripe.com/pricing/local-payment-methods). To pay with Affirm, customers are redirected to Affirm’s site, where they [authorize](https://docs.stripe.com/payments/payment-methods.md#customer-actions) the payment by agreeing to the terms of a payment plan, then return to your website to complete the order. Affirm offers payment options based on factors such as customer credit, prior account history, order amount, and the type of goods or services being underwritten. After payment acceptance, the full amount of the order (minus fees) is made available to your Stripe account upfront, and Affirm collects the purchase amount from your customer, who repays Affirm directly over time. #### Payment method properties - **Customer locations** United States, Canada - **Presentment currency** USD or CAD - **Payment confirmation** Customer-initiated - **Payment method family** Buy now, pay later - **Recurring payments** No - **Payout timing** Standard - **Connect support** Yes - **Dispute support** [Yes, by email from Stripe](https://docs.stripe.com/payments/affirm.md#disputes-and-fraud) - **Manual capture support** Yes - **Refunds / Partial refunds** [Yes / Yes](https://docs.stripe.com/payments/affirm.md#refunds) #### Business locations - CA - US #### Product support - Connect - Payment Links - Checkout1 - Elements2 - Invoicing3 - Terminal 1Not supported when using Checkout in subscription mode or setup mode.2Express Checkout Element doesn’t support Affirm.3Not supported for subscription invoices. > Affirm only supports domestic transactions, meaning you can only sell to customers in the same country as your business. If you’re using [Dynamic payment methods](https://docs.stripe.com/payments/payment-methods/dynamic-payment-methods.md), Stripe handles a customer’s payment method eligibility automatically. If you use [payment_method_types](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-payment_method_types), you must either configure your integration so that it only presents Affirm to eligible customers, or use dynamic payment methods. ## Payment flow Below is a demonstration of the Affirm payment flow from your checkout page: ![](https://d37ugbyn3rpeym.cloudfront.net/videos/affirm_checkout.mp4) ## Get started You don’t have to integrate Affirm and other payment methods individually. If you use our front-end products, Stripe automatically determines the most relevant payment methods to display. Go to the [Stripe Dashboard](https://dashboard.stripe.com/settings/payment_methods) and enable Affirm. To get started with one of our hosted UIs, follow a quickstart: - [Checkout](https://docs.stripe.com/checkout/quickstart.md): Our prebuilt, hosted checkout page. - [Elements](https://docs.stripe.com/payments/quickstart.md): Our drop-in UI components. [Payment Links](https://docs.stripe.com/payment-links.md) also supports adding Affirm from the Dashboard. If you prefer to manually list payment methods, learn how to [manually configure Affirm as a payment](https://docs.stripe.com/payments/affirm/accept-a-payment.md). To accept in-person payments you need to manually list Affirm. Learn how to [accept Affirm on Terminal smart readers](https://docs.stripe.com/terminal/payments/additional-payment-methods.md). You can also let customers know Affirm payments are available by including the [Payment Method Messaging Element](https://docs.stripe.com/elements/payment-method-messaging.md) on your product, cart, and payment pages. We recommend adding a site messaging Element to help drive conversion. ## Payment options Depending on the cart order size, Affirm presents customers with Pay in 30, Pay in 4, or monthly installment offers. Term lengths and cart ranges are determined by Affirm and might change at their discretion. Regardless of the underlying payment option selected, Stripe makes the full amount of the funds (minus fees) available to you upfront and Affirm collects the purchase amount from your customer, who repays Affirm directly. These options include: - **Pay in 30**: Customers pay for the purchase in a single payment in 30 days, interest-free. - **Pay in 4**: Customers pay for purchases in four interest-free, biweekly payments over a 6 week term. - **Monthly installments**: Customers pay for purchases over a longer term of up to 36 months, which might include interest. Affirm supports two *financing packages* (A financing package is a configuration on your Stripe account to set the Affirm payment option terms for your buyers): Standard and Enhanced. By default, businesses get the Standard financing package. However, businesses with Stripe Dashboard access can view or change their financing package on the [Payment methods settings page](https://dashboard.stripe.com/login?redirect=%2Fsettings%2Fpayment_methods). Financing packages are identical across the US and Canada. #### Standard | Order minimum (USD and CAD) | Order maximum (USD and CAD) | Available payment options | | --------------------------- | --------------------------- | ------------------------------------------------------------------------------------- | | 35 (USD only) | 49.99 (USD only) | - Pay in 30 days - 0% APR (USD only) | | 50 | 99.99 | - Pay in 4 - 0% APR | | 100 | 499.99 | - Pay in 4 - 0% APR - 6 months - interest bearing - 12 months - interest bearing | | 500 | 699.99 | - 3 months - 0% APR - 6 months - interest bearing - 12 months - interest bearing | | 700 | 1,699.99 | - 6 months - 0% APR - 12 months - interest bearing - 18 months - interest bearing | | 1,700 | 30,000 | - 6 months - 0% APR - 12 months - interest bearing - 36 months - interest bearing | Rates vary from 10% to 36% APR, subject to eligibility. For example, a 800 USD purchase might cost 72.12 USD per month over 12 months at 15% APR. See [Affirm lending terms](http://affirm.com/disclosures) for more details. Platforms don’t qualify for the pay in 30 plan and 0% APR. #### Enhanced | Order minimum (USD and CAD) | Order maximum (USD and CAD) | Available payment options | | --------------------------- | --------------------------- | --------------------------------------------------------------------------- | | 35 (USD only) | 49.99 (USD only) | - Pay in 30 days - 0% APR (USD only) | | 50 | 99.99 | - Pay in 4 - 0% APR | | 100 | 499.99 | - Pay in 4 - 0% APR - 6 months - 0% APR - 12 months - interest bearing | | 500 | 699.99 | - 3 months - 0% APR - 6 months - 0% APR - 12 months - interest bearing | | 700 | 1,699.99 | - 6 months - 0% APR - 12 months - 0% APR - 18 months - interest bearing | | 1,700 | 30,000 | - 6 months - 0% APR - 12 months - 0% APR - 36 months - interest bearing | Rates vary from 10% to 36% APR, subject to eligibility. For example, a 800 USD purchase might cost 72.12 USD per month over 12 months at 15% APR. See [Affirm lending terms](http://affirm.com/disclosures) for more details. Platforms don’t qualify for the pay in 30 plan and 0% APR. ## Prohibited and restricted business categories For more information about Affirm eligibility for your account, go to your [Payment methods settings](https://dashboard.stripe.com/settings/payment_methods). In addition to the categories of [businesses restricted from using Stripe overall](https://stripe.com/restricted-businesses), the following categories are prohibited from using Affirm in all countries or are subject to additional requirements. - Business to business services - Home improvement services, including contractors and special trade contractors - Titled goods and auto loans, including entire cars, boats, and other motor vehicles (parts and services allowed) - Professional services (including legal, consulting, and accounting) - NFTs - Pre-orders Healthcare services are approved to use Affirm, however they’re subject to additional requirements. For the complete list of prohibited businesses and additional requirements, see [the Affirm Payment Terms](https://stripe.com/legal/affirm). ## Add Affirm branding to your website Use the [Payment Method Messaging Element](https://docs.stripe.com/elements/payment-method-messaging.md) on your site to let customers know that you offer Affirm ahead of checkout. You must comply with Affirm’s [marketing compliance guides](https://docs.affirm.com/developers/docs/compliance_and_guidelines) and use the Affirm [guide](https://businesshub.affirm.com/hc/en-us/articles/10653174159636-Affirm-Marketing-Compliance-Guides) that relates to the Affirm payment options you offer your customers. ## Refunds Returns are subject to the return policy that you display on your website. If your business allows returns, you can [refund](https://docs.stripe.com/refunds.md) Affirm transactions as you normally would for card payments. Affirm supports partial or full refunds for up to 120 days after the original purchase, and processes them asynchronously. After Stripe initiates a refund, Affirm pauses the customer’s payment plan and refunds the customer for any payments they’ve already made, minus any interest paid. Stripe doesn’t credit back the processing fees in the event of a refund. ## Disputes Customers must authenticate Affirm payments by logging into their Affirm account. This requirement helps reduce the risk of fraud or unrecognized payments. While Affirm covers losses incurred from customer fraud, Stripe might contact you on behalf of Affirm and request to stop or pause shipment before any losses are incurred. Comply promptly with these requests. Customers can dispute Affirm payments in certain cases—for example, if they receive faulty goods or don’t receive them at all. Customers can file a dispute after the date of purchase and there isn’t a time limitation for filing. The dispute process works like this: After the customer initiates a dispute, Stripe notifies you using: - Email notification - Stripe Dashboard - An API `charge.dispute.created` event (if your integration is set up to receive [webhooks](https://docs.stripe.com/webhooks.md)) Stripe holds back the disputed amount from your balance until Affirm resolves the dispute, which can take a maximum of 30 calendar days from dispute creation. Stripe requests that you upload compelling evidence that you fulfilled the purchase order [using the Stripe Dashboard](https://docs.stripe.com/disputes/responding.md#respond). This evidence can include: - Received return confirmation (for shipped goods returned from the customer to you) - Tracking ID - Shipping date - Record of purchase for intangible goods, such as IP address or email receipt - Record of purchase for services or physical goods, such as phone number or proof of receipt If you prefer to handle disputes programmatically, you can [respond to disputes using the API](https://docs.stripe.com/disputes/api.md). This information helps Affirm determine if a dispute is valid or if they should reject it. Make sure the evidence you provide contains as much detail as possible from what the customer provided at checkout. You must submit the requested information within 15 calendar days. Affirm makes a decision within 15 calendar days of evidence submission. If Affirm resolves the dispute with you winning, Stripe returns the disputed amount to your Stripe balance. If Affirm rules in favor of the customer, the balance charge becomes permanent. ## Customer emails After a customer uses Affirm to make a purchase, Affirm emails the customer with updates. These updates include information about the following events: - Affirm confirms or denies a loan. Affirms sends these updates when the payment_intent succeeds or when Affirm denies the loan. - A [refund](https://docs.stripe.com/refunds.md) completes. - A payment is cancelled, which results in Affirm cancellling the loan. - The customer completes a payment as part of the payment plan. Affirm only sends email updates about Affirm’s loan issuance to your customer. Continue to separately send emails related to the purchase such as order confirmation and shipping updates. ## Connect You can use [Stripe Connect](https://docs.stripe.com/connect.md) with Affirm to process payments on behalf of a connected account. *Connect* (Connect is Stripe's solution for multi-party businesses, such as marketplace or software platforms, to route payments between sellers, customers, and other recipients) users can use Affirm with the following charge types: - [Direct](https://docs.stripe.com/connect/direct-charges.md) - [Destination](https://docs.stripe.com/connect/destination-charges.md) - [Separate Charges and Transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md) ### Request Affirm capability You must turn on the Affirm payment method in [your platform settings](https://dashboard.stripe.com/settings/payment_methods) and [request](https://docs.stripe.com/connect/account-capabilities.md#requesting-unrequesting) the `affirm_payments` capability for your connected accounts that will accept Affirm payments. ### Set correct MCC Stripe and Affirm rely on merchant category codes (MCC) to determine eligibility of the connected accounts against the Affirm [prohibited business categories](https://docs.stripe.com/payments/affirm.md#prohibited-and-restricted-business-categories). Make sure that you set [correct MCCs](https://docs.stripe.com/connect/setting-mcc.md) for your connected accounts that use the Express Dashboard or a dashboard that isn’t hosted by Stripe. ### Merchant of record The [charge type](https://docs.stripe.com/connect/charges.md) of Connect payments might change the merchant name that appears on Affirm’s website or app during the redirect. The merchant of record determines the Stripe account authorized to create payments with a particular [PaymentMethod](https://docs.stripe.com/api/payment_methods/object.md). ## Buyer country filtering Buyer country filtering applies when you enable a dynamic payment method on the Payment Element or Checkout Session. Affirm only displays as a payment method option if the buyer’s country is supported. We determine the buyer’s country in the following priority order: 1. Shipping address country - The two-letter country code, not the full name of the country. 1. Geocoded country - The country based on the client-side IP address. --- # Source: https://docs.stripe.com/payments/checkout/after-the-payment.md # After the payment Customize the post-payment checkout process. [Fulfill orders](https://docs.stripe.com/checkout/fulfillment.md): Handle post-checkout tasks, such as fulfilling orders and shipping products. [Customize redirect behavior](https://docs.stripe.com/payments/checkout/custom-success-page.md): Display a confirmation page with your customer’s order information. [Recover abandoned carts](https://docs.stripe.com/payments/checkout/abandoned-carts.md): Recover abandoned checkout pages and boost revenue. [Analyze your conversion funnel](https://docs.stripe.com/payments/checkout/analyze-conversion-funnel.md): Analyze your Stripe Checkout conversion funnel with Google Analytics 4. [Send email receipts and paid invoices](https://docs.stripe.com/payments/checkout/receipts.md): Send payment or refund receipts automatically. --- # Source: https://docs.stripe.com/payments/afterpay-clearpay.md # Afterpay and Clearpay payments Offer your customers flexible financing while getting paid upfront with Afterpay (also known as Clearpay in the UK). > Afterpay has rebranded to Cash App Afterpay in the US. This update gives your business access to Cash App users without requiring any changes, unless you have custom Afterpay components. For more information about the change, see the [Cash App Afterpay support page](https://support.stripe.com/questions/afterpay-is-now-branded-as-cash-app-afterpay-in-the-us). Afterpay is a global payment method that allows your customers to split purchases into 4 interest-free installments, or longer term interest-bearing monthly installments (US only). For information on payment method transaction fees, refer to [pricing details](https://stripe.com/pricing/local-payment-methods). To pay with Afterpay, customers are redirected to Afterpay’s site, where they authorize the payment by agreeing to the terms of a payment plan, then return to your website to complete the order. Afterpay offers payment options based on factors such as customer credit, prior account history, order amount, and the type of goods or services being underwritten. After payment acceptance, the full amount of the order (minus fees) is made available to your Stripe account upfront, and Afterpay collects the purchase amount from your customer, who repays Afterpay directly over time. For more information, see [Payment options and limits](https://docs.stripe.com/payments/afterpay-clearpay.md#collection-schedule). #### Payment method properties - **Customer locations** United States, Canada, United Kingdom, Australia, New Zealand - **Presentment currency** USD, CAD, GBP, AUD, or NZD - **Payment confirmation** Customer-initiated - **Payment method family** Buy now, pay later - **Recurring payments** No - **Payout timing** Standard payout timing applies - **Connect support** Yes - **Dispute support** [Yes](https://docs.stripe.com/payments/afterpay-clearpay.md#disputed-payments) - **Manual capture support** Yes - **Refunds / Partial refunds** [Yes / Yes](https://docs.stripe.com/payments/afterpay-clearpay.md#refunds) #### Business locations Stripe accounts in the following countries can accept Afterpay payments with local currency settlement. - AU - CA - GB - NZ - US #### Product support - Connect - Payment Links - Checkout1 - Elements2 - Invoicing3 1Not supported when using Checkout in subscription mode or setup mode.2Express Checkout Element doesn’t support Afterpay or Clearpay.3Private preview for one-time invoices. Not supported for subscription invoices. > Afterpay and Clearpay only support domestic transactions, meaning you can only sell to customers in the same country as your business. If you’re using [Dynamic payment methods](https://docs.stripe.com/payments/payment-methods/dynamic-payment-methods.md), Stripe handles a customer’s payment method eligibility automatically. If you use [payment_method_types](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-payment_method_types), you must either configure your integration so that it only presents Afterpay and Clearpay to eligible customers, or use dynamic payment methods. ## Payment flow ![](https://d37ugbyn3rpeym.cloudfront.net/videos/afterpay_clearpay_payment_demo.mp4) ## Get started You don’t have to integrate Afterpay and other payment methods individually. If you use our front-end products, Stripe automatically determines the most relevant payment methods to display. Go to the [Stripe Dashboard](https://dashboard.stripe.com/settings/payment_methods) and enable Afterpay. To get started with one of our hosted UIs, follow a quickstart: - [Checkout](https://docs.stripe.com/checkout/quickstart.md): Our prebuilt, hosted checkout page. - [Elements](https://docs.stripe.com/payments/quickstart.md): Our drop-in UI components. [Payment Links](https://docs.stripe.com/payment-links.md) also supports adding Afterpay from the Dashboard. If you prefer to manually list payment methods, learn how to [manually configure Afterpay as a payment](https://docs.stripe.com/payments/afterpay-clearpay/accept-a-payment.md). You can also let customers know Afterpay payments are available by including the [Payment Method Messaging Element](https://docs.stripe.com/elements/payment-method-messaging.md) on your product, cart, and payment pages. We recommend adding a site messaging Element to help drive conversion. ## Payment options and limits Payment options vary by cart order size and country. In the US, Afterpay presents customers with Pay in 4, monthly installments, or both options. For all other markets, Afterpay presents customers with Pay in 4 only. - **Pay in 4**: customers pay for purchases in four or fewer interest-free, bi-weekly payments over a 6 week term. - **Monthly installments**: (US only) customers pay for purchases over a 6 or 12 month term that includes capped interest. Afterpay collects the first installment from the customer immediately, and the next installment either 2 weeks or 1 month after, depending on the payment schedule. You can accept payments from customers in the same country that you registered your Stripe account. Payments must also match the local currency of the country. The following table lists total transaction limits and installment schedules by country. | Stripe account and customer country | Currency | Transaction limits | | ----------------------------------- | -------- | ------------------ | | Australia | AUD | 1 - 4,000 AUD | | Canada | CAD | 1 - 2,000 CAD | | New Zealand | NZD | 1 - 4,000 NZD | | United Kingdom | GBP | 1 - 1,200 GBP | | United States | USD | 1 - 4,000 USD | ### United States In the US, a customer can be presented with both Pay in 4 and monthly installments, depending on the order amount: | Cart order range | Pay in 4 | Monthly Installments | | -------------------- | -------- | ------------------------------------ | | 1 - 399.99 USD | Yes | No | | 400 - 2,000 USD | Yes | Interest-bearing 6 or 12 month loans | | 2,000.01 - 4,000 USD | No | Interest-bearing 6 or 12 month loans | ## Prohibited business categories For more information about Afterpay eligibility for your account, go to your [Payment methods settings](https://dashboard.stripe.com/settings/payment_methods). In addition to the categories of [businesses restricted from using Stripe overall](https://stripe.com/restricted-businesses), the following categories are prohibited from using Afterpay. - Alcohol - Donations - Pre-orders - NFTs - B2B For the complete list, see the [terms of service](https://stripe.com/afterpay-clearpay/legal#restricted-businesses). ## Add Afterpay branding to your website Let your customers know you accept payments with Afterpay by including the [Payment Method Messaging Element](https://docs.stripe.com/elements/payment-method-messaging.md) on your product and cart pages. Afterpay also provides static [visual assets and branding guidance](https://www.afterpay.com/retailer-resources). In AU, CA, NZ and the US, consumers know Afterpay as ‘Afterpay’. In the UK, they know it as ‘Clearpay’. Make sure you pick the right location (see the footer in the [Afterpay documentation](https://www.afterpay.com/retailer-resources)) so that you get the appropriate assets. For Clearpay, see the [UK assets and branding guidance](https://www.clearpay.co.uk/en-GB/retailer-resources). ## Disputes Customers must authenticate Afterpay payments by logging into their Afterpay account. This requirement helps reduce the risk of fraud or unrecognized payments. Afterpay covers losses incurred from customer fraud or the inability to repay installments. However, Stripe might contact you on behalf of Afterpay and request to stop or pause a shipment before any losses are incurred. It’s important to comply promptly with these requests. Customers can dispute Afterpay payments in certain cases—for example, if they don’t receive the goods they paid for. Customers have up to 120 calendar days from the date of purchase to file a dispute. The dispute process works like this: After the customer initiates a dispute, Stripe notifies you using: - Email - The Stripe Dashboard - An API `charge.dispute.created` event (if your integration is set up to receive [webhooks](https://docs.stripe.com/webhooks.md)) Stripe holds back the disputed amount from your balance until Afterpay resolves the dispute. Stripe requests that you upload compelling evidence that you fulfilled the purchase order [using the Stripe Dashboard](https://docs.stripe.com/disputes/responding.md#respond). This evidence can include: - A received return confirmation (for shipped goods returned from the customer to you) - The tracking ID - The shipping date - A record of purchase for intangible goods, such as IP address or email receipt - A record of purchase for services or physical goods, such as phone number or proof of receipt If you prefer to handle disputes programmatically, you can [respond to disputes using the API](https://docs.stripe.com/disputes/api.md). This information helps Afterpay determine if a dispute is valid or if they should reject it. Make sure the evidence you provide contains as much detail as possible from what the customer provided at checkout. You must submit the requested information within 14 calendar days. Afterpay makes a decision within 30 calendar days of evidence submission. If Afterpay resolves the dispute with you winning, Stripe returns the disputed amount to your Stripe balance. If Afterpay rules in favor of the customer, the balance charge becomes permanent. ## Refunds You can refund Afterpay charges up to 120 days after the original payment. Refunds for Afterpay payments are asynchronous. ## Connect You can use [Stripe Connect](https://docs.stripe.com/connect/how-connect-works.md) with Afterpay to process payments on behalf of a connected account. *Connect* (Connect is Stripe's solution for multi-party businesses, such as marketplace or software platforms, to route payments between sellers, customers, and other recipients) users can use Afterpay with the following charge types: - [Direct](https://docs.stripe.com/connect/direct-charges.md) - [Destination](https://docs.stripe.com/connect/destination-charges.md) - [Separate Charges and Transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md) Stripe and Afterpay rely on merchant category codes (MCC) to determine eligibility of the connected accounts against the Afterpay [prohibited business categories](https://docs.stripe.com/payments/afterpay-clearpay.md#prohibited-business-categories). Make sure that you set [correct MCCs](https://docs.stripe.com/connect/setting-mcc.md) for your connected accounts that use the Express Dashboard or a dashboard that isn’t hosted by Stripe. ## Buyer country filtering Buyer country filtering applies when you enable a dynamic payment method on the Payment Element or Checkout Session. Afterpay only displays as a payment method option if the buyer’s country is supported. We determine the buyer’s country in the following priority order: 1. Shipping address country - The two-letter country code, not the full name of the country. 1. Geocoded country - The country based on the client-side IP address. --- # Source: https://docs.stripe.com/radar/analytics.md # Source: https://docs.stripe.com/payments/analytics.md # Payments analytics Learn about the performance of your payments using key metrics and reports. The [Payments analytics](https://dashboard.stripe.com/acceptance) page in the Stripe Dashboard helps you track and analyze your payment performance. You can find reports on authentication, disputes, and card acceptance. You can also apply advanced filters and compare different time periods for your payments data to evaluate your payments history. ![Payments analytics page](https://b.stripecdn.com/docs-statics-srv/assets/overview.61ec7a7cfe8a8bc7a503c00c82d59509.png) The Payments analytics page in the Dashboard. Certain analytics (such as [authentication](https://docs.stripe.com/payments/analytics/authentication.md)) require [3D Secure](https://docs.stripe.com/payments/3d-secure.md) enablement. This authentication method verifies the identities of customers to help manage fraud, mitigate liability, and comply with [Strong Customer Authentication regulations](https://docs.stripe.com/strong-customer-authentication.md). ## Analyze key metrics and reports [Acceptance analytics](https://docs.stripe.com/payments/analytics/acceptance.md): Understand what influences card payments acceptance, why payments fail or get declined, and how to improve your payment success rate. [Authentication analytics](https://docs.stripe.com/payments/analytics/authentication.md): Analyze how 3D Secure impacts your payment success rate for card payments. [Disputes analytics](https://docs.stripe.com/payments/analytics/disputes.md): Learn how dispute volume, rates, and outcomes affect your business. [Payment methods analytics](https://docs.stripe.com/payments/analytics/payment-methods.md): Learn which payment methods your customers use most frequently. ## Payment uplift features [Payments optimization](https://docs.stripe.com/payments/analytics/optimization.md): Learn how Authorization Boost features can help increase your payment success rate and reduce network costs. [Dashboard recommendations](https://docs.stripe.com/payments/analytics/recommendations.md): Use the recommended features to help increase revenue and improve fraud detection. --- # Source: https://docs.stripe.com/capital/api-integration.md # Build a custom Capital program Integrate with our API to build a custom Capital program. > Capital for platforms is available in [public preview](https://docs.stripe.com/release-phases.md). [Stripe Capital](https://docs.stripe.com/capital/how-capital-for-platforms-works.md) enables your platform to retrieve prequalified financing offers for your connected accounts, expose a compliant financing offer application, and provide ongoing reporting for in-progress financing. This guide describes how [Connect](https://docs.stripe.com/connect.md) platforms can integrate with the [Capital API](https://docs.stripe.com/api/capital/financing_offers.md). ### Capital lifecycle To launch the program, your platform must support the three phases of the Capital lifecycle: - Marketing financing offers to eligible users. - Providing access to the financing reporting page for in-progress financing. - Continuing to provide access to the financing reporting page after users have fully paid their financing. This guide explains how to: - Retrieve financing offers for eligible users. - Make the financing application available to users. - Provide users access to the financing reporting page. ## Confirm your branding settings [Dashboard] All users who receive Capital offers see your business name, icon, logo, and branding color in the offer emails, application, and financing reporting page. Navigate to your **[Connect branding settings](https://dashboard.stripe.com/settings/connect/stripe-dashboard/branding)**, and make sure your platform’s branding settings are correct. ![Capital offer application page](https://b.stripecdn.com/docs-statics-srv/assets/offer-page.66c647c99e2b25b314b7ca8be2cc98a4.png) ## Create a test undelivered financing offer [Dashboard] We recommend using a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) to build your integration. In a sandbox, visit the [Capital Dashboard](https://dashboard.stripe.com/test/connect/capital). 1. Click **Create** to open the **Create financing offer** modal, which allows you to create test financing offers. The default options create an undelivered financing offer with a 1,000 USD financing amount. 1. Leave the default options, and click **Create financing offer**. 1. From the Dashboard, click the row corresponding to the offer you created. The loans and financing section of the connected account details page displays details about the user’s financing offer. ## Retrieve financing offers [Server-side] You can retrieve financing offers for all of your platform’s users with the [List financing offers](https://docs.stripe.com/api/capital/financing_offers/list.md) endpoint. #### curl ```bash curl https://api.stripe.com/v1/capital/financing_offers \ -u <>: ``` If the offer is successfully created, you receive a response similar to the following: ```json { "object": "list", "url": "/v1/capital/financing_offers", "has_more": false, "data": [ { "id": "financingoffer_abc123", "object": "capital.financing_offer", ..., }, {...} ] } ``` You can look up a financing offer using the [Retrieve financing offer](https://docs.stripe.com/api/capital/financing_offers/retrieve.md#retrieve_financing_offer) endpoint. Retrieve the first financing offer from the list above. #### curl ```bash curl https://api.stripe.com/v1/capital/financing_offers/financingoffer_abc123 \ -u <>: ``` ## Send offer email [Server-side] Stripe sends the `capital.financing_offer.created` *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) after a financing offer is created. Update your webhook integration to listen for the `capital.financing_offer.created` webhook. If you send your own offer emails, the webhook is an important notification to notify the user of their offer. > Make sure the contents of your offer email comply with banking regulations by reviewing the [marketing guidance](https://docs.stripe.com/capital/marketing.md) page. Submit all changes to user-facing materials for review and approval using the [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835). In the email, link users to a dedicated Capital section in your platform dashboard. Users access the Capital financing application with [Account Links](https://docs.stripe.com/api/account_links.md). Account Links expire shortly after they’re generated, so provide a way for users to regenerate the application link. Include a link to the financing application in your platform dashboard by generating an Account Link of type `capital_financing_offer`. #### curl ```bash curl https://api.stripe.com/v1/account_links \ -u <>: \-d account=acct_123 \ # The URL the user will be redirected to if the account link is expired, has been previously-visited, or is otherwise invalid. -d refresh_url="https://example.com/reauth" \ # The URL the user will be redirected to after completing the linked flow. -d return_url="https://example.com/thanks" \ -d type=capital_financing_offer ``` If the creation of an account link is successful, you receive a response similar to the following: ```json { "object": "account_link", "created": 1611264596, "expires_at": 1611264896, "url": "https://connect.stripe.com/capital/offer/SrjgLUfa0O7K" } ``` After updating your webhook integration, create another offer in the [Dashboard](https://dashboard.stripe.com/test/connect/capital), and verify you receive the `capital.financing_offer.created` webhook. ### Mark the offer as delivered Update your webhook integration to [mark the financing offer as delivered](https://docs.stripe.com/api/capital/financing_offers/mark_delivered.md) after sending the offer email. You can verify that the financing offer’s status is delivered using either the [Dashboard](https://dashboard.stripe.com/test/connect/capital) or the [Financing Offers API](https://docs.stripe.com/api/capital/financing_offers/retrieve.md). #### curl ```bash curl https://api.stripe.com/v1/capital/financing_offers/financingoffer_abc123/mark_delivered \ -u <>: ``` You must mark an offer as delivered to verify with Stripe that you’ve marketed the offer to the connected account. When you send your offer emails, you need to BCC [capital-offers@stripe.com](mailto:capital-offers@stripe.com). ## Listen for status changes [Server-side] In addition to the `capital.financing_offer.created` webhook, Stripe sends additional webhooks as the financing offer transitions through different states. The following is a full list of the webhooks you can receive: | **Webhook identifier** | **Trigger** | | --------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | `capital.financing_offer.created` | Financing offer is created | | `capital.financing_offer.accepted` | User submits their offer application | | `capital.financing_offer.paid_out` | Stripe approves the offer application and funds are paid out to the user | | `capital.financing_offer.fully_repaid` | User fully pays the financing balance | | `capital.financing_offer.canceled` | User cancels the financing offer | | `capital.financing_offer.rejected` | User’s application isn’t approved | | `capital.financing_offer.expired` | Financing offer expires and is no longer available | | `capital.financing_offer.replacement_created` | Financing offer is [replaced](https://docs.stripe.com/capital/replacements.md) with a new financing offer | From the [Dashboard](https://dashboard.stripe.com/test/connect/capital), find the offer you delivered earlier. 1. Click the overflow menu (⋯). 1. Click the **Expire offer** option, which lets you simulate expiring the offer. 1. Verify you receive the `capital.financing_offer.expired` webhook. With the exception of `capital.financing_offer.canceled`, you can simulate all webhooks while in a testing environment. ## Apply for an offer [Dashboard] [Server-side] You can simulate the `capital.financing_offer.accepted` webhook by applying for an offer. 1. From the [Dashboard](https://dashboard.stripe.com/test/connect/capital), create a delivered offer with a maximum financing amount of 20,000 USD. 1. Generate an account link of type `capital_financing_offer`, and go to the link. Here, you can preview what the application looks like for your users. 1. Continue to the end of the application, and click **Submit**. 1. Verify you received the `capital.financing_offer.accepted` webhook. 1. View the offer in the Dashboard, and check it has status accepted. ### View the application tracker A financing offer with status accepted is pending application review by the Stripe [servicing](https://docs.stripe.com/capital/servicing.md) team. While this review takes place, you can direct the user to the financing reporting page. The financing reporting page contains an application tracker with an approximate timeline of the application review. Generate an [Account Link](https://docs.stripe.com/api/account_links.md) of type `capital_financing_reporting`. #### curl ```bash curl https://api.stripe.com/v1/account_links \ -u <>: \-d account=acct_123 \ # When the user refreshes the page, where should we redirect them -d refresh_url="https://example.com/reauth" \ # When the user completes the application, where should they return -d return_url="https://example.com/thanks" \ -d type=capital_financing_reporting ``` Navigate to the link, and view the application tracker. ## Approve the application [Dashboard] In the [Dashboard](https://dashboard.stripe.com/test/connect/capital), find the row corresponding to the accepted offer. 1. Click the overflow menu (⋯). 1. Click the **Approve and disburse funds** option, which lets you simulate an application approval and funds disbursal. 1. Verify you receive the `capital.financing_offer.paid_out` webhook, which notifies you that the financing has been paid out. 1. Generate another [Account Link](https://docs.stripe.com/api/account_links.md) of type `capital_financing_reporting`. This reporting page provides access to outstanding balance and payout and payment transaction details for the user’s in-progress financing. 1. Click **Make payment**, and create a manual payment. > It takes up to 15 minutes for the **Make payment** button to be enabled on the reporting page for test financing offers. After the transaction is processed, view the payment in the transactions table. You can programmatically view the user’s paid-down financing amount for in-progress financing using the [financing summary API](https://docs.stripe.com/api/capital/financing_summary.md). #### curl ```bash curl https://api.stripe.com/v1/capital/financing_summary \ -u <>: \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" \ ``` If the retrieval of the financing summary is successful, you receive a response similar to the following: ```json { "object": "capital.financing_summary", "details": { "currency": "usd", "advance_amount": 1000000, "fee_amount": 100000, "withhold_rate": 0.2, "remaining_amount": 999950, "paid_amount": 50, "current_repayment_interval": { "due_at": 123456789, "remaining_amount": 50, "paid_amount": 50 }, "repayments_begin_at": 123456789, "advance_paid_out_at": 123456789 } } ``` ## Fully pay the financing [Dashboard] In the [Dashboard](https://dashboard.stripe.com/test/connect/capital), find the row corresponding to the paid-out financing. 1. Click the overflow menu (⋯). 1. Click the **Repay offer** option, which lets you simulate fully paying down the financing balance. 1. Verify you receive the `capital.financing_offer.fully_repaid` webhook, which notifies you that the financing has been fully paid. 1. Generate another [Account Link](https://docs.stripe.com/api/account_links.md) of type `capital_financing_reporting`. After a user pays the total amount of their financing, they can access past financing details on the reporting page at any time. ## Review your test integration By now, your integration: - Responds to the `capital.financing_offer.created` webhook by sending an offer email and marking the offer as delivered - Exposes the financing application link in your platform dashboard - Exposes the financing reporting link in your platform dashboard The Capital section of your platform dashboard might appear differently depending on which phase the user’s financing is in. Review the state diagram below for a list of possible financing offer status values. Capital financing offer state machine (See full diagram at https://docs.stripe.com/capital/api-integration) ## Prepare to enable automatic offers When automatic offers are enabled in live mode, Stripe automatically creates financing offers for your users on a daily basis. Before enabling automatic offers, make sure that you: 1. Confirm and update email addresses for your users through the [Comms Center](https://dashboard.stripe.com/connect/comms_center/collect) if you’re planning to leverage Stripe co-branded no-code offer emails. To be eligible for Capital financing, users must have an email saved with Stripe so that they can receive transactional emails such as payment progress updates. 1. [Contact us](mailto:capital-review@stripe.com) to enable live mode access to the financing offers API. ### Enable additional features Over time, some of your users might become eligible for refills. Refills are additional financing offers sent to users who have made substantial payment progress towards their in-progress loans. Follow the [refills integration guide](https://docs.stripe.com/capital/refills.md) to update your integration to support refill financing offers. If you want to include Capital transactions on your platform dashboard and update your users payout reporting, refer to the [reporting and reconciliation guide](https://docs.stripe.com/capital/reporting-and-reconciliation.md). ## See also - [Refill offers](https://docs.stripe.com/capital/refills.md) - [Replace offers](https://docs.stripe.com/capital/replacements.md) --- # Source: https://docs.stripe.com/disputes/api.md # Source: https://docs.stripe.com/revenue-recognition/api.md # Source: https://docs.stripe.com/api.md # API Reference The Stripe API is organized around [REST](http://en.wikipedia.org/wiki/Representational_State_Transfer). Our API has predictable resource-oriented URLs, accepts [form-encoded](https://en.wikipedia.org/wiki/POST_\(HTTP\)#Use_for_submitting_web_forms) request bodies, returns [JSON-encoded](http://www.json.org/) responses, and uses standard HTTP response codes, authentication, and verbs. You can use the Stripe API in test mode, which doesn’t affect your live data or interact with the banking networks. The API key you use to [authenticate](https://docs.stripe.com/api/authentication.md) the request determines whether the request is live mode or test mode. Test mode supports some [v2 APIs](https://docs.stripe.com/api-v2-overview.md#limitations). The Stripe API doesn’t support bulk updates. You can work on only one object per request. The Stripe API differs for every account as we release new [versions](https://docs.stripe.com/api/versioning.md) and tailor functionality. Log in to see docs with your test key and data. ## Just getting started? Check out our [development quickstart](https://docs.stripe.com/development/quickstart.md) guide. ## Not a developer? Use Stripe’s [no-code options](https://docs.stripe.com/payments/no-code.md) or apps from [our partners](https://stripe.partners/) to get started with Stripe and to do more with your Stripe account—no code required. ### Base URL ```plaintext https://api.stripe.com ``` --- # Source: https://docs.stripe.com/revenue-recognition/data-import/apple-app-store.md # Stripe Connector for the Apple App Store Manage your revenue recognition in Stripe by importing data from the Apple App Store. The [Stripe Connector for the Apple App Store](https://docs.stripe.com/stripe-data/import-external-data/connectors/apple-app-store.md) lets you automatically import subscription purchases from the Apple App Store into [Stripe Revenue Recognition](https://docs.stripe.com/revenue-recognition.md). The benefits of using Stripe Revenue Recognition for the Apple App Store are: - **Near real-time availability**: Set up daily, automated imports from the Apple App Store. This minimizes manual work and reduces corrections at month-end. - **Increased accuracy**: Improve recognition accuracy by considering time zone differences. - **Improved refund treatment**: Associate refunds with original purchases, and generate more accurate refund journal entries that adjust deferred revenue instead of treating refunds as negative line items. - **Audit by subscribers**: Break down numbers on a per subscriber basis to help with audits. ## Get started To import data from the Apple App Store, [set up the Stripe Connector for the Apple App Store](https://docs.stripe.com/stripe-data/import-external-data/connectors/apple-app-store.md). It can take up to 24 hours for your reports to reflect imported data. ### Backfill historical data When you onboard, the connector backfills up to 1 year of historical data. ### Handle Apple transactions previously imported through manual data import If you previously imported data from the Apple App Store using the Stripe Revenue Recognition [data import](https://docs.stripe.com/revenue-recognition/data-import.md#general-import) feature, you want to avoid double-counting Apple revenue upon switching to the automated connector. To migrate from manual data imports to the connector, [delete](https://docs.stripe.com/revenue-recognition/data-import/manage-imported-data.md#transactions-deletion) all Apple transactions from the past year that you manually uploaded using data import CSVs. The connector replaces these transactions with the entries it generates during import. > Because the connector only backfills up to 1 year of historical data, we recommend keeping your data import CSV uploads for Apple transactions that occurred more than 1 year ago. ## Examples ### Subscription purchase A subscriber purchases 1 unit of a News Plan Monthly subscription on December 3. The subscription is valid for 1 month, which means the service period is December 3 to January 3. The customer pays 32 USD, but the developer receives 31 USD. The developer proceeds count toward revenue rather than customer price, because the customer price also includes taxes and Apple commissions. Revenue is billed and paid in full on December 3. Stripe recognizes most of the revenue in December, and a smaller portion in January. At the end of January, the summary might look like this: | Account | December | January | | ---------------- | -------- | ------- | | External Asset | +31 | | | Revenue | +28 | +3 | | Deferred Revenue | +3 | -3 | ### Subscription refund A subscriber purchases a 3-month subscription on January 2. The service period is January 2 to April 2. The customer pays 91 USD, but the developer receives 90 USD. On February 1, the customer receives a full refund. During a full refund: - The customer receives their money back. - Recognized revenue is offset by the refunds in a contra revenue account. - The unused portion of the subscription revenue is cleared from the deferred revenue. The refund reduces the external assets balance by 90 USD. The customer received 30 days of service, so you add 30 USD to the external refunds balance. The remainder of the deferred revenue–60 USD in this example–is also cleared. At the end of April, the summary might look like this: | Account | December | January | | ---------------- | -------- | ------- | | Revenue | +30 | | | Deferred Revenue | +60 | -60 | | External Asset | +90 | -90 | | External Refunds | | +30 | ### Free trial Stripe doesn’t generate journal entries for free trials. ## Limitations The most detailed level of reporting that Stripe can provide is audit by subscriber. We can’t provide an audit by invoice view because the financial reports from the Apple App Store don’t include invoice IDs. Stripe also can’t book tax liability and Apple commissions because Apple doesn’t provide this data. ## Audit numbers To view account balances for an Apple subscriber: 1. Click a number in the [Monthly summary](https://docs.stripe.com/revenue-recognition/reports/monthly-summary.md) section to view a list of customers. Apple subscribers have names that consist solely of numbers. 1. Click any Apple subscriber to enter the audit view. --- # Source: https://docs.stripe.com/tax/supported-countries/asia-pacific.md # Tax in Asia Pacific Use Stripe Tax to calculate, collect, and report tax in Asia Pacific. In Asia Pacific (APAC), Stripe supports tax calculation for businesses making sales into a [range of countries](https://docs.stripe.com/tax/supported-countries/asia-pacific/collect-tax.md). The requirements for tax registration, as well as which types of transactions are included, vary from country to country. For each country listed, you can find information about: - The types of tax Stripe can help you collect. - The registration threshold that determines when you’re required to register for tax collection. - What kinds of products or sales are subject to tax calculation. - The types of transactions covered. - Resources about how to register with local tax authorities. Stripe can collect tax if your business is based in Australia, Hong Kong, Japan, New Zealand, Singapore, and the United Arab Emirates. To collect tax on Stripe in other listed APAC countries, your business needs to be a remote seller with no physical presence (such as a shop or warehouse). ## When and how to register for tax collection There are different rules for when and how you need to register to collect tax depending on the country. See [Thresholds](https://dashboard.stripe.com/tax/thresholds) to get insights about your potential tax registration obligations in each location. Stripe only monitors if you have reached a tax threshold for sales outside of the country your business is based in. Stripe also notifies you with email and Dashboard alerts when you might need to register to collect tax. Learn more about how the [monitoring tool works](https://docs.stripe.com/tax/monitoring.md). See [Needs attention](https://dashboard.stripe.com/tax/locations?primary_tab=needs_attention) tab to get insights about your potential tax registration obligations in each location. Stripe only monitors if you have reached a tax threshold for sales outside of the country your business is based in. Stripe also notifies you with email and Dashboard alerts when you might need to register to collect tax. Learn more about how the [monitoring tool works](https://docs.stripe.com/tax/monitoring.md). After you’ve registered with a country, go to [Registrations](https://dashboard.stripe.com/tax/registrations) to add your registrations to Stripe in the Dashboard to start collecting tax on your transactions in that location. After you’ve registered with a country, go to [Locations](https://dashboard.stripe.com/tax/locations) to add your registrations to Stripe in the Dashboard to start collecting tax on your transactions in that location. ## How we calculate taxes Learn how Stripe calculates taxes for your sales in Asia Pacific. ### Map your product to our product tax codes Stripe can calculate tax for [any of the product tax codes you assign to your products](https://docs.stripe.com/tax/tax-codes.md) and for domestic and cross-border sales in Australia, Hong Kong, Japan, New Zealand, Singapore, and the United Arab Emirates. For other supported APAC countries, Stripe can only calculate tax for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) sold by remote sellers. Digital products are non-physical items or services that are delivered, given, or rendered electronically. This includes digital goods and electronically supplied services. We determine whether you’re selling digital products or physical goods using the [product tax code](https://docs.stripe.com/tax/tax-codes.md) you assigned to your product. ### Domestic transactions A transaction where your business and your customer are in the same country is called a domestic transaction. Stripe assumes the sale of most goods or services to be taxable unless the tax authority has specifically made them exempt. ### Cross-border transactions A cross-border transaction is where your customer is located in a different country to your business or when goods are shipped from one country to another. Stripe calculates tax on a cross-border transaction taking into account the following factors: - The location of your business. - The tax registrations you’ve added to Stripe. - The location of the buyer. - The location where the activity is performed. - The type of the product sold (based on which [product tax code](https://docs.stripe.com/tax/tax-codes.md) you assigned to your product). - The status of the customer (whether they’re an individual or a business). Digital products are generally taxable in the country where your customer is located. However sales of digital products to businesses in other countries might have reverse charge applied. With reverse charge, your business provides an invoice for the purchase so that your customer can calculate the tax. When physical goods are shipped to a customer in a different country to your business, the transaction is referred to as an export. Exports are zero rated and Stripe applies the [zero rate](https://docs.stripe.com/tax/zero-tax.md). The transaction might still be subject to taxes and customs duties in the country your customer is in. Stripe doesn’t calculate these. ## Report and file your taxes Stripe Tax has filing partners—Taxually, Marosa, and Hands-off Sales Tax (HOST)—to help automate your tax filing. These partners automatically sync your tax transaction data in real time, eliminating the need for manual data entry or file transfers. Learn more about [tax filing](https://docs.stripe.com/tax/filing.md). Stripe also provides reports of your completed tax transactions. Go to [Registrations](https://dashboard.stripe.com/tax/registrations) to access these reports. Learn more about [the different types of reports](https://docs.stripe.com/tax/reports.md). Stripe also provides reports of your completed tax transactions. Go to [Locations](https://dashboard.stripe.com/tax/locations) to access these reports. Learn more about [the different types of reports](https://docs.stripe.com/tax/reports.md). You’re responsible for filing and remitting your taxes. Stripe doesn’t file taxes on your behalf. --- # Source: https://docs.stripe.com/issuing/purchases/atm-usage.md # Use cards at automated teller machines (ATMs) Learn how you can use your Stripe Issuing cards at ATMs. You can use your US-issued cards for ATM cash withdrawals if you enable the feature for your Stripe account, and set up valid PINs for your cards. ## Enable ATM withdrawals ATM withdrawals aren’t enabled by default, so you need to request approval for your use case [through support](https://support.stripe.com/?contact=true). In addition, make sure all your relevant cards have PINs set up by following our [PIN management guide](https://docs.stripe.com/issuing/cards/pin-management.md). ## Treatment of ATM transactions Stripe Issuing treats ATM withdrawals as standard transactions, but a few characteristics of the authorization signal that it’s an ATM withdrawal: - The [merchant category code](https://docs.stripe.com/api/issuing/authorizations/object.md#issuing_authorization_object-merchant_data-category_code) is set to 6011—`Automated Cash Disburse`. - An ATM [fee value](https://docs.stripe.com/api/issuing/authorizations/object.md#issuing_authorization_object-amount_details-atm_fee) might be present. - The [PIN check](https://docs.stripe.com/api/issuing/authorizations/object.md#issuing_authorization_object-verification_data-pin_check) is a `match`. You can approve or decline them using the same [webhook integration](https://docs.stripe.com/issuing/controls/real-time-authorizations.md) as other authorizations. ## Restrictions - **Limits**: ATM withdrawals are subject to a daily maximum limit. Your support representative can share your limit with you and work to increase it if it’s not sufficient for your use case. - **Cash deposits**: Stripe-issued cards aren’t enrolled in any ATM cash deposit programs and don’t have the ability to accept cash deposits. Cash deposit-enabled ATMs won’t trigger prompts for deposits when a Stripe-issued card is used. - **Region availability**: ATM withdrawals aren’t supported for cards issued in the UK or EU. [Contact support](https://support.stripe.com/?contact=true) for information about future availability in these regions. ## Fees Stripe doesn’t assess any fees of its own for ATM withdrawals, but ATM operators often do. These fees are generally: - **ATM use surcharge**: Added to the total transaction amount (this is the [atm fee](https://docs.stripe.com/api/issuing/authorizations/object.md#issuing_authorization_object-amount_details-atm_fee) amount a cardholder sees at the ATM.) - **Dynamic Currency Conversion (DCC)**: When the cardholder is given the option between a local currency and the card’s default currency (for example, using a US issued card in the EU), ATMs generally apply a markup on conversion rates when a cardholder picks the card’s default currency. While this isn’t an explicit fee, the conversion rates functionally behave as a tax on ATM transactions. Neither the ATM provider nor Stripe apply any cash advance fees or annual percentage rate (APR) to an ATM withdrawal. Different markets have different ATM rules and fee structures that influence the frequency and intensity of the fees charged, but the way we describe the fees above generally applies regardless of the country. If an ATM charges a fee to a cardholder, we’ll pass it on as part of the amount for a given authorization. Otherwise, cardholders and issuing users won’t see any impact. --- # Source: https://docs.stripe.com/revenue-recognition/reports/audit-numbers.md # Audit your numbers Use the Stripe Dashboard to examine the details of your revenue numbers. You can get a detailed view of accounting numbers from the Dashboard either by customers or by transactions for: - Each number in the [monthly summary report](https://docs.stripe.com/revenue-recognition/reports/monthly-summary.md) - Each number in the [revenue waterfall report](https://docs.stripe.com/revenue-recognition/reports/waterfall.md) - Each number in the AR aging summary report - A customer - An invoice - An invoice line item - A payment - An Apple subscriber - A Google order ## Monthly summary report Choose a month in [the monthly summary section](https://dashboard.stripe.com/revenue-recognition) to get a report of the activity that occurred during that time. Click an amount in the report to see the details of this number broken down into a list of customers and their total amount for the month. In the customer list, click a customer name to see all their transactions for the month. ## Revenue waterfall report Select a range of dates in [the waterfall section](https://dashboard.stripe.com/revenue-recognition/accounting-reports) (by month-year) to see the distribution of revenue across one or more accounting periods. Click an amount in the report to see the details of this number broken down into a list of customers and their total. In the customer list, click a customer name to see all their transactions for the specified dates. ## AR aging summary report Specify a time period in [the AR aging summary section](https://dashboard.stripe.com/revenue-recognition) to see unpaid invoice balances along with the length of time the invoices have been outstanding (age). Click an amount in the table to see the details of this number broken down into a list of customers or invoices. From the customer list, select a customer to see all their invoices for the specified time period and age. From the invoice list, select an invoice to see its invoice details. ## Audit numbers for a customer To view account balances for a customer: 1. Select a customer from the [Customers view](https://dashboard.stripe.com/customers) in the Dashboard. 1. In the **Invoices** section, click **View revenue recognition** to see the customer’s accounting details, which include: - The total balance for each account - The details on each account across the accounting periods ## Audit numbers for an invoice To view account balances for an invoice: 1. Select an invoice from the [Invoices view](https://dashboard.stripe.com/invoices) in the Dashboard. 1. Scroll down to the **Accounting** section to see the invoice’s accounting details, which include: - The total balance for each account - The details on each account across the accounting periods ## Audit numbers for an invoice line item To view account balances for an invoice line item: 1. Select an invoice from the [Invoices view](https://dashboard.stripe.com/invoices) in the Dashboard. 1. In the **Summary** section, click the overflow menu (⋯) next to the line item > **View revenue recognition** to see the line item’s accounting details, which include: - The total balance for each account - The details on each account across the accounting periods ## Audit numbers for a payment To view account balances for a payment: 1. Select a payment from the [Payments view](https://dashboard.stripe.com/payments) in the Dashboard. 1. In the **Payment breakdown** section, click the overflow menu (⋯) > **View revenue recognition** to see the payment’s accounting details, which include: - The total balance for each account - The details on each account across the accounting periods ## Audit numbers for an Apple subscriber View Apple subscribers as customers in the [Monthly summary](https://docs.stripe.com/revenue-recognition/reports/monthly-summary.md) section in the Customer tab. For detailed steps, see [Stripe Connector for the Apple App Store page](https://docs.stripe.com/revenue-recognition/data-import/apple-app-store.md#audit-numbers). ## Audit numbers for a Google order View Google orders as invoices starting from the [Monthly summary](https://docs.stripe.com/revenue-recognition/reports/monthly-summary.md) section in the Invoice tab. For detailed steps, visit the [Stripe Connector for Google Play page](https://docs.stripe.com/revenue-recognition/data-import/google-play.md#audit-numbers). --- # Source: https://docs.stripe.com/tax/supported-countries/asia-pacific/australia.md # Collect tax in Australia Learn how to use Stripe Tax to calculate, collect, and report tax in Australia. In Australia, Stripe Tax supports calculation and [collection of GST](https://www.ato.gov.au/business/gst/). ## When to register for tax collection See [Thresholds](https://dashboard.stripe.com/tax/thresholds) to get insights about your potential tax registration obligations in Australia. Stripe also notifies you with email and Dashboard alerts when you need to register to collect tax. Learn more about how the [monitoring tool works](https://docs.stripe.com/tax/monitoring.md). See [Needs attention](https://dashboard.stripe.com/tax/locations?primary_tab=needs_attention) tab to get insights about your potential tax registration obligations in Australia. Stripe also notifies you with email and Dashboard alerts when you need to register to collect tax. Learn more about how the [monitoring tool works](https://docs.stripe.com/tax/monitoring.md). Remote sellers must register in Australia if their sales of services or low-value goods to Australian individuals exceed 75,000 AUD in the past 12 months or are expected to in the next 12 months. Sales to GST-registered Australian businesses that are subject to reverse charge don’t count toward the threshold. Non-profit organizations who sell remotely have a higher 150,000 AUD threshold but the threshold monitoring tool doesn’t track this. **Threshold**: 75,000 AUD (or 150,000 AUD for non-profit organizations) **Time frame**: Previous or current year. **Included transactions**: Any taxable transactions that reverse charge doesn’t apply to. Stripe supports domestic registration in Australia for both Australian businesses and remote sellers. If a remote business sells digital services or low-value goods into Australia exclusively through online marketplaces that are responsible for collecting tax on these sales, the seller isn’t required to register for GST in Australia. These sales don’t count toward the seller’s registration threshold. ## Register to collect tax Find more information on how to register for GST in Australia on the government website: - [Registration for businesses with an origin address in Australia](https://www.ato.gov.au/Business/GST/Registering-for-GST/) - [Registration for remote sellers](https://www.ato.gov.au/Business/International-tax-for-business/Non-resident-businesses-and-GST/) (businesses based outside of Australia selling into Australia) After you’ve registered to collect tax in Australia, go to [Registrations](https://dashboard.stripe.com/tax/registrations?location=au) to add your registrations to Stripe in the Dashboard. This turns on tax calculation and collection in Stripe for your transactions in Australia. After you’ve registered to collect tax in Australia, go to [Locations](https://dashboard.stripe.com/tax/locations?location=au) to add your registrations to Stripe in the Dashboard. This turns on tax calculation and collection in Stripe for your transactions in Australia. Learn more about [how to add your registration](https://docs.stripe.com/tax/registering.md#track-your-registrations-in-the-tax-dashboard) in the Dashboard. ## How we calculate taxes When both your business and your customer are in Australia, Stripe calculates Australian GST unless the sale is exempt or zero-rated. If you’re a remote seller and sell services to Australian customers, GST is typically collected on sales to individuals. No tax is charged on sales to business customers who provide their Australian Business Register (ABN) number. When goods are shipped into Australia from abroad, Stripe treats the sale as an export and doesn’t calculate tax, unless you choose to calculate tax on cross-border sales of goods into Australia through the [tax registration settings](https://docs.stripe.com/tax/registering.md#track-your-registrations-in-the-tax-dashboard). Generally, businesses need to collect tax on these sales if they act as the importer for customs purposes. If goods are imported in the customer’s name, the sale is considered to occur outside Australia, and no Australian VAT is due. Stripe doesn’t calculate GST on sales of imported low-value goods (valued 1,000 AUD or less) to Australian individuals unless you select the option to calculate tax on cross-border sales of goods into Australia. If you provide services related to admission to events and other venues, Stripe Tax considers them taxable in the country where the venue or event is located. Cross-border sales of goods into Australia might also be subject to import taxes and customs duties in Australia, which Stripe doesn’t calculate. ## Report and file your taxes Stripe provides reports of your completed tax transactions. Go to [Registrations](https://dashboard.stripe.com/tax/registrations) to access these reports. Learn more about [the different types of reports](https://docs.stripe.com/tax/reports.md). Stripe provides reports of your completed tax transactions. Go to [Locations](https://dashboard.stripe.com/tax/locations) to access these reports. Learn more about [the different types of reports](https://docs.stripe.com/tax/reports.md). You’re responsible for filing and remitting your taxes to Australia. Stripe doesn’t file taxes on your behalf. However, we do have trusted partners who can help manage your filing and remittance. ## Marketplace tax liability Australia defines electronic distribution platform (EDP) operators as marketplace operators that might have tax collection obligations. To qualify as an EDP, a marketplace operator must set terms or conditions for the sale, process or enable customer payments, or handle ordering or delivery of the product. Businesses that only provides payment processing or maintain the technical infrastructure behind an online marketplace don’t qualify as EDPs. EDP operators must collect GST on: - Sales of imported low-value goods by remote sellers to private individuals in Australia. - Sales of digital services by remote sellers to private individuals in Australia. --- # Source: https://docs.stripe.com/radar/reviews/auth-and-capture.md # Review uncaptured payments Learn how to use reviews if your Stripe integration uses auth and capture. By default, you [create payments](https://docs.stripe.com/payments/accept-a-payment.md) in one step. You don’t need to do anything else to send funds to your bank account. Stripe also supports two-step payments, often called [auth and capture](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md). If your integration uses this method, approving a review and capturing a payment are separate actions. Your capture window for approved payments varies by [card brand](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md#authorization-validity-windows), potential [extended holds](https://docs.stripe.com/payments/extended-authorization.md), and [payment method type](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md#auth-capture-limitations). ## Review uncaptured payments in the Dashboard When we place an uncaptured payment in review, the Stripe Dashboard shows a **Capture** button alongside buttons to approve or cancel the review. Uncaptured payments show a **Cancel** button instead of a **Refund** button because canceling an uncaptured payment releases the authorization without creating a [Refund object](https://docs.stripe.com/api/refunds.md). > Approving the review doesn’t automatically capture the charge. You still need to click **Capture**. ![](https://b.stripecdn.com/docs-statics-srv/assets/uncaptured-payment.b9aab5781bebea8e1cc8f349dc2092bf.png) ## Use the API to automatically capture approved payments Through the API, you can set up your integration to: - Immediately capture payments *not* placed in `review`. - Leave payments placed in `review` uncaptured. - When the review is approved, capture the payment. ### Immediately capture payments not placed in review Set the `capture_method` in your API request to create an uncaptured payment. After a successful request, check the [review](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-review) attribute on the PaymentIntent. If it’s empty, capture the charge. #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' # Get the credit card details submitted by the form # Create a PaymentIntent with manual capture payment_intent = Stripe::PaymentIntent.create({ amount: 1000, currency: 'usd', payment_method: '{{PAYMENT_METHOD_ID}}', description: 'Example charge', confirm: true, capture_method: 'manual', }) # Check if the payment is in review. If not, capture it. if !payment_intent.review payment_intent.capture end ``` #### Python ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' # Get the credit card details submitted by the form # Create a PaymentIntent with manual capture payment_intent = stripe.PaymentIntent.create( amount=2000, currency='usd', description='Example charge', confirm=True, capture_method='manual', ) # Check if the payment is in review. If not, capture it. if not payment_intent.review: payment_intent.capture ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('<>'); // Get the credit card details submitted by the form // Create a PaymentIntent with manual capture $payment_intent = \Stripe\PaymentIntent::create([ 'amount' => 1000, 'currency' => 'usd', 'payment_method' => '{{PAYMENT_METHOD_ID}}', 'description' => 'Example charge', 'confirm' => true, 'capture_method' => 'manual', ]); // Check if the payment is in review. If not, capture it. if(!$payment_intent->review) { $payment_intent->capture(); } ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; // Get the credit card details submitted by the form // Create a PaymentIntent with manual capture PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1000L) .setCurrency("usd") .setPaymentMethod("{{PAYMENT_METHOD_ID}}") .setDescription("Example charge") .setConfirm(true) .setCaptureMethod(PaymentIntentCreateParams.CaptureMethod.MANUAL) .build(); PaymentIntent paymentIntent = PaymentIntent.create(params); // Check if the payment is in review. If not, capture it. if(!paymentIntent.getReview()) { paymentIntent.capture(); } ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); // Get the credit card details submitted by the form // Create a PaymentIntent with manual capture var paymentIntent = await stripe.paymentIntents.create({ amount: 1000, currency: 'usd', payment_method: '{{PAYMENT_METHOD_ID}}', description: 'Example charge', confirm: true, capture_method: 'manual', }); // Check if the payment is in review. If not, capture it. if(!payment_intent.review) { var paymentIntentCaptured = await stripe.paymentIntents.capture(payment_intent.id); } ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" // Get the credit card details submitted by the form // Create a PaymentIntent with manual capture params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1000), Currency: stripe.String(string(stripe.CurrencyUSD)), PaymentMethod: stripe.String("{{PAYMENT_METHOD_ID}}"), Description: stripe.String("Example charge"), Confirm: stripe.Bool(true), CaptureMethod: stripe.String(string(stripe.PaymentIntentCaptureMethodManual)), } pi, _ := paymentintent.New(params) // Check if the payment is in review. If not, capture it. if pi.Review == nil { paymentintent.Capture(pi.ID, nil) } ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; // Get the credit card details submitted by the form // Create a PaymentIntent with manual capture var options = new PaymentIntentCreateOptions { Amount = 1000, Currency = "usd", Description = "Example charge", Confirm = true, CaptureMethod = "manual", }; var service = new PaymentIntentService(); var paymentIntent = service.Create(options); // Check if the payment is in review. If not, capture it. if(paymentIntent.Review == null) { service.Capture(paymentIntent.Id, null); } ``` ### Capture a payment after a review is approved In the previous step, you left payments in `review` and uncaptured. Use *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) to automatically capture these payments after approval. Configure your webhooks to listen for the `review.closed` event. The event includes the [Review object](https://docs.stripe.com/api.md#review_object), and its `reason` attribute indicates whether the review was approved or closed for another reason (for example, the payment was refunded). ```json // Review object included in review.closed event webhook. { "id": "prv_08voh1589O8KAxCGPcIQpmkz", "object": "review", "payment_intent": "pi_1D0CsEITpIrAk4QYdrWDnbRS", "created": 1474379631, "livemode": false, "open": false, "reason": "approved" } ``` If `reason` is `approved`, capture the charge. ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' post "/my/webhook/url" do event_json = JSON.parse(request.body.read) event = Stripe::Event.retrieve(event_json["id"]) if event.type == 'review.closed' review = event.object if review.reason == 'approved' pi = Stripe::PaymentIntent.retrieve(review.payment_intent) pi.capture end end status 200 end ``` --- # Source: https://docs.stripe.com/connect/authentication.md # Making API calls for connected accounts Learn how to add the right information to your API calls so you can make calls for your connected accounts. You can make API calls for your connected accounts: - Server-side with the [Stripe-Account header](https://docs.stripe.com/connect/authentication.md#stripe-account-header) and the connected account ID, per request - Client-side by passing the connected account ID as an argument to the client library To help with performance and reliability, Stripe has established [rate limits and allocations](https://docs.stripe.com/rate-limits.md) for API endpoints. ## Add the Stripe-Account header server-side To make server-side API calls for connected accounts, use the `Stripe-Account` header with the account identifier, which begins with the prefix `acct_`. Here are four examples using your platform’s [API secret key](https://docs.stripe.com/keys.md) and the connected account’s [Account](https://docs.stripe.com/api/accounts.md) identifier: #### Create PaymentIntent ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d amount=1000 \ -d currency=usd ``` ```cli stripe payment_intents create \ --stripe-account {{CONNECTEDACCOUNT_ID}} \ --amount=1000 \ --currency=usd ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create( { amount: 1000, currency: 'usd', }, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create( {"amount": 1000, "currency": "usd"}, {"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create( [ 'amount' => 1000, 'currency' => 'usd', ], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder().setAmount(1000L).setCurrency("usd").build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params, requestOptions); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create( { amount: 1000, currency: 'usd', }, { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(1000), Currency: stripe.String(stripe.CurrencyUSD), } params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 1000, Currency = "usd" }; var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options, requestOptions); ``` #### Retrieve Balance ```curl curl https://api.stripe.com/v1/balance \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" ``` ```cli stripe balance retrieve \ --stripe-account {{CONNECTEDACCOUNT_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") balance = client.v1.balance.retrieve( {}, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. balance = client.v1.balance.retrieve( options={"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $balance = $stripe->balance->retrieve( [], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); BalanceRetrieveParams params = BalanceRetrieveParams.builder().build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Balance balance = client.v1().balance().retrieve(params, requestOptions); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const balance = await stripe.balance.retrieve({ stripeAccount: '{{CONNECTEDACCOUNT_ID}}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.BalanceRetrieveParams{} params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result, err := sc.V1Balance.Retrieve(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new BalanceGetOptions(); var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Balance; Balance balance = service.Get(options, requestOptions); ``` #### List Products ```curl curl -G https://api.stripe.com/v1/products \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d limit=5 ``` ```cli stripe products list \ --stripe-account {{CONNECTEDACCOUNT_ID}} \ --limit=5 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") products = client.v1.products.list( {limit: 5}, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. products = client.v1.products.list( {"limit": 5}, {"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $products = $stripe->products->all( ['limit' => 5], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); ProductListParams params = ProductListParams.builder().setLimit(5L).build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. StripeCollection stripeCollection = client.v1().products().list(params, requestOptions); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const products = await stripe.products.list( { limit: 5, }, { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.ProductListParams{} params.Limit = stripe.Int64(5) params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result := sc.V1Products.List(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new ProductListOptions { Limit = 5 }; var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Products; StripeList products = service.List(options, requestOptions); ``` #### Delete Customer ```curl curl -X DELETE https://api.stripe.com/v1/customers/{{CUSTOMER_ID}} \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" ``` ```cli stripe customers delete {{CUSTOMER_ID}} \ --stripe-account {{CONNECTEDACCOUNT_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") deleted = client.v1.customers.delete( '{{CUSTOMER_ID}}', {}, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. deleted = client.v1.customers.delete( "{{CUSTOMER_ID}}", options={"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $deleted = $stripe->customers->delete( '{{CUSTOMER_ID}}', [], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Customer customer = client.v1().customers().delete("{{CUSTOMER_ID}}", requestOptions); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const deleted = await stripe.customers.del( '{{CUSTOMER_ID}}', { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerDeleteParams{} params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result, err := sc.V1Customers.Delete(context.TODO(), "{{CUSTOMER_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Customers; Customer deleted = service.Delete("{{CUSTOMER_ID}}", null, requestOptions); ``` The `Stripe-Account` header approach is implied in any API request that includes the Stripe account ID in the URL. Here’s an example that shows how to [Retrieve an account](https://docs.stripe.com/api/accounts/retrieve.md) with your user’s [Account](https://docs.stripe.com/api/accounts.md) identifier in the URL. ```curl curl https://api.stripe.com/v1/accounts/{{CONNECTEDACCOUNT_ID}} \ -u "<>:" ``` ```cli stripe accounts retrieve {{CONNECTEDACCOUNT_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.accounts.retrieve('{{CONNECTEDACCOUNT_ID}}') ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.accounts.retrieve("{{CONNECTEDACCOUNT_ID}}") ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->accounts->retrieve('{{CONNECTEDACCOUNT_ID}}', []); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountRetrieveParams params = AccountRetrieveParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().accounts().retrieve("{{CONNECTEDACCOUNT_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.accounts.retrieve('{{CONNECTEDACCOUNT_ID}}'); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.AccountRetrieveParams{} result, err := sc.V1Accounts.GetByID( context.TODO(), "{{CONNECTEDACCOUNT_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.Accounts; Account account = service.Get("{{CONNECTEDACCOUNT_ID}}"); ``` All of Stripe’s server-side libraries support this approach on a per-request basis: ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ --data-urlencode email="person@example.com" ``` ```cli stripe customers create \ --stripe-account {{CONNECTEDACCOUNT_ID}} \ --email="person@example.com" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer = client.v1.customers.create( {email: 'person@example.com'}, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer = client.v1.customers.create( {"email": "person@example.com"}, {"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $customer = $stripe->customers->create( ['email' => 'person@example.com'], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CustomerCreateParams params = CustomerCreateParams.builder().setEmail("person@example.com").build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Customer customer = client.v1().customers().create(params, requestOptions); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const customer = await stripe.customers.create( { email: 'person@example.com', }, { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerCreateParams{Email: stripe.String("person@example.com")} params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result, err := sc.V1Customers.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CustomerCreateOptions { Email = "person@example.com" }; var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Customers; Customer customer = service.Create(options, requestOptions); ``` ## Add the connected account ID to a client-side application Client-side libraries set the connected account ID as an argument to the client application: #### HTML + JS The JavaScript code for passing the connected account ID client-side is the same for plain JS and for ESNext. ```javascript var stripe = Stripe('<>', { stripeAccount: '{{CONNECTED_ACCOUNT_ID}}', }); ``` #### React ```javascript import {loadStripe} from '@stripe/stripe-js'; // Make sure to call `loadStripe` outside of a component's render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe('<>', { stripeAccount: '{{CONNECTED_ACCOUNT_ID}}', }); ``` #### iOS #### Swift ```swift import UIKit import StripePayments @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { StripeAPI.defaultPublishableKey = "<>" STPAPIClient.shared.stripeAccount = "{{CONNECTED_ACCOUNT_ID}}" return true } } ``` #### Objective C ```objc #import "AppDelegate.h" @import StripeCore; @import StripePayments; @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [StripeAPI setDefaultPublishableKey:@"<>"]; [[STPAPIClient sharedClient] setStripeAccount:@"{{CONNECTED_ACCOUNT_ID}}"]; return YES; } @end ``` #### Android #### Kotlin ```kotlin import com.stripe.android.PaymentConfiguration class MyActivity: Activity() { private lateinit var stripe: Stripe override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) stripe = Stripe( this, PaymentConfiguration.getInstance(this).publishableKey, "{{CONNECTED_ACCOUNT_ID}}" ) } } ``` #### Java ```java import com.stripe.android.PaymentConfiguration; public class MyActivity extends Activity { private Stripe stripe; @Override public void onCreate(@Nullable Bundle savedInstancedState) { super.onCreate(savedInstancedState); stripe = new Stripe( this, PaymentConfiguration.getInstance(this).getPublishableKey(), "{{CONNECTED_ACCOUNT_ID}}" ); } } ``` #### React Native ```javascript import {StripeProvider} from '@stripe/stripe-react-native'; function App() { return ( // Your app code here ); } ``` ## Use Connect embedded components Instead of directly integrating with Stripe’s APIs, you can use [Connect embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md) to provide Stripe functionality to your connected accounts in your platform’s UI. These components require less code to implement and handle all API calls internally. For example, to show payments data to your connected accounts, embed the [Payments component](https://docs.stripe.com/connect/supported-embedded-components/payments.md) in your platform’s UI. This eliminates the need to make separate calls to the [Charges](https://docs.stripe.com/api/charges.md), [Payment Intents](https://docs.stripe.com/api/payment_intents.md), [Refunds](https://docs.stripe.com/api/refunds.md), and [Disputes](https://docs.stripe.com/api/disputes.md) API. Note: The following is a preview/demo component that behaves differently than live mode usage with real connected accounts. The actual component has more functionality than what might appear in this demo component. For example, for connected accounts without Stripe dashboard access (custom accounts), no user authentication is required in production. For a complete list of the available embedded components, see [Supported components](https://docs.stripe.com/connect/supported-embedded-components.md). ## See also - [Creating charges](https://docs.stripe.com/connect/charges.md) - [Using subscriptions](https://docs.stripe.com/connect/subscriptions.md) - [Getting started with Connect embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md) --- # Source: https://docs.stripe.com/invoicing/integration/automatic-advancement-collection.md # Automatic invoice advancement Learn how Stripe can automatically advance invoice states and help collect payment. All invoices start as a `draft` and must be transitioned to `open` to accept a payment. If the invoice becomes overdue, or payment on the invoice fails, Stripe can automatically send reminders or retry the payment for you. You can choose to let Stripe manage these state transitions and these collection attempts automatically or choose to manage them yourself. Learn more about the [invoice lifecycle](https://docs.stripe.com/invoicing/overview.md#invoice-lifecycle). For invoices created using the API, set the [auto_advance](https://docs.stripe.com/api/invoices/update.md#update_invoice-auto_advance) property on the invoice to `true`. You might also want to configure a webhook endpoint to receive associated events. When you set `auto_advance` to `false`, you’re responsible for transitioning the invoice between states. Learn more about [webhook endpoints and finalizing invoices](https://docs.stripe.com/billing/subscriptions/webhooks.md#understand). ## Update automatic invoice advancement An invoice must be in a `draft` or `open` state to update automatic advancement. Invoices that are `paid`, `void`, or `uncollectible` always have automatic advancement turned off. #### Dashboard Automatic invoice advancement is on by default for any invoice created in the Dashboard. You can manually turn on or off automatic advancement for any invoice. On the invoice details page, click the overflow menu (⋯) and select **Turn on/off automatic reminders**. Invoices set to charge a payment method on file automatically display **Turn on/off automatic collection**, which changes the `auto_advance` property on the invoice. See the feature table below for a comparison of turning this on or off. #### API You can toggle the `auto_advance` property on `draft` and `open` invoices. ```curl curl https://api.stripe.com/v1/invoices/id \ -u "<>:" \ -d auto_advance=false ``` ```cli stripe invoices update id \ --auto-advance=false ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") invoice = client.v1.invoices.update('id', {auto_advance: false}) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. invoice = client.v1.invoices.update( "id", {"auto_advance": False}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $invoice = $stripe->invoices->update('id', ['auto_advance' => false]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); InvoiceUpdateParams params = InvoiceUpdateParams.builder().setAutoAdvance(false).build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Invoice invoice = client.v1().invoices().update("id", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const invoice = await stripe.invoices.update( 'id', { auto_advance: false, } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.InvoiceUpdateParams{AutoAdvance: stripe.Bool(false)} result, err := sc.V1Invoices.Update(context.TODO(), "id", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new InvoiceUpdateOptions { AutoAdvance = false }; var client = new StripeClient("<>"); var service = client.V1.Invoices; Invoice invoice = service.Update("id", options); ``` ## Pause automatic advancement In some cases, you might want to stop Stripe from automatically advancing your invoices toward collection. For example, if you want to: - Use your own business logic to manage the lifecycle of an invoice. - Decide if and when to send invoice emails on a per-invoice basis. In both of these cases, use the `auto_advance` property to disable the automatic advancement and collection behavior. ## Automatic advancement feature comparison When you turn off automatic advancement in the Dashboard or set `auto_advance` to `false`, Stripe disables most of the automatic collection features for Invoicing. The following table outlines some key changes in the behavior of automatic collection, depending on whether `auto_advance` is set to `true` or `false`: | Feature | True | False | | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | Emailing invoices | ✓ Yes ⚙ Configurable in settings | ✗ Not enabled | | Retries (email and charge) | ✓ Yes ⚙ Configurable in settings | ✗ Not enabled | | Invoice reminder emails | ✓ Yes ⚙ Configurable in settings | ✗ Not enabled | | 3D Secure reminder emails | ✓ Yes ⚙ Configurable in settings | ✗ Not enabled | | Email receipts | ✓ Yes ⚙ Configurable in settings | ✓ Yes ⚙ Configurable in settings | | Attempting payments for auto-charge invoices | ✓ Yes | ✗ Not enabled | | Finalize draft subscription invoices to open | ✓ Yes ⚙ Configurable in settings (after [approximately one hour](https://docs.stripe.com/billing/subscriptions/overview.md#subscription-lifecycle)) | ✗ Not enabled | | [Stripe Automation](https://docs.stripe.com/billing/automations.md) | ✓ Yes | ✗ Not enabled | #### Legend - ✓ Yes = Can be enabled depending on your settings. - ⚙ = Configurable in your settings. - ✗ Not enabled = Not enabled. The invoice isn’t automatically transitioned. --- # Source: https://docs.stripe.com/invoicing/automatic-charging.md # Automatic charging Have Stripe automatically charge a customer's stored payment method. Stripe can automatically attempt to pay an *invoice* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) if the customer has a payment method on file. You can automatically charge a customer when you’re [creating an invoice](https://dashboard.stripe.com/invoices/create) or through the [API](https://docs.stripe.com/api/invoices.md). When you automatically charge a payment method on file, Stripe doesn’t notify the customer about the invoice. However, if you want to send an email receipt, make sure that you enable the **Successful payments** option in your [Email settings](https://dashboard.stripe.com/settings/emails) and that you’ve added your customer’s email address. ## Add a payment method #### Dashboard To add a payment method, go to the [Customers page](https://dashboard.stripe.com/customers) and select a customer. Select **Add** in the **Payment methods** section to add a card or an ACH debit bank account. You can also add a payment method during invoice creation. If your customer uses multiple payment methods, click the overflow menu (⋯) next to the card to make it the default. #### API With the API, set the invoice’s [collection_method](https://docs.stripe.com/api/invoices/create.md#create_invoice-collection_method) property to `charge_automatically` to automatically charge the payment method on file. ## See also - [Use the Dashboard](https://docs.stripe.com/invoicing/dashboard.md) - [Send email reminders](https://docs.stripe.com/invoicing/send-email.md) --- # Source: https://docs.stripe.com/issuing/integration-guides/b2b-payments.md # B2B payments integration guide Build a B2B payments integration with Issuing. Check out our introductory guide to using [embedded finance for SaaS Platforms](https://stripe.com/guides/introduction-to-embedded-finance). Build a US B2B payments integration by using Stripe [Issuing](https://docs.stripe.com/issuing/how-issuing-works.md) to create cards for your business, employees, or contractors to make purchases on your behalf. By the end of this guide, you’ll know how to: - Fund your Issuing Balance - Create virtual cards for your own business - Use these cards to spend funds from your Issuing Balance ## Before you begin 1. Sign up for a [Stripe account](https://dashboard.stripe.com/register). 1. [Activate Issuing](https://dashboard.stripe.com/issuing/activate) in a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment from the Dashboard. ## Add funds To spend money using cards, add funds to the Issuing balance on your account. This balance represents funds reserved for Issuing and is safely separated from your earnings, payouts, and funds from other Stripe products. You can add funds from your [Dashboard](https://dashboard.stripe.com/balance/overview#issuing-summary). ## Create cardholders and cards ### Create a cardholder The [Cardholder](https://docs.stripe.com/api/.md#issuing_cardholder_object) is the company or business entity that’s authorized to use card funding by the Issuing balance. The `Cardholder` object includes relevant details, such as a [name](https://docs.stripe.com/api/issuing/cardholders/object.md#issuing_cardholder_object-name) to display on cards and a [billing](https://docs.stripe.com/api/issuing/cardholders/object.md#issuing_cardholder_object-billing) address, which is usually the business address. The following API call creates a new `Cardholder`: ```curl curl https://api.stripe.com/v1/issuing/cardholders \ -u "<>:" \ -d name="Company Card" \ --data-urlencode email="company@example.com" \ --data-urlencode phone_number="+18008675309" \ -d status=active \ -d type=company \ -d "billing[address][line1]"="123 Main Street" \ -d "billing[address][city]"="San Francisco" \ -d "billing[address][state]"=CA \ -d "billing[address][postal_code]"=94111 \ -d "billing[address][country]"=US ``` ```cli stripe issuing cardholders create \ --name="Company Card" \ --email="company@example.com" \ --phone-number="+18008675309" \ --status=active \ --type=company \ -d "billing[address][line1]"="123 Main Street" \ -d "billing[address][city]"="San Francisco" \ -d "billing[address][state]"=CA \ -d "billing[address][postal_code]"=94111 \ -d "billing[address][country]"=US ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") cardholder = client.v1.issuing.cardholders.create({ name: 'Company Card', email: 'company@example.com', phone_number: '+18008675309', status: 'active', type: 'company', billing: { address: { line1: '123 Main Street', city: 'San Francisco', state: 'CA', postal_code: '94111', country: 'US', }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. cardholder = client.v1.issuing.cardholders.create({ "name": "Company Card", "email": "company@example.com", "phone_number": "+18008675309", "status": "active", "type": "company", "billing": { "address": { "line1": "123 Main Street", "city": "San Francisco", "state": "CA", "postal_code": "94111", "country": "US", }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $cardholder = $stripe->issuing->cardholders->create([ 'name' => 'Company Card', 'email' => 'company@example.com', 'phone_number' => '+18008675309', 'status' => 'active', 'type' => 'company', 'billing' => [ 'address' => [ 'line1' => '123 Main Street', 'city' => 'San Francisco', 'state' => 'CA', 'postal_code' => '94111', 'country' => 'US', ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CardholderCreateParams params = CardholderCreateParams.builder() .setName("Company Card") .setEmail("company@example.com") .setPhoneNumber("+18008675309") .setStatus(CardholderCreateParams.Status.ACTIVE) .setType(CardholderCreateParams.Type.COMPANY) .setBilling( CardholderCreateParams.Billing.builder() .setAddress( CardholderCreateParams.Billing.Address.builder() .setLine1("123 Main Street") .setCity("San Francisco") .setState("CA") .setPostalCode("94111") .setCountry("US") .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Cardholder cardholder = client.v1().issuing().cardholders().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const cardholder = await stripe.issuing.cardholders.create({ name: 'Company Card', email: 'company@example.com', phone_number: '+18008675309', status: 'active', type: 'company', billing: { address: { line1: '123 Main Street', city: 'San Francisco', state: 'CA', postal_code: '94111', country: 'US', }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.IssuingCardholderCreateParams{ Name: stripe.String("Company Card"), Email: stripe.String("company@example.com"), PhoneNumber: stripe.String("+18008675309"), Status: stripe.String(stripe.IssuingCardholderStatusActive), Type: stripe.String(stripe.IssuingCardholderTypeCompany), Billing: &stripe.IssuingCardholderCreateBillingParams{ Address: &stripe.AddressParams{ Line1: stripe.String("123 Main Street"), City: stripe.String("San Francisco"), State: stripe.String("CA"), PostalCode: stripe.String("94111"), Country: stripe.String("US"), }, }, } result, err := sc.V1IssuingCardholders.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Issuing.CardholderCreateOptions { Name = "Company Card", Email = "company@example.com", PhoneNumber = "+18008675309", Status = "active", Type = "company", Billing = new Stripe.Issuing.CardholderBillingOptions { Address = new AddressOptions { Line1 = "123 Main Street", City = "San Francisco", State = "CA", PostalCode = "94111", Country = "US", }, }, }; var client = new StripeClient("<>"); var service = client.V1.Issuing.Cardholders; Stripe.Issuing.Cardholder cardholder = service.Create(options); ``` Stripe returns a `Cardholder` object that contains the information you provided and sends the `issuing_cardholder.created` webhook event. ### Create a card Create a card and attach it to the `Cardholder` that you want to make the authorized user of the card. In the following examples, we show you how to create a [virtual card](https://docs.stripe.com/issuing/cards/virtual.md). You can, however, create [physical cards](https://docs.stripe.com/issuing/cards/physical.md) and ship them to cardholders in live mode. ```curl curl https://api.stripe.com/v1/issuing/cards \ -u "<>:" \ -d currency=usd \ -d type=virtual \ -d cardholder="{{ISSUINGCARDHOLDER_ID}}" ``` ```cli stripe issuing cards create \ --currency=usd \ --type=virtual \ --cardholder="{{ISSUINGCARDHOLDER_ID}}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") card = client.v1.issuing.cards.create({ currency: 'usd', type: 'virtual', cardholder: '{{ISSUINGCARDHOLDER_ID}}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. card = client.v1.issuing.cards.create({ "currency": "usd", "type": "virtual", "cardholder": "{{ISSUINGCARDHOLDER_ID}}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $card = $stripe->issuing->cards->create([ 'currency' => 'usd', 'type' => 'virtual', 'cardholder' => '{{ISSUINGCARDHOLDER_ID}}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CardCreateParams params = CardCreateParams.builder() .setCurrency("usd") .setType(CardCreateParams.Type.VIRTUAL) .setCardholder("{{ISSUINGCARDHOLDER_ID}}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Card card = client.v1().issuing().cards().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const card = await stripe.issuing.cards.create({ currency: 'usd', type: 'virtual', cardholder: '{{ISSUINGCARDHOLDER_ID}}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.IssuingCardCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), Type: stripe.String(stripe.IssuingCardTypeVirtual), Cardholder: stripe.String("{{ISSUINGCARDHOLDER_ID}}"), } result, err := sc.V1IssuingCards.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Issuing.CardCreateOptions { Currency = "usd", Type = "virtual", Cardholder = "{{ISSUINGCARDHOLDER_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Issuing.Cards; Stripe.Issuing.Card card = service.Create(options); ``` Stripe returns a `Card` object on creation, and sends the `issuing_card.created` webhook event: ```json { "id": "ic_1NvPjF2SSJdH5vn2OVbE7r0b", "object": "issuing.card", "brand": "Visa", ... "status": "inactive", "type": "virtual" } ``` You need to activate the card before a user can use it. While you can activate virtual cards in the same API call you used to create it, you must activate physical cards separately. When ready, activate the card by marking the `status` as `active`: ```curl curl https://api.stripe.com/v1/issuing/cards/ic_1NvPjF2SSJdH5vn2OVbE7r0b \ -u "<>:" \ -d status=active ``` ```cli stripe issuing cards update ic_1NvPjF2SSJdH5vn2OVbE7r0b \ --status=active ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") card = client.v1.issuing.cards.update('ic_1NvPjF2SSJdH5vn2OVbE7r0b', {status: 'active'}) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. card = client.v1.issuing.cards.update( "ic_1NvPjF2SSJdH5vn2OVbE7r0b", {"status": "active"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $card = $stripe->issuing->cards->update( 'ic_1NvPjF2SSJdH5vn2OVbE7r0b', ['status' => 'active'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CardUpdateParams params = CardUpdateParams.builder().setStatus(CardUpdateParams.Status.ACTIVE).build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Card card = client.v1().issuing().cards().update("ic_1NvPjF2SSJdH5vn2OVbE7r0b", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const card = await stripe.issuing.cards.update( 'ic_1NvPjF2SSJdH5vn2OVbE7r0b', { status: 'active', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.IssuingCardUpdateParams{ Status: stripe.String(stripe.IssuingCardStatusActive), } result, err := sc.V1IssuingCards.Update( context.TODO(), "ic_1NvPjF2SSJdH5vn2OVbE7r0b", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Issuing.CardUpdateOptions { Status = "active" }; var client = new StripeClient("<>"); var service = client.V1.Issuing.Cards; Stripe.Issuing.Card card = service.Update("ic_1NvPjF2SSJdH5vn2OVbE7r0b", options); ``` At this point, there’s now an active card attached to a cardholder. See the [Issuing page](https://dashboard.stripe.com/issuing/overview) to view the card and cardholder information. ```json { "id": "ic_1NvPjF2SSJdH5vn2OVbE7r0b", "object": "issuing.card", "brand": "Visa", ... "status": "active", "type": "virtual", } ``` To learn more, see: - [Virtual cards](https://docs.stripe.com/issuing/cards/virtual.md) - [Physical cards](https://docs.stripe.com/issuing/cards/physical.md) - [Use the Dashboard for Issuing with Connect](https://docs.stripe.com/issuing/connect.md#using-dashboard-issuing) - [Create cards with the API](https://docs.stripe.com/api/issuing/cards.md) ## Use the card ### Create an authorization To observe the impact of card activity on the associated balance, generate a test authorization. You can do this in the **Issuing page** of the Dashboard, or with the following call to the [Authorization API](https://docs.stripe.com/api/issuing/authorizations.md): ```curl curl https://api.stripe.com/v1/test_helpers/issuing/authorizations \ -u "<>:" \ -d card="{{ISSUINGCARD_ID}}" \ -d amount=1000 \ -d authorization_method=chip \ -d "merchant_data[category]"=taxicabs_limousines \ -d "merchant_data[city]"="San Francisco" \ -d "merchant_data[country]"=US \ -d "merchant_data[name]"="Rocket Rides" \ -d "merchant_data[network_id]"=1234567890 \ -d "merchant_data[postal_code]"=94107 \ -d "merchant_data[state]"=CA ``` ```cli stripe test_helpers issuing authorizations create \ --card="{{ISSUINGCARD_ID}}" \ --amount=1000 \ --authorization-method=chip \ -d "merchant_data[category]"=taxicabs_limousines \ -d "merchant_data[city]"="San Francisco" \ -d "merchant_data[country]"=US \ -d "merchant_data[name]"="Rocket Rides" \ -d "merchant_data[network_id]"=1234567890 \ -d "merchant_data[postal_code]"=94107 \ -d "merchant_data[state]"=CA ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") authorization = client.v1.test_helpers.issuing.authorizations.create({ card: '{{ISSUINGCARD_ID}}', amount: 1000, authorization_method: 'chip', merchant_data: { category: 'taxicabs_limousines', city: 'San Francisco', country: 'US', name: 'Rocket Rides', network_id: '1234567890', postal_code: '94107', state: 'CA', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. authorization = client.v1.test_helpers.issuing.authorizations.create({ "card": "{{ISSUINGCARD_ID}}", "amount": 1000, "authorization_method": "chip", "merchant_data": { "category": "taxicabs_limousines", "city": "San Francisco", "country": "US", "name": "Rocket Rides", "network_id": "1234567890", "postal_code": "94107", "state": "CA", }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $authorization = $stripe->testHelpers->issuing->authorizations->create([ 'card' => '{{ISSUINGCARD_ID}}', 'amount' => 1000, 'authorization_method' => 'chip', 'merchant_data' => [ 'category' => 'taxicabs_limousines', 'city' => 'San Francisco', 'country' => 'US', 'name' => 'Rocket Rides', 'network_id' => '1234567890', 'postal_code' => '94107', 'state' => 'CA', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AuthorizationCreateParams params = AuthorizationCreateParams.builder() .setCard("{{ISSUINGCARD_ID}}") .setAmount(1000L) .setAuthorizationMethod(AuthorizationCreateParams.AuthorizationMethod.CHIP) .setMerchantData( AuthorizationCreateParams.MerchantData.builder() .setCategory(AuthorizationCreateParams.MerchantData.Category.TAXICABS_LIMOUSINES) .setCity("San Francisco") .setCountry("US") .setName("Rocket Rides") .setNetworkId("1234567890") .setPostalCode("94107") .setState("CA") .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Authorization authorization = client.v1().testHelpers().issuing().authorizations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const authorization = await stripe.testHelpers.issuing.authorizations.create({ card: '{{ISSUINGCARD_ID}}', amount: 1000, authorization_method: 'chip', merchant_data: { category: 'taxicabs_limousines', city: 'San Francisco', country: 'US', name: 'Rocket Rides', network_id: '1234567890', postal_code: '94107', state: 'CA', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TestHelpersIssuingAuthorizationCreateParams{ Card: stripe.String("{{ISSUINGCARD_ID}}"), Amount: stripe.Int64(1000), AuthorizationMethod: stripe.String(stripe.IssuingAuthorizationAuthorizationMethodChip), MerchantData: &stripe.TestHelpersIssuingAuthorizationCreateMerchantDataParams{ Category: stripe.String("taxicabs_limousines"), City: stripe.String("San Francisco"), Country: stripe.String("US"), Name: stripe.String("Rocket Rides"), NetworkID: stripe.String("1234567890"), PostalCode: stripe.String("94107"), State: stripe.String("CA"), }, } result, err := sc.V1TestHelpersIssuingAuthorizations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.TestHelpers.Issuing.AuthorizationCreateOptions { Card = "{{ISSUINGCARD_ID}}", Amount = 1000, AuthorizationMethod = "chip", MerchantData = new Stripe.TestHelpers.Issuing.AuthorizationMerchantDataOptions { Category = "taxicabs_limousines", City = "San Francisco", Country = "US", Name = "Rocket Rides", NetworkId = "1234567890", PostalCode = "94107", State = "CA", }, }; var client = new StripeClient("<>"); var service = client.V1.TestHelpers.Issuing.Authorizations; Stripe.Issuing.Authorization authorization = service.Create(options); ``` After approval, Stripe creates an `Authorization` in a `pending` state while it waits for [capture](https://docs.stripe.com/issuing/purchases/transactions.md). Note the authorization `id` that you’ll use to capture the funds: ```json {"id": "iauth_1NvPyY2SSJdH5vn2xZQE8C7k", "object": "issuing.authorization", "amount": 1000, ... "status": "pending", "transactions": [], } ``` ### Capture the funds Capture the funds using the following code: ```curl curl -X POST https://api.stripe.com/v1/test_helpers/issuing/authorizations/{{ISSUINGAUTHORIZATION_ID}}/capture \ -u "<>:" ``` ```cli stripe test_helpers issuing authorizations capture {{ISSUINGAUTHORIZATION_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") authorization = client.v1.test_helpers.issuing.authorizations.capture('{{ISSUINGAUTHORIZATION_ID}}') ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. authorization = client.v1.test_helpers.issuing.authorizations.capture( "{{ISSUINGAUTHORIZATION_ID}}", ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $authorization = $stripe->testHelpers->issuing->authorizations->capture( '{{ISSUINGAUTHORIZATION_ID}}', [] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AuthorizationCaptureParams params = AuthorizationCaptureParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Authorization authorization = client.v1().testHelpers().issuing().authorizations().capture( "{{ISSUINGAUTHORIZATION_ID}}", params ); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const authorization = await stripe.testHelpers.issuing.authorizations.capture( '{{ISSUINGAUTHORIZATION_ID}}' ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TestHelpersIssuingAuthorizationCaptureParams{} result, err := sc.V1TestHelpersIssuingAuthorizations.Capture( context.TODO(), "{{ISSUINGAUTHORIZATION_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.TestHelpers.Issuing.Authorizations; Stripe.Issuing.Authorization authorization = service.Capture( "{{ISSUINGAUTHORIZATION_ID}}"); ``` After the authorization is captured, Stripe creates an Issuing [Transaction](https://docs.stripe.com/issuing/purchases/transactions.md), the `status` of the authorization is set to `closed`. ## See also - [Spending controls](https://docs.stripe.com/issuing/controls/spending-controls.md) - [Issuing authorizations](https://docs.stripe.com/issuing/purchases/authorizations.md) - [Issuing transactions](https://docs.stripe.com/issuing/purchases/transactions.md) - [Working with Stripe Issuing cards and Financial Accounts for platforms](https://docs.stripe.com/financial-accounts/connect/account-management/issuing-cards.md) - [Manage transaction fraud](https://docs.stripe.com/issuing/manage-fraud.md) --- # Source: https://docs.stripe.com/api/balance.md # Balance This is an object representing your Stripe balance. You can retrieve it to see the balance currently on your Stripe account. The top-level `available` and `pending` comprise your “payments balance.” Related guide: [Balances and settlement time](https://docs.stripe.com/docs/payments/balances.md), [Understanding Connect account balances](https://docs.stripe.com/docs/connect/account-balances.md) ## Endpoints ### Retrieve balance - [GET /v1/balance](https://docs.stripe.com/api/balance/balance_retrieve.md) --- # Source: https://docs.stripe.com/api/balance/balance_object.md # The Balance object ## Attributes - `object` (string) String representing the object’s type. Objects of the same type share the same value. - `available` (array of objects) Available funds that you can transfer or pay out automatically by Stripe or explicitly through the [Transfers API](https://docs.stripe.com/api/balance/balance_object.md#transfers) or [Payouts API](https://docs.stripe.com/api/balance/balance_object.md#payouts). You can find the available balance for each currency and payment type in the `source_types` property. - `available.amount` (integer) Balance amount. - `available.currency` (enum) 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). - `available.source_types` (object, nullable) Breakdown of balance by source types. Funds coming from certain source / payment method types must be shown separately. All payment methods that do not have this restriction will be combined with the `card` source type balance. - `available.source_types.bank_account` (integer, nullable) Amount coming from [legacy US ACH payments](https://docs.stripe.com/ach-deprecated.md). - `available.source_types.card` (integer, nullable) Amount coming from most payment methods, including cards as well as [non-legacy bank debits](https://docs.stripe.com/payments/bank-debits.md). - `available.source_types.fpx` (integer, nullable) Amount coming from [FPX](https://docs.stripe.com/payments/fpx.md), a Malaysian payment method. - `connect_reserved` (array of objects, nullable) Funds held due to negative balances on connected accounts where [account.controller.requirement_collection](https://docs.stripe.com/api/accounts/object.md#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. - `connect_reserved.amount` (integer) Balance amount. - `connect_reserved.currency` (enum) 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). - `connect_reserved.source_types` (object, nullable) Breakdown of balance by source types. Funds coming from certain source / payment method types must be shown separately. All payment methods that do not have this restriction will be combined with the `card` source type balance. - `connect_reserved.source_types.bank_account` (integer, nullable) Amount coming from [legacy US ACH payments](https://docs.stripe.com/ach-deprecated.md). - `connect_reserved.source_types.card` (integer, nullable) Amount coming from most payment methods, including cards as well as [non-legacy bank debits](https://docs.stripe.com/payments/bank-debits.md). - `connect_reserved.source_types.fpx` (integer, nullable) Amount coming from [FPX](https://docs.stripe.com/payments/fpx.md), a Malaysian payment method. - `instant_available` (array of objects, nullable) Funds that you can pay out using Instant Payouts. - `instant_available.amount` (integer) Balance amount. - `instant_available.currency` (enum) 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). - `instant_available.net_available` (array of objects, nullable) Breakdown of balance by destination. - `instant_available.net_available.amount` (integer) Net balance amount, subtracting fees from platform-set pricing. - `instant_available.net_available.destination` (string) ID of the external account for this net balance (not expandable). - `instant_available.net_available.source_types` (object, nullable) Breakdown of balance by source types. Funds coming from certain source / payment method types must be shown separately. All payment methods that do not have this restriction will be combined with the `card` source type balance. - `instant_available.net_available.source_types.bank_account` (integer, nullable) Amount coming from [legacy US ACH payments](https://docs.stripe.com/ach-deprecated.md). - `instant_available.net_available.source_types.card` (integer, nullable) Amount coming from most payment methods, including cards as well as [non-legacy bank debits](https://docs.stripe.com/payments/bank-debits.md). - `instant_available.net_available.source_types.fpx` (integer, nullable) Amount coming from [FPX](https://docs.stripe.com/payments/fpx.md), a Malaysian payment method. - `instant_available.source_types` (object, nullable) Breakdown of balance by source types. Funds coming from certain source / payment method types must be shown separately. All payment methods that do not have this restriction will be combined with the `card` source type balance. - `instant_available.source_types.bank_account` (integer, nullable) Amount coming from [legacy US ACH payments](https://docs.stripe.com/ach-deprecated.md). - `instant_available.source_types.card` (integer, nullable) Amount coming from most payment methods, including cards as well as [non-legacy bank debits](https://docs.stripe.com/payments/bank-debits.md). - `instant_available.source_types.fpx` (integer, nullable) Amount coming from [FPX](https://docs.stripe.com/payments/fpx.md), a Malaysian payment method. - `issuing` (object, nullable) Funds that you can spend on your [Issued Cards](https://docs.stripe.com/api/balance/balance_object.md#issuing/cards). - `issuing.available` (array of objects) Funds that are available for use. - `issuing.available.amount` (integer) Balance amount. - `issuing.available.currency` (enum) 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). - `issuing.available.source_types` (object, nullable) Breakdown of balance by source types. Funds coming from certain source / payment method types must be shown separately. All payment methods that do not have this restriction will be combined with the `card` source type balance. - `issuing.available.source_types.bank_account` (integer, nullable) Amount coming from [legacy US ACH payments](https://docs.stripe.com/ach-deprecated.md). - `issuing.available.source_types.card` (integer, nullable) Amount coming from most payment methods, including cards as well as [non-legacy bank debits](https://docs.stripe.com/payments/bank-debits.md). - `issuing.available.source_types.fpx` (integer, nullable) Amount coming from [FPX](https://docs.stripe.com/payments/fpx.md), a Malaysian payment method. - `livemode` (boolean) Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. - `pending` (array of objects) 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` (integer) Balance amount. - `pending.currency` (enum) 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). - `pending.source_types` (object, nullable) Breakdown of balance by source types. Funds coming from certain source / payment method types must be shown separately. All payment methods that do not have this restriction will be combined with the `card` source type balance. - `pending.source_types.bank_account` (integer, nullable) Amount coming from [legacy US ACH payments](https://docs.stripe.com/ach-deprecated.md). - `pending.source_types.card` (integer, nullable) Amount coming from most payment methods, including cards as well as [non-legacy bank debits](https://docs.stripe.com/payments/bank-debits.md). - `pending.source_types.fpx` (integer, nullable) Amount coming from [FPX](https://docs.stripe.com/payments/fpx.md), a Malaysian payment method. - `refund_and_dispute_prefunding` (object, nullable) Funds to cover future refunds, disputes, or a negative balance. See the [Add funds to your Stripe balance](https://docs.stripe.com/docs/get-started/account/add-funds.md) guide for more information. - `refund_and_dispute_prefunding.available` (array of objects) Funds that are available for use. - `refund_and_dispute_prefunding.available.amount` (integer) Balance amount. - `refund_and_dispute_prefunding.available.currency` (enum) 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). - `refund_and_dispute_prefunding.available.source_types` (object, nullable) Breakdown of balance by source types. Funds coming from certain source / payment method types must be shown separately. All payment methods that do not have this restriction will be combined with the `card` source type balance. - `refund_and_dispute_prefunding.available.source_types.bank_account` (integer, nullable) Amount coming from [legacy US ACH payments](https://docs.stripe.com/ach-deprecated.md). - `refund_and_dispute_prefunding.available.source_types.card` (integer, nullable) Amount coming from most payment methods, including cards as well as [non-legacy bank debits](https://docs.stripe.com/payments/bank-debits.md). - `refund_and_dispute_prefunding.available.source_types.fpx` (integer, nullable) Amount coming from [FPX](https://docs.stripe.com/payments/fpx.md), a Malaysian payment method. - `refund_and_dispute_prefunding.pending` (array of objects) Funds that are pending - `refund_and_dispute_prefunding.pending.amount` (integer) Balance amount. - `refund_and_dispute_prefunding.pending.currency` (enum) 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). - `refund_and_dispute_prefunding.pending.source_types` (object, nullable) Breakdown of balance by source types. Funds coming from certain source / payment method types must be shown separately. All payment methods that do not have this restriction will be combined with the `card` source type balance. - `refund_and_dispute_prefunding.pending.source_types.bank_account` (integer, nullable) Amount coming from [legacy US ACH payments](https://docs.stripe.com/ach-deprecated.md). - `refund_and_dispute_prefunding.pending.source_types.card` (integer, nullable) Amount coming from most payment methods, including cards as well as [non-legacy bank debits](https://docs.stripe.com/payments/bank-debits.md). - `refund_and_dispute_prefunding.pending.source_types.fpx` (integer, nullable) Amount coming from [FPX](https://docs.stripe.com/payments/fpx.md), a Malaysian payment method. ### The Balance object ```json { "object": "balance", "available": [ { "amount": 666670, "currency": "usd", "source_types": { "card": 666670 } } ], "connect_reserved": [ { "amount": 0, "currency": "usd" } ], "livemode": false, "pending": [ { "amount": 61414, "currency": "usd", "source_types": { "card": 61414 } } ] } ``` --- # Source: https://docs.stripe.com/financial-connections/balances.md # Access balances for a Financial Connections account Learn how to access an account's balances with your user's permission. The Financial Connections API allows you to retrieve up-to-date balances of a [Financial Connections Account](https://docs.stripe.com/api/financial_connections/accounts.md). Balance data is useful for a variety of applications, including reducing the risk of insufficient funds failures for ACH, underwriting, or building financial management tools. ## Before you begin You must have a completed Financial Connections registration to access balances in live mode. Visit your [Dashboard settings](https://dashboard.stripe.com/settings/financial-connections) to check the state of your registration or begin the registration process. Financial Connections test data is always available. ## Create a customer [Recommended] [Server-side] We recommend that you create a *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) with an email address and phone number to represent your user, that you then attach to your payment. Attaching a `Customer` object allows you to [list previously linked accounts ](https://docs.stripe.com/api/financial_connections/accounts/list.md) later. By providing the email address and phone number on the `Customer` object, Financial Connections can improve the authentication flow by simplifying sign-in or sign-up for your user, depending on whether they’re a returning [Link](https://support.stripe.com/questions/link-for-financial-connections-support-for-businesses) user. ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ -d email={{CUSTOMER_EMAIL}} \ -d phone={{CUSTOMER_PHONE}} ``` ```cli stripe customers create \ --email={{CUSTOMER_EMAIL}} \ --phone={{CUSTOMER_PHONE}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer = client.v1.customers.create({ email: '{{CUSTOMER_EMAIL}}', phone: '{{CUSTOMER_PHONE}}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer = client.v1.customers.create({ "email": "{{CUSTOMER_EMAIL}}", "phone": "{{CUSTOMER_PHONE}}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $customer = $stripe->customers->create([ 'email' => '{{CUSTOMER_EMAIL}}', 'phone' => '{{CUSTOMER_PHONE}}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CustomerCreateParams params = CustomerCreateParams.builder() .setEmail("{{CUSTOMER_EMAIL}}") .setPhone("{{CUSTOMER_PHONE}}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Customer customer = client.v1().customers().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const customer = await stripe.customers.create({ email: '{{CUSTOMER_EMAIL}}', phone: '{{CUSTOMER_PHONE}}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerCreateParams{ Email: stripe.String("{{CUSTOMER_EMAIL}}"), Phone: stripe.String("{{CUSTOMER_PHONE}}"), } result, err := sc.V1Customers.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CustomerCreateOptions { Email = "{{CUSTOMER_EMAIL}}", Phone = "{{CUSTOMER_PHONE}}", }; var client = new StripeClient("<>"); var service = client.V1.Customers; Customer customer = service.Create(options); ``` ## Request access to an account's balances [Server-side] You must collect an account before you can access its balance data. To learn more about how to collect Financial Connections Accounts consult the integration guide most relevant to your use case: [accept payments](https://docs.stripe.com/financial-connections/ach-direct-debit-payments.md), [facilitate Connect payouts](https://docs.stripe.com/financial-connections/connect-payouts.md), or [build other-data powered products](https://docs.stripe.com/financial-connections/other-data-powered-products.md). When collecting an account, you specify the data you need access to with the [permissions](https://docs.stripe.com/financial-connections/fundamentals.md#data-permissions) parameter. The set of requested data permissions are viewable by the user in the [authentication flow](https://docs.stripe.com/financial-connections/fundamentals.md#authentication-flow). Financial Connections Accounts are collectible through various integration paths, and how you specify the parameter varies slightly by API. #### Payment Intents ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=20000 \ -d currency=usd \ -d customer="{{CUSTOMER_ID}}" \ -d "payment_method_types[]"=us_bank_account \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=payment_method ``` ```cli stripe payment_intents create \ --amount=20000 \ --currency=usd \ --customer="{{CUSTOMER_ID}}" \ -d "payment_method_types[0]"=us_bank_account \ -d "payment_method_options[us_bank_account][financial_connections][permissions][0]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][1]"=payment_method ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 20000, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: {permissions: ['balances', 'payment_method']}, }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 20000, "currency": "usd", "customer": "{{CUSTOMER_ID}}", "payment_method_types": ["us_bank_account"], "payment_method_options": { "us_bank_account": { "financial_connections": {"permissions": ["balances", "payment_method"]}, }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 20000, 'currency' => 'usd', 'customer' => '{{CUSTOMER_ID}}', 'payment_method_types' => ['us_bank_account'], 'payment_method_options' => [ 'us_bank_account' => [ 'financial_connections' => ['permissions' => ['balances', 'payment_method']], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(20000L) .setCurrency("usd") .setCustomer("{{CUSTOMER_ID}}") .addPaymentMethodType("us_bank_account") .setPaymentMethodOptions( PaymentIntentCreateParams.PaymentMethodOptions.builder() .setUsBankAccount( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.builder() .setFinancialConnections( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.builder() .addPermission( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.BALANCES ) .addPermission( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.PAYMENT_METHOD ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 20000, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: { permissions: ['balances', 'payment_method'], }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(20000), Currency: stripe.String(stripe.CurrencyUSD), Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentMethodTypes: []*string{stripe.String("us_bank_account")}, PaymentMethodOptions: &stripe.PaymentIntentCreatePaymentMethodOptionsParams{ USBankAccount: &stripe.PaymentIntentCreatePaymentMethodOptionsUSBankAccountParams{ FinancialConnections: &stripe.PaymentIntentCreatePaymentMethodOptionsUSBankAccountFinancialConnectionsParams{ Permissions: []*string{ stripe.String(stripe.PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionBalances), stripe.String(stripe.PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionPaymentMethod), }, }, }, }, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 20000, Currency = "usd", Customer = "{{CUSTOMER_ID}}", PaymentMethodTypes = new List { "us_bank_account" }, PaymentMethodOptions = new PaymentIntentPaymentMethodOptionsOptions { UsBankAccount = new PaymentIntentPaymentMethodOptionsUsBankAccountOptions { FinancialConnections = new PaymentIntentPaymentMethodOptionsUsBankAccountFinancialConnectionsOptions { Permissions = new List { "balances", "payment_method" }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` #### Setup Intents ```curl curl https://api.stripe.com/v1/setup_intents \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "payment_method_types[]"=us_bank_account \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=payment_method ``` ```cli stripe setup_intents create \ --customer="{{CUSTOMER_ID}}" \ -d "payment_method_types[0]"=us_bank_account \ -d "payment_method_options[us_bank_account][financial_connections][permissions][0]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][1]"=payment_method ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") setup_intent = client.v1.setup_intents.create({ customer: '{{CUSTOMER_ID}}', payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: {permissions: ['balances', 'payment_method']}, }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. setup_intent = client.v1.setup_intents.create({ "customer": "{{CUSTOMER_ID}}", "payment_method_types": ["us_bank_account"], "payment_method_options": { "us_bank_account": { "financial_connections": {"permissions": ["balances", "payment_method"]}, }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $setupIntent = $stripe->setupIntents->create([ 'customer' => '{{CUSTOMER_ID}}', 'payment_method_types' => ['us_bank_account'], 'payment_method_options' => [ 'us_bank_account' => [ 'financial_connections' => ['permissions' => ['balances', 'payment_method']], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SetupIntentCreateParams params = SetupIntentCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .addPaymentMethodType("us_bank_account") .setPaymentMethodOptions( SetupIntentCreateParams.PaymentMethodOptions.builder() .setUsBankAccount( SetupIntentCreateParams.PaymentMethodOptions.UsBankAccount.builder() .setFinancialConnections( SetupIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.builder() .addPermission( SetupIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.BALANCES ) .addPermission( SetupIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.PAYMENT_METHOD ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. SetupIntent setupIntent = client.v1().setupIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const setupIntent = await stripe.setupIntents.create({ customer: '{{CUSTOMER_ID}}', payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: { permissions: ['balances', 'payment_method'], }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SetupIntentCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentMethodTypes: []*string{stripe.String("us_bank_account")}, PaymentMethodOptions: &stripe.SetupIntentCreatePaymentMethodOptionsParams{ USBankAccount: &stripe.SetupIntentCreatePaymentMethodOptionsUSBankAccountParams{ FinancialConnections: &stripe.SetupIntentCreatePaymentMethodOptionsUSBankAccountFinancialConnectionsParams{ Permissions: []*string{ stripe.String(stripe.SetupIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionBalances), stripe.String(stripe.SetupIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionPaymentMethod), }, }, }, }, } result, err := sc.V1SetupIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SetupIntentCreateOptions { Customer = "{{CUSTOMER_ID}}", PaymentMethodTypes = new List { "us_bank_account" }, PaymentMethodOptions = new SetupIntentPaymentMethodOptionsOptions { UsBankAccount = new SetupIntentPaymentMethodOptionsUsBankAccountOptions { FinancialConnections = new SetupIntentPaymentMethodOptionsUsBankAccountFinancialConnectionsOptions { Permissions = new List { "balances", "payment_method" }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.SetupIntents; SetupIntent setupIntent = service.Create(options); ``` #### Sessions ```curl curl https://api.stripe.com/v1/financial_connections/sessions \ -u "<>:" \ -d "account_holder[type]"=customer \ -d "account_holder[customer]"="{{CUSTOMER_ID}}" \ -d "permissions[]"=balances ``` ```cli stripe financial_connections sessions create \ -d "account_holder[type]"=customer \ -d "account_holder[customer]"="{{CUSTOMER_ID}}" \ -d "permissions[0]"=balances ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.financial_connections.sessions.create({ account_holder: { type: 'customer', customer: '{{CUSTOMER_ID}}', }, permissions: ['balances'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.financial_connections.sessions.create({ "account_holder": {"type": "customer", "customer": "{{CUSTOMER_ID}}"}, "permissions": ["balances"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->financialConnections->sessions->create([ 'account_holder' => [ 'type' => 'customer', 'customer' => '{{CUSTOMER_ID}}', ], 'permissions' => ['balances'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setAccountHolder( SessionCreateParams.AccountHolder.builder() .setType(SessionCreateParams.AccountHolder.Type.CUSTOMER) .setCustomer("{{CUSTOMER_ID}}") .build() ) .addPermission(SessionCreateParams.Permission.BALANCES) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().financialConnections().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.financialConnections.sessions.create({ account_holder: { type: 'customer', customer: '{{CUSTOMER_ID}}', }, permissions: ['balances'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.FinancialConnectionsSessionCreateParams{ AccountHolder: &stripe.FinancialConnectionsSessionCreateAccountHolderParams{ Type: stripe.String(stripe.FinancialConnectionsSessionAccountHolderTypeCustomer), Customer: stripe.String("{{CUSTOMER_ID}}"), }, Permissions: []*string{ stripe.String(stripe.FinancialConnectionsSessionPermissionBalances), }, } result, err := sc.V1FinancialConnectionsSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.FinancialConnections.SessionCreateOptions { AccountHolder = new Stripe.FinancialConnections.SessionAccountHolderOptions { Type = "customer", Customer = "{{CUSTOMER_ID}}", }, Permissions = new List { "balances" }, }; var client = new StripeClient("<>"); var service = client.V1.FinancialConnections.Sessions; Stripe.FinancialConnections.Session session = service.Create(options); ``` #### Checkout ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "payment_method_types[]"=us_bank_account \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=payment_method ``` ```cli stripe checkout sessions create \ --customer="{{CUSTOMER_ID}}" \ -d "payment_method_types[0]"=us_bank_account \ -d "payment_method_options[us_bank_account][financial_connections][permissions][0]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][1]"=payment_method ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ customer: '{{CUSTOMER_ID}}', payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: {permissions: ['balances', 'payment_method']}, }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "customer": "{{CUSTOMER_ID}}", "payment_method_types": ["us_bank_account"], "payment_method_options": { "us_bank_account": { "financial_connections": {"permissions": ["balances", "payment_method"]}, }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'customer' => '{{CUSTOMER_ID}}', 'payment_method_types' => ['us_bank_account'], 'payment_method_options' => [ 'us_bank_account' => [ 'financial_connections' => ['permissions' => ['balances', 'payment_method']], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .addPaymentMethodType(SessionCreateParams.PaymentMethodType.US_BANK_ACCOUNT) .setPaymentMethodOptions( SessionCreateParams.PaymentMethodOptions.builder() .setUsBankAccount( SessionCreateParams.PaymentMethodOptions.UsBankAccount.builder() .setFinancialConnections( SessionCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.builder() .addPermission( SessionCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.BALANCES ) .addPermission( SessionCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.PAYMENT_METHOD ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ customer: '{{CUSTOMER_ID}}', payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: { permissions: ['balances', 'payment_method'], }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentMethodTypes: []*string{stripe.String("us_bank_account")}, PaymentMethodOptions: &stripe.CheckoutSessionCreatePaymentMethodOptionsParams{ USBankAccount: &stripe.CheckoutSessionCreatePaymentMethodOptionsUSBankAccountParams{ FinancialConnections: &stripe.CheckoutSessionCreatePaymentMethodOptionsUSBankAccountFinancialConnectionsParams{ Permissions: []*string{ stripe.String(stripe.CheckoutSessionPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionBalances), stripe.String(stripe.CheckoutSessionPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionPaymentMethod), }, }, }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Customer = "{{CUSTOMER_ID}}", PaymentMethodTypes = new List { "us_bank_account" }, PaymentMethodOptions = new Stripe.Checkout.SessionPaymentMethodOptionsOptions { UsBankAccount = new Stripe.Checkout.SessionPaymentMethodOptionsUsBankAccountOptions { FinancialConnections = new Stripe.Checkout.SessionPaymentMethodOptionsUsBankAccountFinancialConnectionsOptions { Permissions = new List { "balances", "payment_method" }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Invoices ```curl curl https://api.stripe.com/v1/invoices \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "payment_settings[payment_method_types][]"=us_bank_account \ -d "payment_settings[payment_method_options][us_bank_account][financial_connections][permissions][]"=balances \ -d "payment_settings[payment_method_options][us_bank_account][financial_connections][permissions][]"=payment_method ``` ```cli stripe invoices create \ --customer="{{CUSTOMER_ID}}" \ -d "payment_settings[payment_method_types][0]"=us_bank_account \ -d "payment_settings[payment_method_options][us_bank_account][financial_connections][permissions][0]"=balances \ -d "payment_settings[payment_method_options][us_bank_account][financial_connections][permissions][1]"=payment_method ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") invoice = client.v1.invoices.create({ customer: '{{CUSTOMER_ID}}', payment_settings: { payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: {permissions: ['balances', 'payment_method']}, }, }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. invoice = client.v1.invoices.create({ "customer": "{{CUSTOMER_ID}}", "payment_settings": { "payment_method_types": ["us_bank_account"], "payment_method_options": { "us_bank_account": { "financial_connections": {"permissions": ["balances", "payment_method"]}, }, }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $invoice = $stripe->invoices->create([ 'customer' => '{{CUSTOMER_ID}}', 'payment_settings' => [ 'payment_method_types' => ['us_bank_account'], 'payment_method_options' => [ 'us_bank_account' => [ 'financial_connections' => ['permissions' => ['balances', 'payment_method']], ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); InvoiceCreateParams params = InvoiceCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .setPaymentSettings( InvoiceCreateParams.PaymentSettings.builder() .addPaymentMethodType( InvoiceCreateParams.PaymentSettings.PaymentMethodType.US_BANK_ACCOUNT ) .setPaymentMethodOptions( InvoiceCreateParams.PaymentSettings.PaymentMethodOptions.builder() .setUsBankAccount( InvoiceCreateParams.PaymentSettings.PaymentMethodOptions.UsBankAccount.builder() .setFinancialConnections( InvoiceCreateParams.PaymentSettings.PaymentMethodOptions.UsBankAccount.FinancialConnections.builder() .addPermission( InvoiceCreateParams.PaymentSettings.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.BALANCES ) .addPermission( InvoiceCreateParams.PaymentSettings.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.PAYMENT_METHOD ) .build() ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Invoice invoice = client.v1().invoices().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const invoice = await stripe.invoices.create({ customer: '{{CUSTOMER_ID}}', payment_settings: { payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: { permissions: ['balances', 'payment_method'], }, }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.InvoiceCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentSettings: &stripe.InvoiceCreatePaymentSettingsParams{ PaymentMethodTypes: []*string{ stripe.String(stripe.InvoicePaymentSettingsPaymentMethodTypeUSBankAccount), }, PaymentMethodOptions: &stripe.InvoiceCreatePaymentSettingsPaymentMethodOptionsParams{ USBankAccount: &stripe.InvoiceCreatePaymentSettingsPaymentMethodOptionsUSBankAccountParams{ FinancialConnections: &stripe.InvoiceCreatePaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsParams{ Permissions: []*string{ stripe.String(stripe.InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionBalances), stripe.String(stripe.InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionPaymentMethod), }, }, }, }, }, } result, err := sc.V1Invoices.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new InvoiceCreateOptions { Customer = "{{CUSTOMER_ID}}", PaymentSettings = new InvoicePaymentSettingsOptions { PaymentMethodTypes = new List { "us_bank_account" }, PaymentMethodOptions = new InvoicePaymentSettingsPaymentMethodOptionsOptions { UsBankAccount = new InvoicePaymentSettingsPaymentMethodOptionsUsBankAccountOptions { FinancialConnections = new InvoicePaymentSettingsPaymentMethodOptionsUsBankAccountFinancialConnectionsOptions { Permissions = new List { "balances", "payment_method" }, }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Invoices; Invoice invoice = service.Create(options); ``` #### Subscriptions ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d customer={{CUSTOMER_ID}} \ -d "payment_settings[payment_method_types][]"=us_bank_account \ -d "payment_settings[payment_method_options][us_bank_account][financial_connections][permissions][]"=balances \ -d "payment_settings[payment_method_options][us_bank_account][financial_connections][permissions][]"=payment_method ``` ```cli stripe subscriptions create \ --customer={{CUSTOMER_ID}} \ -d "payment_settings[payment_method_types][0]"=us_bank_account \ -d "payment_settings[payment_method_options][us_bank_account][financial_connections][permissions][0]"=balances \ -d "payment_settings[payment_method_options][us_bank_account][financial_connections][permissions][1]"=payment_method ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.create({ customer: '{{CUSTOMER_ID}}', payment_settings: { payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: {permissions: ['balances', 'payment_method']}, }, }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.create({ "customer": "{{CUSTOMER_ID}}", "payment_settings": { "payment_method_types": ["us_bank_account"], "payment_method_options": { "us_bank_account": { "financial_connections": {"permissions": ["balances", "payment_method"]}, }, }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->create([ 'customer' => '{{CUSTOMER_ID}}', 'payment_settings' => [ 'payment_method_types' => ['us_bank_account'], 'payment_method_options' => [ 'us_bank_account' => [ 'financial_connections' => ['permissions' => ['balances', 'payment_method']], ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionCreateParams params = SubscriptionCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .setPaymentSettings( SubscriptionCreateParams.PaymentSettings.builder() .addPaymentMethodType( SubscriptionCreateParams.PaymentSettings.PaymentMethodType.US_BANK_ACCOUNT ) .setPaymentMethodOptions( SubscriptionCreateParams.PaymentSettings.PaymentMethodOptions.builder() .setUsBankAccount( SubscriptionCreateParams.PaymentSettings.PaymentMethodOptions.UsBankAccount.builder() .setFinancialConnections( SubscriptionCreateParams.PaymentSettings.PaymentMethodOptions.UsBankAccount.FinancialConnections.builder() .addPermission( SubscriptionCreateParams.PaymentSettings.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.BALANCES ) .addPermission( SubscriptionCreateParams.PaymentSettings.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.PAYMENT_METHOD ) .build() ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.create({ customer: '{{CUSTOMER_ID}}', payment_settings: { payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: { permissions: ['balances', 'payment_method'], }, }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentSettings: &stripe.SubscriptionCreatePaymentSettingsParams{ PaymentMethodTypes: []*string{ stripe.String(stripe.SubscriptionPaymentSettingsPaymentMethodTypeUSBankAccount), }, PaymentMethodOptions: &stripe.SubscriptionCreatePaymentSettingsPaymentMethodOptionsParams{ USBankAccount: &stripe.SubscriptionCreatePaymentSettingsPaymentMethodOptionsUSBankAccountParams{ FinancialConnections: &stripe.SubscriptionCreatePaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsParams{ Permissions: []*string{ stripe.String(stripe.SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionBalances), stripe.String(stripe.SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionPaymentMethod), }, }, }, }, }, } result, err := sc.V1Subscriptions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionCreateOptions { Customer = "{{CUSTOMER_ID}}", PaymentSettings = new SubscriptionPaymentSettingsOptions { PaymentMethodTypes = new List { "us_bank_account" }, PaymentMethodOptions = new SubscriptionPaymentSettingsPaymentMethodOptionsOptions { UsBankAccount = new SubscriptionPaymentSettingsPaymentMethodOptionsUsBankAccountOptions { FinancialConnections = new SubscriptionPaymentSettingsPaymentMethodOptionsUsBankAccountFinancialConnectionsOptions { Permissions = new List { "balances", "payment_method" }, }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Create(options); ``` When using dynamic payment methods for certain payments APIs, you can also configure requested permissions in the Dashboard. Learn how to [access additional account data on Financial Connections accounts](https://docs.stripe.com/financial-connections/ach-direct-debit-payments.md?dashboard-or-api=dashboard#access). ## Initiate a balance refresh [Server-side] All Financial Connections data retrievals are asynchronous. You initiate a balance refresh and wait for it to complete, then retrieve the results. You can initiate balance refreshes with the `prefetch` API parameter or the [Refresh API](https://docs.stripe.com/api/financial_connections/accounts/refresh.md). ### Prefetch balance data Specify whether you want to prefetch account balances *before* account collection. This initiates the refresh process as soon as your user connects their account in the [authentication flow](https://docs.stripe.com/financial-connections/fundamentals.md#authentication-flow). Set `prefetch` when you require balance data for every linked account, to make sure you receive it with minimal delay. An example of this is if you plan to perform balance checks prior to initiating an ACH payment. The `prefetch` parameter is available on all APIs that support Financial Connections. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=20000 \ -d currency=usd \ -d "payment_method_types[]"=us_bank_account \ -d "payment_method_options[us_bank_account][financial_connections][prefetch][]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=payment_method \ -d "payment_method_options[us_bank_account][financial_connections][permissions][]"=balances ``` ```cli stripe payment_intents create \ --amount=20000 \ --currency=usd \ -d "payment_method_types[0]"=us_bank_account \ -d "payment_method_options[us_bank_account][financial_connections][prefetch][0]"=balances \ -d "payment_method_options[us_bank_account][financial_connections][permissions][0]"=payment_method \ -d "payment_method_options[us_bank_account][financial_connections][permissions][1]"=balances ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 20000, currency: 'usd', payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: { prefetch: ['balances'], permissions: ['payment_method', 'balances'], }, }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 20000, "currency": "usd", "payment_method_types": ["us_bank_account"], "payment_method_options": { "us_bank_account": { "financial_connections": { "prefetch": ["balances"], "permissions": ["payment_method", "balances"], }, }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 20000, 'currency' => 'usd', 'payment_method_types' => ['us_bank_account'], 'payment_method_options' => [ 'us_bank_account' => [ 'financial_connections' => [ 'prefetch' => ['balances'], 'permissions' => ['payment_method', 'balances'], ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(20000L) .setCurrency("usd") .addPaymentMethodType("us_bank_account") .setPaymentMethodOptions( PaymentIntentCreateParams.PaymentMethodOptions.builder() .setUsBankAccount( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.builder() .setFinancialConnections( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.builder() .addPrefetch( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Prefetch.BALANCES ) .addPermission( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.PAYMENT_METHOD ) .addPermission( PaymentIntentCreateParams.PaymentMethodOptions.UsBankAccount.FinancialConnections.Permission.BALANCES ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 20000, currency: 'usd', payment_method_types: ['us_bank_account'], payment_method_options: { us_bank_account: { financial_connections: { prefetch: ['balances'], permissions: ['payment_method', 'balances'], }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(20000), Currency: stripe.String(stripe.CurrencyUSD), PaymentMethodTypes: []*string{stripe.String("us_bank_account")}, PaymentMethodOptions: &stripe.PaymentIntentCreatePaymentMethodOptionsParams{ USBankAccount: &stripe.PaymentIntentCreatePaymentMethodOptionsUSBankAccountParams{ FinancialConnections: &stripe.PaymentIntentCreatePaymentMethodOptionsUSBankAccountFinancialConnectionsParams{ Prefetch: []*string{ stripe.String(stripe.PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPrefetchBalances), }, Permissions: []*string{ stripe.String(stripe.PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionPaymentMethod), stripe.String(stripe.PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermissionBalances), }, }, }, }, } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 20000, Currency = "usd", PaymentMethodTypes = new List { "us_bank_account" }, PaymentMethodOptions = new PaymentIntentPaymentMethodOptionsOptions { UsBankAccount = new PaymentIntentPaymentMethodOptionsUsBankAccountOptions { FinancialConnections = new PaymentIntentPaymentMethodOptionsUsBankAccountFinancialConnectionsOptions { Prefetch = new List { "balances" }, Permissions = new List { "payment_method", "balances" }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` ### Initiate an on-demand refresh Use the [Refresh API](https://docs.stripe.com/api/financial_connections/accounts/refresh.md) to initiate on-demand balance refreshes *after* account collection, and fetch balance information for a specific account at your convenience, allowing you to defer the decision until a later time. Use the Financial Connections account ID to initiate a refresh. If you’re integrating through a payments flow, find the account ID [on the associated Payment Method](https://docs.stripe.com/financial-connections/ach-direct-debit-payments.md#finding-the-financial-connections-account-id). When using a Financial Connections Session, retrieve it [through the session](https://docs.stripe.com/financial-connections/other-data-powered-products.md?platform=web#collect-an-account). ```curl curl https://api.stripe.com/v1/financial_connections/accounts/{{FINANCIALCONNECTIONSACCOUNT_ID}}/refresh \ -u "<>:" \ -d "features[]"=balance ``` ```cli stripe financial_connections accounts refresh {{FINANCIALCONNECTIONSACCOUNT_ID}} \ -d "features[0]"=balance ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.financial_connections.accounts.refresh( '{{FINANCIALCONNECTIONSACCOUNT_ID}}', {features: ['balance']}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.financial_connections.accounts.refresh( "{{FINANCIALCONNECTIONSACCOUNT_ID}}", {"features": ["balance"]}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->financialConnections->accounts->refresh( '{{FINANCIALCONNECTIONSACCOUNT_ID}}', ['features' => ['balance']] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountRefreshParams params = AccountRefreshParams.builder().addFeature(AccountRefreshParams.Feature.BALANCE).build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().financialConnections().accounts().refresh( "{{FINANCIALCONNECTIONSACCOUNT_ID}}", params ); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.financialConnections.accounts.refresh( '{{FINANCIALCONNECTIONSACCOUNT_ID}}', { features: ['balance'], } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.FinancialConnectionsAccountRefreshParams{ Features: []*string{stripe.String("balance")}, } result, err := sc.V1FinancialConnectionsAccounts.Refresh( context.TODO(), "{{FINANCIALCONNECTIONSACCOUNT_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.FinancialConnections.AccountRefreshOptions { Features = new List { "balance" }, }; var client = new StripeClient("<>"); var service = client.V1.FinancialConnections.Accounts; Stripe.FinancialConnections.Account account = service.Refresh( "{{FINANCIALCONNECTIONSACCOUNT_ID}}", options); ``` > Refreshes aren’t allowed on inactive accounts. ### Wait for the balance refresh to complete The [balance_refresh](https://docs.stripe.com/api/financial_connections/accounts/object.md#financial_connections_account_object-balance_refresh) field on a Financial Connections account represents the balance refresh state. This field remains `null` until you request the `balances` permission and initiate a refresh. After you start a balance refresh, the state changes to `pending`, and after completion, it moves to either `succeeded` or `failed`. We send the [financial_connections.account.refreshed_balance](https://docs.stripe.com/api/events/types.md#event_types-financial_connections.account.refreshed_balance) event when the balance refresh completes. To determine the success of the refresh, check the `balance_refresh.status` field while handling the webhook. Balance refresh flow (See full diagram at https://docs.stripe.com/financial-connections/balances) After a balance refresh completes, Stripe sets the availability of future refreshes through the [balance_refresh.next_refresh_available_at](https://docs.stripe.com/api/financial_connections/accounts/object.md#financial_connections_account_object-balance_refresh-next_refresh_available_at) field. Check this field before initiating a new balance refresh to make sure that refreshes are currently available. If you attempt a refresh while the value is `null` (as is always the case when the refresh is pending or the account is inactive) or the current time is less than the `next_refresh_available_at` timestamp, the refresh won’t be initiated. > In the unlikely event that a refresh fails, the `error` field on the refresh hash is a preview feature that provides the cause of the failure and recommended next steps. If you’d like to use it, [email us](mailto:financial-connections-beta+refresh-error@stripe.com) for access. ## Retrieve an account's balances [Server-side] After the balance refresh has completed, retrieve the Financial Connections Account from the body of the [financial_connections.account.refreshed_balance](https://docs.stripe.com/api/events/types.md#event_types-financial_connections.account.refreshed_balance) event or through the API. ```curl curl https://api.stripe.com/v1/financial_connections/accounts/{{FINANCIALCONNECTIONSACCOUNT_ID}} \ -u "<>:" ``` ```cli stripe financial_connections accounts retrieve {{FINANCIALCONNECTIONSACCOUNT_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.financial_connections.accounts.retrieve('{{FINANCIALCONNECTIONSACCOUNT_ID}}') ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.financial_connections.accounts.retrieve( "{{FINANCIALCONNECTIONSACCOUNT_ID}}", ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->financialConnections->accounts->retrieve( '{{FINANCIALCONNECTIONSACCOUNT_ID}}', [] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountRetrieveParams params = AccountRetrieveParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().financialConnections().accounts().retrieve( "{{FINANCIALCONNECTIONSACCOUNT_ID}}", params ); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.financialConnections.accounts.retrieve( '{{FINANCIALCONNECTIONSACCOUNT_ID}}' ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.FinancialConnectionsAccountRetrieveParams{} result, err := sc.V1FinancialConnectionsAccounts.GetByID( context.TODO(), "{{FINANCIALCONNECTIONSACCOUNT_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.FinancialConnections.Accounts; Stripe.FinancialConnections.Account account = service.Get( "{{FINANCIALCONNECTIONSACCOUNT_ID}}"); ``` If the refresh completed successfully, the account object contains balance data. ```json { "id": "fca_1Jbry3BAjqvGMUSxCDjFsrLU", "object": "financial_connections.account", "balance": { "as_of": 1651516592, "cash": { "available": { "usd": 6000 } }, "current": { "usd": 6000 }, "type": "cash" }, "balance_refresh": { "last_attempted_at": 1651516582, "next_refresh_available_at": 1651516583, "status": "succeeded", }, // ... other fields on the Financial Connections Account } ``` #### Balance data details The `balance` hash describes the different types of balances made available by a financial institution. | Balance Types | Description | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `current` | The `current` balance is the amount of funds that have posted to the account. This amount ignores events that have yet to post to an account such as incoming transfers, outgoing transfers, and other holds. A positive amount indicates money owed to the account holder. A negative amount indicates money owed by the account holder. | | `available` | The balance object is polymorphic, with types `cash` and `credit`. If the balance has `type: "cash"`, you’ll see a `cash` sub-object with the `available` property, which is the amount of funds available for use, such as any to be transferred or paid out, after considering incoming and outgoing holds. | | `used` | The balance object is polymorphic, with types `cash` and `credit`. If the balance has `type: "credit"`, you’ll see a `credit` sub-object with the `used` property, which is the amount of funds that have been consumed after taking outgoing holds into account. For credit balances, `current` and `used` amounts use the same sign convention used for cash balances: a positive amount means funds owed *to* the account holder, a negative amount means funds owed *by* the account holder. In most cases a credit balance has negative amounts. | The availability of balances varies by underlying financial institution. We return all balance data that we have access to. In rare cases, most often when dealing with smaller financial institutions, Stripe can’t retrieve balance data from a financial institution or partner of any kind, in which case the `balance` object is `null`. The balance object is also `null` if the account has been disconnected. In some instances only a `current` balance is returned, or a balance that is up to 24 hours stale. See our list of [supported institutions](https://docs.stripe.com/financial-connections/supported-institutions.md) for data coverage. For the `cash` balance type, use the `available` sub-object to confirm sufficient funds exist prior to initiating an ACH Direct Debit payment. If an `available` balance is null, you might want to use the `current` balance to confirm sufficient funds prior to initiating an ACH Direct Debit, but be mindful that this amount ignores events that have yet to post to an account such as incoming transfers, outgoing transfers, and other holds. The `as_of` field on a balance is the date and time that the financial institution calculated this balance. This isn’t the same as the date and time of balance data retrieval. For example, certain institutions only update balance data once per day, while others update more frequently. --- # Source: https://docs.stripe.com/payments/bank-debits.md # Bank Debits Learn how to accept bank debits with Stripe. With bank debits, you can pull funds directly from your customer’s bank account for both one-time and recurring purchases. Bank debits are often used by: - Businesses collecting recurring payments from other businesses. - Retail and services businesses that want a low-cost alternative to cards for large consumer payments, like rent or tuition. Bank debits might not be a good fit for your business if: - You deliver goods immediately after checkout because payment confirmation takes several business days. - Your business is sensitive to disputes—consider other payment methods because some bank debit methods favor the customer during disputes. ## Payment flow To initiate a bank debit, a customer enters their bank account details during checkout and gives you permission to debit the account. This permission is called a mandate. ![Flow chart of the three step process the customer experiences. First, they select bank debit at checkout. Next the customer provides banking details and authorizes mandate. Finally, the customer gets notification that the payment is complete.](https://b.stripecdn.com/docs-statics-srv/assets/payment_flow.e4fcc05342cae882b39c41b497e5a24d.svg) To reduce fraud with some bank debits, verify the bank account before the payment by confirming microdeposits or bank login. Verifying bank login can improve the user experience because customers pay by logging into their bank rather than entering bank account details. ## Product support You can use a single integration for all bank debits that works across Stripe products. With [Stripe Checkout](https://docs.stripe.com/payments/checkout.md), [Payment Element](https://docs.stripe.com/payments/payment-element.md), and [Payment Links](https://docs.stripe.com/payment-links.md), you can enable bank debits directly from the Dashboard with no integration work. | Payment method | [Connect](https://docs.stripe.com/connect.md) | [Checkout](https://docs.stripe.com/payments/checkout.md) | [Payment Links](https://docs.stripe.com/payment-links.md) | [Payment Element](https://docs.stripe.com/payments/payment-element.md) | [Express Checkout Element](https://docs.stripe.com/elements/express-checkout-element.md) | [Mobile Payment Element](https://docs.stripe.com/payments/mobile.md) | [Subscriptions](https://docs.stripe.com/subscriptions.md) | [Invoicing](https://docs.stripe.com/invoicing.md) | [Customer Portal](https://docs.stripe.com/customer-management.md) | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------- | | [Instant Bank Payments](https://docs.stripe.com/payments/link/instant-bank-payments.md) or [ACH Direct Debit](https://docs.stripe.com/payments/ach-direct-debit.md) | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | | [Bacs Direct Debit](https://docs.stripe.com/payments/payment-methods/bacs-debit.md) | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported 1 | ✓ Supported | ✓ Supported | | [Australia BECS Direct Debit](https://docs.stripe.com/payments/au-becs-debit.md) | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | | [New Zealand BECS Direct Debit](https://docs.stripe.com/payments/nz-bank-account.md) | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | | [Pre-authorized debit in Canada](https://docs.stripe.com/payments/acss-debit.md) | ✓ Supported | ✓ Supported 2 | - Unsupported | ✓ Supported 3,4 | - Unsupported | - Unsupported | ✓ Supported | ✓ Supported | ✓ Supported | | [SEPA Direct Debit](https://docs.stripe.com/payments/sepa-debit.md) | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | 1 You can’t use the Payment Element to create SetupIntents for Bacs Direct Debit. Use Checkout in [setup mode](https://docs.stripe.com/payments/save-and-reuse.md?platform=checkout) instead.2 Not supported when using Checkout in subscription mode.3 Supports ACSS debit if you [create a PaymentIntent before rendering the Payment Element](https://docs.stripe.com/payments/accept-a-payment-deferred.md).4 Not supported when using [Elements with the Checkout Sessions API](https://docs.stripe.com/payments/quickstart-checkout-sessions.md). [Contact us](https://support.stripe.com/contact) to request a new bank debit method. ## API support | Payment method | API enum | [PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) | [SetupIntents](https://docs.stripe.com/payments/setup-intents.md) | [Manual capture](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md) | [Setup future usage](https://docs.stripe.com/payments/save-during-payment.md?platform=web&ui=elements)1 | Requires redirect2 | | ------------------------------------------------------------------------------------ | ----------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------ | | [ACH Direct Debit](https://docs.stripe.com/payments/ach-direct-debit.md) | `us_bank_account` | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | No | | [Bacs Direct debit](https://docs.stripe.com/payments/payment-methods/bacs-debit.md) | `bacs_debit` | ✓ Supported 3 | - Unsupported 4 | - Unsupported | ✓ Supported | No | | [Australia BECS Direct Debit](https://docs.stripe.com/payments/au-becs-debit.md) | `au_becs_debit` | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | No | | [New Zealand BECS Direct Debit](https://docs.stripe.com/payments/nz-bank-account.md) | `nz_bank_account` | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | No | | [Pre-authorized debit in Canada](https://docs.stripe.com/payments/acss-debit.md)5 | `acss_debit` | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | No | | [SEPA debit](https://docs.stripe.com/payments/sepa-debit.md) | `sepa_debit` | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | No | 1 Cards and bank debit methods including SEPA debit, AU BECS direct debit, and ACSS debit support both `on_session` and `off_session` with [setup future usage](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-setup_future_usage). All other payment method types either don’t support `setup_future_usage` or only support `off_session`.2 Payment methods might require confirmation with [return_url](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-return_url) to indicate where Stripe should redirect your customer after they complete the payment.3 PaymentIntents support confirmation with Bacs Direct Debit payment methods when the [Mandate](https://docs.stripe.com/api/mandates.md) has been collected by a Stripe-owned flow such as [Checkout](https://docs.stripe.com/payments/checkout.md), [Payment Element](https://docs.stripe.com/payments/payment-element.md), and [Payment Links](https://docs.stripe.com/payment-links.md).4 You can create SetupIntents for Bacs Direct Debit through [Checkout](https://docs.stripe.com/payments/checkout.md) using [setup mode](https://docs.stripe.com/payments/save-and-reuse.md?platform=checkout).5 Pre-authorized debit in Canada doesn’t support the [deferred intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md) creation integration path. ## Migrating from the Sources, Tokens, or Charges APIs If your current bank debit integration uses the Sources, Tokens, or Bank Accounts API, we recommend following the appropriate migration guide to transition to *Payment Intents API* (The Payment Intents API tracks the lifecycle of a customer checkout flow and triggers additional authentication steps when required by regulatory mandates, custom Radar fraud rules, or redirect-based payment methods): - [ACH migration guide](https://docs.stripe.com/payments/ach-direct-debit/migrating-from-charges.md) - For all other bank debit payment methods, follow the general [migration guide](https://docs.stripe.com/payments/payment-intents/migration.md) --- # Source: https://docs.stripe.com/payments/bank-redirects.md # Bank redirects Learn about bank redirects with Stripe. Bank redirects let customers pay online using their bank account. They drive more than half of online commerce in Germany, the Netherlands, and Malaysia. Bank redirects are often used by: - Retailers that want to improve conversion and reduce fraud with consumers in Europe and Asia Pacific. - Software or service businesses collecting one-time payments from other businesses. Bank redirects might not be a good fit for your business if you sell *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis). Some bank redirects don’t support recurring payments. ## Payment flow At checkout, the customer is redirected to their online banking portal, logs in with their bank credentials, approves the transaction, and then returns to your site. Some bank redirects verify the user through SMS or other two-factor authentication for additional security. ![Bank redirect payment flow from checkout to payment confirmation.](https://b.stripecdn.com/docs-statics-srv/assets/payment_flow.d6b9be158ecbb4b70a85d2497da2e405.svg) ## Product support We’ve created a single integration for all bank redirects that works across Stripe products. With [Stripe Checkout](https://docs.stripe.com/payments/checkout.md), you can add any bank redirect by changing one line of code. | Payment method | [Connect](https://docs.stripe.com/connect.md) | [Checkout](https://docs.stripe.com/payments/checkout.md) | [Payment Links](https://docs.stripe.com/payment-links.md) | [Payment Element](https://docs.stripe.com/payments/payment-element.md) | [Express Checkout Element](https://docs.stripe.com/elements/express-checkout-element.md) | [Mobile Payment Element](https://docs.stripe.com/payments/mobile.md) | [Subscriptions](https://docs.stripe.com/subscriptions.md) | [Invoicing](https://docs.stripe.com/invoicing.md) | [Customer Portal](https://docs.stripe.com/customer-management.md) | | ------------------------------------------------------------ | --------------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------- | | [Bancontact](https://docs.stripe.com/payments/bancontact.md) | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported 7 | Invite only | - Unsupported | | [BLIK](https://docs.stripe.com/payments/blik.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported 3,4 | - Unsupported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | | [EPS](https://docs.stripe.com/payments/eps.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported 7 | Invite only | - Unsupported | | [FPX](https://docs.stripe.com/payments/fpx.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported 7 | ✓ Supported | - Unsupported | | [iDEAL](https://docs.stripe.com/payments/ideal.md) | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported 5,6,7 | ✓ Supported 6 | - Unsupported | | [P24](https://docs.stripe.com/payments/p24.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported 7 | Invite only | - Unsupported | | [TWINT](https://docs.stripe.com/payments/twint.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | 1 Not supported when using Checkout in subscription mode.2 Not supported when using Checkout in setup mode.3 Not supported when [collecting payment details before creating a PaymentIntent](https://docs.stripe.com/payments/accept-a-payment-deferred.md).4 Not supported when using [Elements with the Checkout Sessions API](https://docs.stripe.com/payments/quickstart-checkout-sessions.md).5 Only supported when using [Checkout in subscription mode](https://docs.stripe.com/billing/subscriptions/ideal.md).6 Not supported when using `charge_automatically` for subscriptions or invoices. iDEAL is a [single use](https://docs.stripe.com/payments/payment-methods.md#usage) payment method where customers are required to [authenticate](https://docs.stripe.com/payments/payment-methods.md#customer-actions) each payment.7 Invoices and Subscriptions only support the [send_invoice](https://docs.stripe.com/api/invoices/object.md#invoice_object-collection_method) collection method. [Contact us](https://support.stripe.com/contact) to request a new bank redirect payment method. ## API support | Payment method | API enum | [PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) | [SetupIntents](https://docs.stripe.com/payments/setup-intents.md) | [Manual capture](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md) | [Setup future usage](https://docs.stripe.com/payments/save-during-payment.md?platform=web&ui=elements)1 | Requires redirect2 | | -------------------------------------------------------------- | ------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------ | | [Bancontact](https://docs.stripe.com/payments/bancontact.md) | `bancontact` | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | Yes | | [BLIK](https://docs.stripe.com/payments/blik.md)3 | `blik` | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | No | | [EPS](https://docs.stripe.com/payments/eps.md) | `eps` | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | Yes | | [FPX](https://docs.stripe.com/payments/fpx.md) | `fpx` | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | Yes | | [iDEAL](https://docs.stripe.com/payments/ideal.md) | `ideal` | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | Yes | | [P24](https://docs.stripe.com/payments/p24.md) | `p24` | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | Yes | | [Pay by Bank](https://docs.stripe.com/payments/pay-by-bank.md) | `pay_by_bank` | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | Yes | | [TWINT](https://docs.stripe.com/payments/twint.md) | `twint` | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | Yes | 1 Cards and bank debit methods including SEPA debit, AU BECS direct debit, and ACSS debit support both `on_session` and `off_session` with [setup future usage](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-setup_future_usage). All other payment method types either don’t support `setup_future_usage` or only support `off_session`.2 Payment methods might require confirmation with [return_url](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-return_url) to indicate where Stripe should redirect your customer after they complete the payment.3 BLIK doesn’t support the [deferred intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md) creation integration path. ## Migrating from the Sources or Tokens APIs If you currently use the Sources or Tokens API, see [migrating to PaymentIntents](https://docs.stripe.com/payments/payment-intents/migration.md) to use the latest integrations. --- # Source: https://docs.stripe.com/payments/bank-transfers.md # Bank transfer payments Learn about bank transfers and managing payments with the customer balance. Available in: EU, GB, JP, MX, US Bank transfers provide a safe way for customers to send money over bank rails. When accepting bank transfers with Stripe, you provide customers with a virtual bank account number that they can push money to from their own online bank interface or in-person bank branch. Stripe uses this virtual account number to automate reconciliation and prevent exposing your real account details to customers. > #### Turn on bank transfers > > To turn on bank transfer payments, go to your [Payment methods settings](https://dashboard.stripe.com/settings/payment_methods). ## Bank transfer methods Stripe supports the following bank transfer methods: - JPY bank transfers in Japan - GBP bank transfers in the UK - EUR bank transfers in the UK, US, and SEPA countries - MXN bank transfers in Mexico - USD bank transfers in the US, UK, and SEPA countries Please [contact us](https://support.stripe.com/contact) to request another bank transfer method. Learn more about [country and currency support](https://docs.stripe.com/payments/payment-methods/payment-method-support.md#country-currency-support). ## Get started You don’t have to integrate Bank Transfers and other payment methods individually. If you use our front-end products, Stripe automatically determines the most relevant payment methods to display. Go to the [Stripe Dashboard](https://dashboard.stripe.com/settings/payment_methods) and enable Bank Transfers. To get started with one of our hosted UIs, follow a quickstart: - [Checkout](https://docs.stripe.com/checkout/quickstart.md): Our prebuilt, hosted checkout page. - [Elements](https://docs.stripe.com/payments/quickstart.md): Our drop-in UI components. ### Other payment products The following Stripe products also let you add Bank Transfers from the Dashboard: - [Invoicing](https://docs.stripe.com/invoicing/no-code-guide.md) - [Subscriptions](https://docs.stripe.com/billing/subscriptions/overview.md) > #### Checkout requirement > > Enabling bank transfers on the checkout page requires specifying the [customer](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer) in the checkout session. If you prefer to manually list payment methods, or want to learn more about how bank transfers work with invoicing and subscriptions, see the following guides: - [Accept a bank transfer payment](https://docs.stripe.com/payments/bank-transfers/accept-a-payment.md) - [Send an invoice with bank transfer instructions](https://docs.stripe.com/invoicing/bank-transfer.md) - [Set up a subscription with bank transfers as a payment method](https://docs.stripe.com/billing/subscriptions/bank-transfer.md) ## Customer balance Unlike most payment methods, bank transfers don’t allow you to control the amount a customer sends to you, which means that customers might send too much or too little money by accident. To manage common overpayment and underpayment issues, Stripe holds your customer’s bank transfers in a [customer balance](https://docs.stripe.com/payments/customer-balance.md) that you can reconcile payments from. This allows you to track how much your customers owe, regardless of how much or how often they send funds. If unreconciled funds are held in the customer balance for more than 75 days, Stripe automatically attempts to return the funds to the customer’s bank account. When Stripe doesn’t have the customer’s account information, Stripe might reach out to the customer directly to initiate the refund. If Stripe is unable to determine the customer’s account information by the 90 day mark, we sweep the unreconciled funds to your Stripe account balance. For further information on what happens when funds remain unreconciled, see the [reconciliation documentation](https://docs.stripe.com/payments/customer-balance/reconciliation.md#cash-unreconciled-funds). ## International payments Bank transfers users in the United States can accept international wire transfers (SWIFT). International wire transfers may incur fees on the way to Stripe, which can result in an amount received that’s less than what the customer originally sent. Stripe-incurred fees appear on the balances page in the Dashboard, alongside other relevant Stripe fees. The amount shown in the cash balance is the amount that Stripe received from the customer. International transfers can take a longer period of time to settle into the customer balance. Stripe doesn’t support refunds for international wires. You’re responsible for executing any refunds related to these payments. > #### Note on currencies > > The accounts that support international payments only support their own currency. For example, US accounts support SWIFT transfers in USD only. ## Cross-border payments Bank transfers users in the United States can accept EUR payments from customers in SEPA countries. With cross-border bank transfers, you create payments in the currency local to the customer’s country and the customer gets a virtual bank account number local to their country. You don’t have to have an account setup for the customer’s country to use cross-border bank transfers. Cross-border bank transfers incur additional fees that are visible in the Dashboard. Offering payments to a local bank account with a customer’s local currency helps reduce the friction and cost involved in sending money abroad. ### Implement cross-border payments To accept cross-border payments, create an additional bank transfers account under the customer with the relevant currency. This generates the relevant funding instructions. 1. In the **Customers** page of the [Dashboard](https://dashboard.stripe.com/customers), choose the customer to enable cross-border payments for. 1. In the **Payment Methods** section, click Add (+) and choose **Add a bank transfer account**. 1. In the editor, choose the currency to charge the customer in for their bank transfer payments. 1. Choose which country to present the specified currency to the customer. 1. Click **Add**. ## Refunds You can refund customer balance payments: - Directly to the customer’s bank account - Back to the customer’s cash balance, where the refund can be used towards another customer balance payment To refund to the customer’s bank account, Stripe requires the customer’s bank account details. In some cases, Stripe receives these details when the customer transfers funds. When these details aren’t available, Stripe sends an email to the customer to collect bank account details and initiate a transfer when we receive those details. If your customer has excess funds in their customer balance, you can initiate a return of funds through the Dashboard or the API. For more information, see [Refund bank transfer payments](https://docs.stripe.com/payments/customer-balance/refunding.md). ## Funding instructions You can show bank account details to your customer before they make their first payment through the Dashboard or the API. See [Funding instructions](https://docs.stripe.com/payments/customer-balance/funding-instructions.md) for more details. > #### Beneficiary details in the EU > > To prevent payment delays when expecting EUR payments, make sure your customers enter a beneficiary name that exactly matches your business name registered on Stripe when sending transfers. Any discrepancies might trigger additional screening by our banking partner, potentially delaying fund receipt. ## Sender information You can determine the sender details of an incoming bank transfer through either the Dashboard or the API. Those details can include the name of the sender, the reference, and the network through which the transfer arrived. #### Dashboard 1. In the [Dashboard](https://dashboard.stripe.com/customers), go to the customer’s page. 1. Under **Payment Methods**, expand the cash balance tab. 1. Open the Cash Balance page by clicking **View balance details**. On the cash balance page, the **Transactions** section displays a list of the customer’s incoming and outgoing cash balance transactions. Incoming transfers have type **Funding**. Find the transfer you’re interested in and open its details page by clicking its description. #### API Access a customer’s cash balance transactions using the [Cash Balance Transactions API](https://docs.stripe.com/api/cash_balance_transactions.md). ```curl curl https://api.stripe.com/v1/customers/cus_xxxxxxx/cash_balance_transactions/ccsbtxn_xxxx \ -u "<>:" ``` ```cli stripe customer_cash_balance_transactions retrieve cus_xxxxxxx ccsbtxn_xxxx ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer_cash_balance_transaction = client.v1.customers.cash_balance_transactions.retrieve( 'cus_xxxxxxx', 'ccsbtxn_xxxx', ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer_cash_balance_transaction = client \ .v1 \ .customers \ .cash_balance_transactions \ .retrieve( "cus_xxxxxxx", "ccsbtxn_xxxx", ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $customerCashBalanceTransaction = $stripe->customers->retrieveCashBalanceTransaction( 'cus_xxxxxxx', 'ccsbtxn_xxxx', [] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CustomerCashBalanceTransactionRetrieveParams params = CustomerCashBalanceTransactionRetrieveParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. CustomerCashBalanceTransaction customerCashBalanceTransaction = client.v1().customers().cashBalanceTransactions().retrieve( "cus_xxxxxxx", "ccsbtxn_xxxx", params ); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const customerCashBalanceTransaction = await stripe .customers .retrieveCashBalanceTransaction('cus_xxxxxxx', 'ccsbtxn_xxxx'); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerCashBalanceTransactionRetrieveParams{ Customer: stripe.String("cus_xxxxxxx"), } result, err := sc.V1CustomerCashBalanceTransactions.Retrieve( context.TODO(), "ccsbtxn_xxxx", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.Customers.CashBalanceTransactions; CustomerCashBalanceTransaction customerCashBalanceTransaction = service.Get( "cus_xxxxxxx", "ccsbtxn_xxxx"); ``` An incoming transfer transaction’s [type attribute](https://docs.stripe.com/api/cash_balance_transactions/object.md#customer_cash_balance_transaction_object-type) has the value `funded`, and its [funded attribute](https://docs.stripe.com/api/cash_balance_transactions/object.md#customer_cash_balance_transaction_object-funded) contains details about the sender. ### Example response for an incoming transfer transaction #### US ```json { "id": "ccsbtxn_1Nkr8vGH59QTMK2f9CIA34L5", "object": "customer_cash_balance_transaction", "created": 1693412481, "currency": "usd", "customer": "cus_OVD6ezUsYGBILH", "ending_balance": 10000, "funded": { "bank_transfer": { "reference": "REF-4242", "type": "us_bank_transfer", "us_bank_transfer": { "network": "ach", "sender_name": "John Doe" } } }, "livemode": false, "net_amount": 12300, "type": "funded" } ``` If the `network` attribute is `ach`, the incoming transfer was completed through an ACH transfer. Likewise, if the `network` attribute is `domestic_wire_us`, the incoming transfer was completed through a domestic wire. #### GB ```json { "id": "ccsbtxn_1Nkr8vGH59QTMK2f9CIA34L5", "object": "customer_cash_balance_transaction", "created": 1693412481, "currency": "gbp", "customer": "cus_OVD6ezUsYGBILH", "ending_balance": 10000, "funded": { "bank_transfer": { "gb_bank_transfer": { "account_number_last4": "1113", "sender_name": "John Doe", "sort_code": "108800" }, "reference": "REF-4242", "type": "gb_bank_transfer" } }, "livemode": false, "net_amount": 12300, "type": "funded" } ``` #### EU ```json { "id": "ccsbtxn_1Nkr8vGH59QTMK2f9CIA34L5", "object": "customer_cash_balance_transaction", "created": 1693412481, "currency": "eur", "customer": "cus_OVD6ezUsYGBILH", "ending_balance": 10000, "funded": { "bank_transfer": { "eu_bank_transfer": { "bic": "COBADEFFXXX", "iban_last4": "4000", "sender_name": "John Doe", "network": "sepa" }, "reference": "REF-4242", "type": "eu_bank_transfer" } }, "livemode": false, "net_amount": 12300, "type": "funded" } ``` #### JP ```json { "id": "ccsbtxn_1Nkr8vGH59QTMK2f9CIA34L5", "object": "customer_cash_balance_transaction", "created": 1693412481, "currency": "jpy", "customer": "cus_OVD6ezUsYGBILH", "ending_balance": 10000, "funded": { "bank_transfer": { "jp_bank_transfer": { "sender_branch": "京都", "sender_bank": "新生銀行", "sender_name": "John Doe" }, "reference": "REF-4242", "type": "jp_bank_transfer" } }, "livemode": false, "net_amount": 12300, "type": "funded" } ``` #### MX Example of a `funded` ccsbtxn for eu_bank_transfer: ```json { "id": "ccsbtxn_1Nkr8vGH59QTMK2f9CIA34L5", "object": "customer_cash_balance_transaction", "created": 1693412481, "currency": "mxn", "customer": "cus_OVD6ezUsYGBILH", "ending_balance": 10000, "funded": { "bank_transfer": { "mx_bank_transfer": { "clabe_last4": "4567", "sender_bank": "Citi", "sender_name": "JOHN DOE" }, "reference": "REF-4242", "type": "mx_bank_transfer" } }, "livemode": false, "net_amount": 12300, "type": "funded" } ``` ## Disputes Bank transfer payments can’t be reversed except for USD and CAD transactions. ### USD disputes USD bank transfers that go through the ACH network in the US can be reversed. After you push a transfer, you can request that your bank reverse it. You must provide the bank with evidence as to why they should reverse the transfer. The remitting bank then sends a reversal to the beneficiary bank. A reversal must be sent no later than 5 days after the payment. ### CAD disputes CAD bank transfers that go through ACH reversals are always initiated by the remitting bank, and the beneficiary bank must honor them. ## Connect [Stripe Connect](https://docs.stripe.com/connect/how-connect-works.md) can be used with bank transfers to process payments on behalf of connected accounts. *Connect* (Connect is Stripe's solution for multi-party businesses, such as marketplace or software platforms, to route payments between sellers, customers, and other recipients) platforms can use bank transfers with [any type of charges](https://docs.stripe.com/connect/charges.md#types). The [on_behalf_of attribute](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-on_behalf_of) isn’t supported. ### Accepting bank transfer payments as the connected account [Direct charges](https://docs.stripe.com/connect/direct-charges.md) require the connected account itself (not the platform) to have activated the bank transfers payment method—Connect platforms can use the [relevant bank transfers capability](https://docs.stripe.com/connect/account-capabilities.md#payment-methods) to determine whether this is the case for a connected account. [Standard Connect accounts](https://docs.stripe.com/connect/standard-accounts.md) can request the relevant capability from their Stripe Dashboard. ### Activation process The process varies by country, but in general for bank transfer payments, the [required information](https://docs.stripe.com/connect/required-verification-information.md) is the same as what’s necessary to activate a Stripe account for payments. If the account doesn’t fulfill all the required information, the capability remains `inactive` with any issues highlighted on the [capability object](https://docs.stripe.com/api/capabilities/object.md) in the `requirements.currently_due` and `requirements.disabled_reason` fields until these issues have been addressed. After all the highlighted issues are resolved, the capability’s `status` changes to `active`, unless there are issues activating the account in general, in which case Stripe sends the Connect platform owner an email. ## Product support | Payment method | [Connect](https://docs.stripe.com/connect.md) | [Checkout](https://docs.stripe.com/payments/checkout.md) | [Payment Links](https://docs.stripe.com/payment-links.md) | [Payment Element](https://docs.stripe.com/payments/payment-element.md) | [Express Checkout Element](https://docs.stripe.com/elements/express-checkout-element.md) | [Mobile Payment Element](https://docs.stripe.com/payments/mobile.md) | [Subscriptions](https://docs.stripe.com/subscriptions.md) | [Invoicing](https://docs.stripe.com/invoicing.md) | [Customer Portal](https://docs.stripe.com/customer-management.md) | | -------------- | --------------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------- | | Bank transfers | ✓ Supported | ✓ Supported 1,2 | - Unsupported | ✓ Supported | - Unsupported | - Unsupported | ✓ Supported | ✓ Supported | - Unsupported | 1 Not supported when using Checkout in subscription mode.2 Not supported when using Checkout in setup mode. ## API support | Payment method | API enum | [PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) | [SetupIntents](https://docs.stripe.com/payments/setup-intents.md) | [Manual capture](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md) | [Setup future usage](https://docs.stripe.com/payments/save-during-payment.md?platform=web&ui=elements)1 | Requires redirect2 | | -------------- | ------------------ | --------------------------------------------------------------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------ | | Bank transfers | `customer_balance` | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | No | 1 Cards and bank debit methods including SEPA debit, AU BECS direct debit, and ACSS debit support both `on_session` and `off_session` with [setup future usage](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-setup_future_usage). All other payment method types either don’t support `setup_future_usage` or only support `off_session`.2 Payment methods might require confirmation with [return_url](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-return_url) to indicate where Stripe should redirect your customer after they complete the payment. ## Unsupported businesses Stripe can’t accept payments for certain types of businesses. In addition to the [Restricted Business list](https://stripe.com/restricted-businesses), Stripe doesn’t support bank transfers if your business falls into any of the following categories: #### EU #### UK ## Unsupported products and features Bank transfers don’t support Payment Links. --- # Source: https://docs.stripe.com/dashboard/basics.md # Web Dashboard Learn how to use the web version of the Stripe Dashboard. The [Stripe Dashboard](https://dashboard.stripe.com/) is the user interface where you manage and configure your account. You can use the Dashboard to navigate account resources, [search transactions](https://docs.stripe.com/dashboard/search.md), invite team members, monitor your integration, and more. On your keyboard, press the question mark key (`?`) for a list of available keyboard shortcuts for common actions. The Dashboard officially supports the following web browsers: - The last 20 major versions of Chrome, Firefox, and Edge. - The last 4 major versions of Safari. If you don’t have access to the Dashboard, [activate your account](https://docs.stripe.com/get-started/account/activate.md). ## Primary navigation In the Dashboard, the first section of the sidebar is where you can access and act on information related to your balances, transactions, customers, and products. ### Home The [Home](https://dashboard.stripe.com/dashboard) page provides analytics and charts about your business performance. It also surfaces important notifications, like unresolved disputes or identity verifications. To customize this page: 1. Click **Add** under **Your overview**. 1. Add or remove widgets by selecting or unselecting them. 1. Click **Apply** to save your changes. You can also click **Edit** to remove widgets. ### Balances Use [Balances](https://dashboard.stripe.com/balances) to see your Stripe balance, including top-ups, payouts, and transaction history. ### Transactions Use [Transactions](https://dashboard.stripe.com/payments) to view all your customer payments, including collected fees and transfers, and their status. You can filter your transactions or export them if you want to use the data outside of Stripe. If you use [Organizations](https://docs.stripe.com/get-started/account/orgs.md), you can see a detailed list of payments across all of your accounts. You can also filter the list down by account. ### Customers Use [Customers](https://dashboard.stripe.com/customers) to create and manage customer profiles. You can see information about your existing customers, including their accounting details, using filters to locate specific customers. Click a customer’s name to see more details, including subscriptions, payments, payment methods, invoices, and quotes. To learn more, see [Create customers](https://docs.stripe.com/invoicing/customer.md). If you use [Organizations](https://docs.stripe.com/get-started/account/orgs.md), you can view a list of your shared and unshared customers across all your accounts. You can filter this list by email address, card status, creation date, account type, and delinquency status. When you click into a customer, there’s also a link to the customer’s details page within the account they belong to. > You can only create, export or analyze customers from the **Customers** page at the account level. ### Product catalog The [Product catalog](https://dashboard.stripe.com/products) lets you create and manage products and prices for your business. Click your product to see more details. To learn more, see [Manage products and prices](https://docs.stripe.com/products-prices/manage-prices.md). ## Shortcuts Use the **Shortcuts** section to display your pinned and most recently visited pages. After you visit a page, it apperas under this section, where you can pin it. ## Products Use the **Products** section to complete tasks, and view important product information. ### Connect If your business is a platform or marketplace, and you have [connected accounts](https://dashboard.stripe.com/connect), the Stripe Dashboard allows you to also manage and support them. To learn more, see [Managing connected accounts](https://docs.stripe.com/connect/dashboard.md). ### Payments Payments contains insights and tools for improving your payments performance, including card authorization rates, fraud prevention, and dispute management. Here, you can review insights and opportunities for improving your card authorization rates, address any disputes, and manage fraudulent payments with [Radar](https://dashboard.stripe.com/radar). [Payment links](https://dashboard.stripe.com/payment-links) let you accept payments or sell subscriptions without building an additional standalone website or application. To learn more, see [Payment Links](https://docs.stripe.com/payment-links.md). [Terminal readers](https://dashboard.stripe.com/setup/terminal/activate) are a selection of pre-certified readers that accept EMV, contactless, and swiped payments, encrypt sensitive card information, and return a token to your application for payment confirmation. To learn more, see [Terminal](https://docs.stripe.com/terminal.md). ### Billing [Billing](https://dashboard.stripe.com/billing) lets you manage and configure your billing and subscription-related information, such as creating, customizing, and sending invoices to customers, and managing subscriptions, applying discounts, and generating revenue reports. To learn more, see [Billing](https://docs.stripe.com/billing.md). ### Reporting [Reporting](https://dashboard.stripe.com/reports/hub) allows you to export historical transactions, payments, and payouts information from the Dashboard. You can customize the reports by filtering and adding custom columns, and access financial reports for an accounting-grade view. To learn more, see [Reports](https://docs.stripe.com/stripe-reports.md). In addition to the general financial reporting available in the Dashboard, Billing, Tax, and Radar offer product-specific analytics for additional performance insights. If you need more customized reporting, [Sigma](https://dashboard.stripe.com/sigma/queries) lets you access and analyze your data within an interactive SQL environment. While [Data management](https://dashboard.stripe.com/data-management), lets you import external data into Stripe. Learn more at [Stripe data](https://docs.stripe.com/stripe-data.md). To automate your accrual accounting process, use [Revenue Recognition](https://dashboard.stripe.com/revenue-recognition). To learn more, see [Revenue Recognition](https://docs.stripe.com/revenue-recognition.md). ### Other Stripe products To see additional Stripe products in the Dashboard, click **More**: - [Workflows](https://dashboard.stripe.com/workflows): Automate tasks and create custom flows, without writing code. Workflows help you automate multi-step tasks and can span across multiple Stripe products. To learn more, see [Stripe Workflows](https://docs.stripe.com/workflows.md). - [Tax](https://dashboard.stripe.com/tax/thresholds): Automate sales tax, VAT, and GST compliance on all your transactions. To learn more see, [Stripe Tax](https://docs.stripe.com/tax.md). - [Connect](https://dashboard.stripe.com/connect) (if disabled): For platforms or marketplaces who want to route payments between multiple parties. To learn more, see [Connect](https://docs.stripe.com/connect.md). - [Identity](https://dashboard.stripe.com/identity): Confirm the identity of global users to prevent fraud and streamline risk operations. To learn more, see [Identity](https://docs.stripe.com/identity.md). - [Atlas](https://dashboard.stripe.com/setup/atlas/activate): Start a US company from anywhere in the world. To learn more, see [Atlas](https://docs.stripe.com/atlas.md). - [Issuing](https://dashboard.stripe.com/issuing/overview): Create, manage, and distribute payment cards for your business. To learn more, see [Issuing](https://docs.stripe.com/issuing.md). - [Financial connections](https://dashboard.stripe.com/settings/financial-connections): Allow users to securely share their financial data with your business. To learn more, see [Financial Connections](https://docs.stripe.com/financial-connections.md) to learn more. - [Capital](https://dashboard.stripe.com/capital): Financing offers for eligible businesses processing payments through Stripe. To learn more, see [Capital](https://docs.stripe.com/capital/how-stripe-capital-works.md). - [Climate](https://dashboard.stripe.com/climate): Remove carbon as you grow your business. To learn more, see [Climate](https://docs.stripe.com/climate.md). ## Dashboard settings The Dashboard’s settings are broken into three categories: Personal, Account, and Product. ### Account settings You can manage your [business settings](https://dashboard.stripe.com/settings) directly from the Dashboard. Business settings include: - [Account details](https://dashboard.stripe.com/settings/account), account health, public information, payouts, legal entity, custom domains, and so on. - [Personal details](https://dashboard.stripe.com/settings/user) settings, password, communication preferences, and your active sessions. - [PCI compliance details](https://dashboard.stripe.com/settings/compliance) and Stripe’s Attestation of Compliance. - [Viewing and uploading documents](https://dashboard.stripe.com/settings/documents), legacy exports, and PCI compliance. - [Get early access](https://dashboard.stripe.com/settings/early_access) to new beta features. Under **Team and security**, you can [invite team members](https://dashboard.stripe.com/settings/team?invite_shown=true) to access the Dashboard, and help manage your business. Each of them can have different levels of access. For example, you can let members of your customer service team access your Dashboard for the purpose of handling [refunds](https://docs.stripe.com/refunds.md) and [disputes](https://docs.stripe.com/disputes/responding.md). To learn more about team roles, see [User roles](https://docs.stripe.com/get-started/account/teams/roles.md). You can customize your customer’s payment forms, emails, invoices, and quotes with the public details you set for your business. You can also upload your logo or icon and aelect colors in your [Branding](https://dashboard.stripe.com/settings/branding) settings. Learn more about [branding your Stripe configuration](https://docs.stripe.com/get-started/account/branding.md). If you’re using Stripe Checkout, you can also [customize your policies and contact information](https://dashboard.stripe.com/settings/checkout) to display to your customers. ### Product settings Manage the settings for individual Stripe products directly from the Dashboard. Product settings include: - [Billing](https://dashboard.stripe.com/settings/billing/automatic): Manage subscriptions, invoices, quotes, and customer portal. - [Financial connections](https://dashboard.stripe.com/settings/financial-connections): Manage appearance, featured institutions, optimizations and usage details. - [Radar](https://dashboard.stripe.com/settings/radar): Manage fraud protection and customization capabilities for your account. - [Card issuing](https://dashboard.stripe.com/settings/issuing/authorizations): Manage authorizations, balance notifications, card branding, and digital wallets. - [Identity verification](https://dashboard.stripe.com/settings/identity): Use synthetic identity protection and the native mobile SDK. - [Sigma custom reports](https://dashboard.stripe.com/settings/sigma): Manage your Sigma subscription. - [Connect](https://dashboard.stripe.com/settings/connect): Manage your platform and connected accounts. - [Payments](https://dashboard.stripe.com/settings/checkout): Manage user checkout, payment methods, currency conversion, and so on. - [Tax](https://dashboard.stripe.com/settings/tax): Manage head office address, preset tax code, default tax behavior, and tax integrations. - [Data pipeline](https://dashboard.stripe.com/settings/stripe-data-pipeline): Manage an external data warehouse. ## Monitor and test your integration [Workbench](https://dashboard.stripe.com/workbench) gives you information about the performance and health of your integration. You can view your API and *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) usage, upgrade your API version, and review API errors that can be filtered by endpoint or type. To access Workbench, enable it under **Beta features** in the [Dashboard](https://dashboard.stripe.com/settings/early_access). To learn more, see [Workbench](https://docs.stripe.com/workbench.md). Workbench also [logs](https://dashboard.stripe.com/workbench/logs) every successful or failed request made using your API keys. Each log contains details about the original request, whether it succeeded or failed, the response from Stripe, and a reference to any related API resources. To test your integration, use [Sandboxes](https://docs.stripe.com/sandboxes.md) to simulate and test your integrations without impacting live transactions or affecting real data. ## Mobile Dashboard app Like the web version of the Dashboard, you can use our [mobile app](https://docs.stripe.com/dashboard/mobile.md) to monitor your business metrics, create and manage payments, track and initiate payouts, get push notifications on business activity, and so on. The app is available on iOS and Android in 14 languages. To download the mobile app, go to: - [iOS on App Store](https://apps.apple.com/app/apple-store/id978516833?pt=91215812&ct=stripe-docs-dashboard-basics&mt=8) - [Android on Google Play](https://play.google.com/store/apps/details?id=com.stripe.android.dashboard&pli=1) The mobile app lets you create and accept payments [in-person](https://docs.stripe.com/no-code/get-started.md#in-person) or online. It only supports the following products: | Payment capability | iOS | Android | | ---------------------------------------------------------------------------------------------- | --- | -------------- | | [Tap to pay](https://docs.stripe.com/no-code/in-person.md) | ✓ | ✓ | | [Manual card entry](https://support.stripe.com/questions/b7bd8ea6-d20c-40f8-a273-4d6c4902957a) | ✓ | ✓ | | [Invoices](https://docs.stripe.com/no-code/invoices.md) | ✓ | ✓ | | [Payment Links](https://docs.stripe.com/no-code/payment-links.md) (including QR codes) | ✓ | :cancelCircle: | | [Subscriptions](https://docs.stripe.com/no-code/subscriptions.md) | ✓ | :cancelCircle: | ## Stripe organizations If you have multiple Stripe accounts for regulatory or financial requirements you can centralize reporting, operations, and team management across your enterprise by setting up [Stripe Organizations](https://docs.stripe.com/get-started/account/orgs.md) within the Stripe Dashboard. ## See also - [Activate your account](https://docs.stripe.com/get-started/account/activate.md) - [Start a team](https://docs.stripe.com/get-started/account/teams.md) - [Perform searches](https://docs.stripe.com/dashboard/search.md) --- # Source: https://docs.stripe.com/terminal/readers/bbpos-wisepad3.md # Source: https://docs.stripe.com/terminal/payments/setup-reader/bbpos-wisepad3.md # Set up BBPOS WisePad 3 Learn how to set up the BBPOS WisePad 3. Available in: CA, GB, IE, SG, AU, NZ, FR, DE, NL, BE, AT, ES, DK, SE, NO, CH, IT, LU, PT, FI, MY, CZ, PL, JP![](https://b.stripecdn.com/docs-statics-srv/assets/wisepad-floating-thumb.d6e3015116e0b4295b0106e770b9843e.png) The BBPOS WisePad 3 is a handheld reader for use with mobile applications. It uses Bluetooth Low Energy (BLE) or USB (Android only) to [connect](https://docs.stripe.com/terminal/payments/connect-reader.md?reader-type=bluetooth) to the Stripe Terminal SDK on a mobile device. The WisePad 3 features a display and PIN pad, which facilitates use in countries where PIN-authenticated transactions are more common. This reader is compatible with our iOS, Android, and React Native SDKs. To view the reader’s parts and features, see the [BBPOS WisePad 3 product sheet](https://docs.stripecdn.com/d90c245525d03b60db93a9d861197e1c14c7adf0e53c864e62220290a7db8d14.pdf). > Stripe readers aren’t liquid-proof and we recommend that users make appropriate efforts to make sure their devices remain dry. If your device has experienced liquid ingress, we recommend that you stop using the device and let it dry thoroughly before attempting to re-use or charge the device. If your device doesn’t properly operate or charge properly after drying, you need to replace it. ## Turn the reader on and off You can turn on the BBPOS WisePad 3 reader by pressing and holding the power button, located at the top right of the PIN pad. The display powers on and shows the device’s splash screen. The display dims after a few seconds of inactivity. If inactive and disconnected from your application for more than 5 minutes, it beeps and powers off. Turn off the reader manually by pressing and holding the power button until the LED display shows a “Power off?” prompt, then press the green enter button to confirm. > With typical usage, you generally need to [charge the reader](https://docs.stripe.com/terminal/payments/setup-reader/bbpos-wisepad3.md#charging) once per day. The reader can typically accept approximately 600 contact or 800 contactless transactions in a single charge cycle. ## Charge the reader To charge the BBPOS WisePad 3, use the included cable or a USB-A to USB-C cable. ## Default reader language The [BBPOS WisePad 3](https://docs.stripe.com/terminal/readers/bbpos-wisepad3.md) supports changing reader language directly in the reader interface. After you have registered your reader to a [Location](https://docs.stripe.com/api/terminal/locations.md), the reader installs a language pack relevant for your region if one isn’t already in place. To view available language options and to select a language, click the **Power / Settings** button and scroll down using the arrow keys until you reach the language selection menu. Highlight your desired language and press the green **Enter** key. ## Accessories for the reader You can design your own accessories for the BBPOS WisePad 3. To download the BBPOS WisePad 3 mechanical design files (.STP), you must first review and accept our [Terminal Design File License Agreement](https://stripe.com/legal/terminal-design). By downloading the file below, you agree to the terms outlined in the license. [Download Stripe design files](https://d37ugbyn3rpeym.cloudfront.net/terminal/bbpos_wp3_mechanical_design_files_and_guidelines.zip) ## See also - [Set up your integration](https://docs.stripe.com/terminal/payments/setup-integration.md) - [WisePad 3 reference](https://docs.stripe.com/terminal/readers/bbpos-wisepad3.md) The BBPOS and Chipper™ name and logo are trademarks or registered trademarks of BBPOS Limited in the United States or other countries. The Verifone® name and logo are either trademarks or registered trademarks of Verifone in the United States and/or other countries. Use of the trademarks doesn’t imply any endorsement by BBPOS or Verifone. --- # Source: https://docs.stripe.com/terminal/readers/bbpos-wisepos-e.md # BBPOS WisePOS E Learn about the BBPOS WisePOS E reader. Available in: US, CA, GB, IE, SG, AU, NZ, NL, BE, AT, ES, DK, SE, NO, CH, IT, LU, PT, FI, MY, CZ, PL![](https://b.stripecdn.com/docs-statics-srv/assets/wisepos-floating-tall.e8478124cda0e088b2e19f503f574f53.png) The [BBPOS WisePOS E](https://docs.stripe.com/terminal/payments/setup-reader/bbpos-wisepos-e.md) is a countertop reader for Stripe Terminal apps. It [connects](https://docs.stripe.com/terminal/payments/connect-reader.md?reader-type=internet) to the Stripe Terminal SDK over the internet. This reader is compatible with the following integrations: JavaScript, iOS, Android, and React Native SDKs and server-driven. For BBPOS WisePOS E readers, we recommend the [server-driven integration](https://docs.stripe.com/terminal/payments/setup-integration.md?terminal-sdk-platform=server-driven), which uses the Stripe API instead of a Terminal SDK. To view the reader’s parts and features, see the [BBPOS WisePOS E product sheet](https://d37ugbyn3rpeym.cloudfront.net/terminal/product-sheets/wpe_product_sheet.pdf). ## LED status lights The LEDs above the LCD display show the current status. ### LED icon meanings Use this table to understand what the icons in the subsequent tables indicate. | Icon | Meaning | | ---- | ---------------------- | | | The light is on. | | | The light is flashing. | | | The light is off. | ### Power on When you press and hold the power button for 2 seconds, the device powers on and the right LED array flashes. | LEDs | Meaning | | ---- | --------------------- | | | The device turned on. | ### Battery and charging status When the BBPOS WisePOS E is on, you can check the battery level in the left LED array. Learn more about [BBPOS WisePOS E battery life](https://docs.stripe.com/terminal/payments/setup-reader.md#device-specs-and-accessories). | LEDs | Meaning | | ---- | ----------------------- | | | Charging or full charge | If the first LED is red, there might be an issue with charging. ### Contactless and reader status When you connect to the BBPOS WisePOS E, you can check the reader status in the right LED array. | LEDs | Meaning | | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | | Reader is in bootloader mode and has reverted to default keys. | | | Reader integrity check failed or reader tampered. If this occurs, and your reader is under warranty, [contact support](https://support.stripe.com/contact/) from the Stripe account that ordered your reader and include the serial number of the device to arrange a replacement reader. | | | (2 seconds) Reader is experiencing a hard fault and might need replacing. [Contact support](https://support.stripe.com/contact/). | ## Expected sounds during payment The following table describes sounds that occur during successful and failed payments on the BBPOS WisePOS E. | | Tap | Chip | Swipe | | ------- | ------------------------- | -------- | -------- | | Success | 1 long, high-pitched beep | No sound | No sound | | Failure | 1 long, high-pitched beep | No sound | No sound | ## Troubleshoot the reader Make sure your network meets all of our [network requirements](https://docs.stripe.com/terminal/network-requirements.md), and try the steps in the [network troubleshooting](https://docs.stripe.com/terminal/network-requirements.md#troubleshooting) section. To begin troubleshooting, use the following common scenarios to help diagnose the issue. ### Run diagnostics The BBPOS WisePOS E includes built-in diagnostics that can help you identify connectivity and configuration issues. We recommend running these diagnostics as the first step when troubleshooting any reader problems. To access the diagnostics menu: 1. Swipe in from the left edge of the screen on your reader. 1. Tap **Settings**. 1. Enter the admin passcode. The default is **0-7-1-3-9**. 1. Select **Diagnostics**. The diagnostics menu displays test results and information about your reader: - **DNS resolution**: Verifies that the reader can resolve domain names. - **Stripe connectivity**: Verifies that the reader can connect to Stripe servers. This test must pass for your reader to process payments and receive updates. - **Terminal events connectivity**: Tests the reader’s connection to the Stripe event infrastructure. - **WiFi information**: Shows WiFi frequency and signal strength (if connected using WiFi). - **Battery and hardware status**: Displays battery health, voltage, capacity, and dock/hub connection status. > If the Stripe connectivity test fails, your reader won’t be able to process payments or receive software updates. Follow the [network troubleshooting steps](https://docs.stripe.com/terminal/network-requirements.md#troubleshooting) to resolve connectivity issues. We recommend running diagnostics whenever you experience issues with your reader, or as part of your regular maintenance routine to proactively identify potential problems. ### Reader is unable to connect To check connectivity, go to [settings](https://docs.stripe.com/terminal/payments/setup-reader/bbpos-wisepos-e.md#settings), then select **WiFi settings**. This displays all available WiFi networks. To see more details about the connection, tap the connected network name. If you’re experiencing connectivity issues, run the [diagnostics tests](https://docs.stripe.com/terminal/readers/bbpos-wisepos-e.md#diagnostics) to check Stripe connectivity and identify the root cause. ### Reader is unable to connect to Ethernet, even though docked You must connect both cables before inserting the reader into the dock. Remove the reader and re-insert into the dock. If the issue persists, run the [diagnostics tests](https://docs.stripe.com/terminal/readers/bbpos-wisepos-e.md#diagnostics) to verify network and Stripe connectivity. ### Reader is unable to update If your reader doesn’t update, it’s possible that it can’t connect to Stripe. Run the [diagnostics tests](https://docs.stripe.com/terminal/readers/bbpos-wisepos-e.md#diagnostics) to check Stripe connectivity. Make sure the Stripe connectivity test says “Passed.” If the test fails, follow [these steps](https://docs.stripe.com/terminal/network-requirements.md#troubleshooting). > If you use a router, refer to your router’s manual and reconfigure the networking setup. ## Stripe reader software Stripe maintains the software that controls the BBPOS WisePOS E. The reader receives updates automatically from Stripe when not in use. These can include improvements and required security updates from Stripe and our hardware partners. As reader software updates are made available, update your readers to the latest available version to continue using Stripe Terminal. Failing to install a required update can prevent a reader from accepting payments. The reader restarts every day at midnight for PCI compliance, and disconnects from the POS app every morning. Leave your reader on and connected to power to receive automatic software updates. This ensures that updates happen at midnight (in the timezone of the [assigned location](https://docs.stripe.com/terminal/fleet/locations-and-zones.md)) to avoid interruption to sales. If you unplug the reader at night, an update could start when you turn it back on. To manually check for an update, reboot the reader. ### Reader software version The BBPOS WisePOS E software consists of four components: the reader application, firmware, configuration, and key identifier. The following table summarizes the latest version of each of these components for the countries where WisePOS E is available. You can find your reader’s versions in the [Diagnostics menu](https://docs.stripe.com/terminal/readers/bbpos-wisepos-e.md#diagnostics). > In PCI listings, the firmware identifier is in the format `WSC5x.11-xxxxx-xxxxx`, where `xxxxx` is a placeholder for ROM version and firmware version, respectively. All versions are PCI compliant. > > Specifically, a PCI firmware ID `WSC5x.11-WXYZZ-ABCDD` maps to ROM version `W.X.Y.ZZ` and reader version `AA.BB.CC.DD`. For example, `WSC5x.11-18302-50127` maps to ROM version `1.8.3.2` and firmware version `5.00.01.27`. If the ROM version only has three digits `W.X.Y`, `ZZ` is `00`. | Countries | Reader | Firmware | Configuration | ROM | | ---------------------------- | ---------- | ------------------- | ----------------------- | ------- | | US | `2.38.2.0` | `5.00.01.43` | `szzz_us_v19` | `1.8.4` | | CA | `2.38.2.0` | `5.00.01.43` | `szzz_ca_v17` | `1.8.4` | | AU | `2.38.2.0` | `5.00.01.43.eftpos` | `szzz_prod_au_v11` | `1.8.4` | | MYNZ | `2.38.2.0` | `5.00.01.43` | `szzz_prod_apac_on_v4` | `1.8.4` | | SG | `2.38.2.0` | `5.00.01.43` | `szzz_prod_apac_off_v4` | `1.8.4` | | GBIEFI | `2.38.2.0` | `5.00.01.43` | `szzz_prod_eu_off_v11` | `1.8.4` | | ATBEDKFRITDENLESSECZLUPTCHNO | `2.38.2.0` | `5.00.01.43` | `szzz_prod_eu_on_v7` | `1.8.4` | ### Reader software changelog #### 2026-01-13 (version 2.38.2.0) - General bug fixes and improvements. - Added a fix to always play payment audio tones at correct volume regardless of device volume. #### 2025-11-12 (version 2.37.2.0) - General bug fixes and improvements. #### 2025-10-07 (version 2.36.2.0) - General bug fixes and improvements. #### 2025-09-10 (version 2.35.2.0) - Renamed “PIN” to “passcode" on the admin menu access screen. - General bug fixes and improvements. #### 2025-08-06 (version 2.34.4.0) - Updated the S700 UI to state “Select payment method” instead of “Select Account” on the CB co-branded choice selection screen. - General bug fixes and improvements. #### 2025-06-30 (version 2.33.3.0) - Fixed a bug that impacted the flow for decline and autorecollection. - Added a message on the postpone update page to notify users when a device software update becomes mandatory. - Added support for cobranded card choice (girocard, CB) on S700 devices. - General bug fixes and improvements. #### 2025-05-28 (version 2.32.1.0) - General bug fixes and improvements. #### 2025-04-29 (version 2.31.6.0) - Updated the UI for ROM installation status to show the progress percentage during installation. - Added UI improvements for QR code payments with WeChat Pay and Affirm. - Added various UI updates for Cartes Bancaires support on S700. - General bug fixes and improvements. #### 2025-03-26 (version 2.30.5.0) - Fixed a factory reset bug for newly unboxed S700 devices. - Fixed a bug for an edge case scenario where ROM updates might time out. - Updated Interac prompts for French cardholders to “Cheque” instead of “Compte courant” and “Entrez votre NIP” instead of “Saisir le code PIN.” - Fixed the UI to display the correct language on payment prompts for Dutch and French cardholders. #### 2025-03-12 (version 2.29.6.0) - Updated the reader to return a success (instead of an error) when an on-reader form operation is initiated while the reader displays “Remove card.” - Fixed a bug to ensure offline mode correctly handles SDI requests. - Added a “Try again” button on the reader UI when the “Failed to launch reader” error displays. - Added sounds to indicate correct and incorrect PIN entry. - Fixed a bug that might cause some offline mode transactions to fail. - Added connection improvements for server-driven integrations operating in poor network connectivity environments. - Additional bug fixes and improvements. #### 2025-01-29 (version 2.28.3.0) - Improved device IoT connectivity when in Doze mode. This change removes the need to manually keep the screen active before initiating a transaction. - Added log entries for when a device enters into and exits out of Doze mode. - Added the ability to insert a card before the transaction is initiated. This requires version 2.28 and enabling a Stripe-controlled feature flag. - Fixed the cancel buttons on `charge_error` screens. - Fixed an issue that prevented canceling the reader action using SDI when collecting and confirming SCA transactions. - Fixed race conditions for on-reader forms. - Fixed collect input validations for on-reader forms. - Fixed a hand-off mode bug that prevented hand-off mode transactions from returning to the POS screen after completing. #### 2024-11-13 (version 2.27.7.0) - Fixed a bug where handoff mode transactions weren’t reliably returning to the POS app. - Fixed a UI bug where the cancel button wasn’t displaying. - Fixed a bug that impacted certain uses of on-reader forms. - Fixed a UI bug that affected Finnish language display on the admin pin screen. #### 2024-09-18 (version 2.26.5.0) - Fix for errors that prevented Apps on Devices users from accepting successful payments. - Fix for an issue that prevented bug reports from uploading. - Fix for a UI bug that impacted collect inputs. #### 2024-08-26 (version 2.25.3.0) - Bug fixes and stability improvements. #### 2024-07-30 (version 2.25.1.0) - Fixed a bug where Stripe test card timeouts reported as a user cancellation when selecting “Stripe PIN credit” option. - Added support for Accessible PIN payments. - Fixed a race condition bug that caused contactless payments to fail with the error “Underlying request took too long. Please check your local network.” - Fixed a bug where a Norwegian card showed Swedish text. - Fixed a bug where accessibility mode did not read out the “Incorrect PIN entered” message. #### 2024-06-25 (version 2.24.2.0) - UI fixes for the Reader app. - Fixed an issue where auto-rotate wasn’t working correctly for Stripe S700. #### 2024-05-30 (version 2.23.3.0) - Bug fixes and stability improvements. - Updated the custom tip entry screen to include enter and cancel buttons. #### 2024-04-18 (version 2.22.3.0) - Fixed an installation error for language packs. - Updated the 50% battery requirement when performing a configuration or key update on the battery. - Fixed an issue where readers attempted to use a 2nd Gen AC on contactless EMV. - Added support for connecting to a hidden Enterprise WPA or WPA2-EAP network. - Added a progress indicator for key, firmware, and configuration updates. #### 2024-03-18 (version 2.21.2.0) - Fixed the text size and made copy changes and UI modifications for AAA accessibility compliance. - Updated `PaymentIntent` support for Magstripe + PIN for EFTPOS. - Fixed bugs related to support for `PaymentIntent` when using offline mode. #### 2024-02-08 (version 2.20.4.0) - Fixed an issue where iOS SDK 2.x versions returned nil for the `CardPresent` object `charges.paymentMethodDetails.cardPresent`. #### 2024-02-08 (version 2.20.3.0) - Bug fixes and stability improvements #### 2023-12-11 (version 2.19.2.0) - Updated SCA support. - Fixed an issue where the network screen running multiple connect calls could cause Armada to become unauthenticated. - Added issuer information in the `PaymentMethod` bindings. - Updated the refund by `PaymentIntent.id`. - Surfaced the language detected from the card in the `PaymentIntent`. #### 2023-11-16 (version 2.18.9.0) - Bug fixes and stability improvements #### 2023-11-08 (version 2.18.5.0) - Bug fixes and stability improvements #### 2023-10-18 (version 2.17.8.0) - Bug fixes and stability improvements #### 2023-09-21 (version 2.16.7.0) - Bug fixes and stability improvements #### 2023-07-12 (version 2.15.5.0) - Fixed an issue where the NFC logo was missing on the cart display. - Fixed an issue where the reader app crashed during firmware updates. - Improved recovery from an issue that caused the reader to stop responding. - You no longer need to check a box when connecting to hidden WiFi networks. - Disabling the payment tone now works as intended on the WisePOS E. #### 2023-06-12 (version 2.14.3.0) - Improved reliability and security of Stripe SDK to reader connectivity. - Fixed an issue where saved networks couldn’t always be forgotten. #### 2023-04-03 (version 2.12.2.3) - Fixed an issue where ROM background downloads were occasionally interrupted. - Fixed an issue where language selection occasionally failed after factory reset. #### 2023-03-14 (version 2.11.4.0) - Improved reliability and security of Stripe SDK to reader connectivity. #### 2023-02-06 (version 2.10.2.0) - Devices now have a one hour screen timeout when the reader isn’t connected to a power source. #### 2023-01-04 (version 2.9.2.0) - Various improvements to animations during the payment flow. - Improved reliability and security of Stripe SDK to reader connectivity. #### 2022-10-17 (version 2.8.4.0) - Improved performance when processing several payments sequentially. #### 2022-09-19 (version 2.7.7.0) - Rolled out support for dark and light themes on the reader update screen. #### 2022-06-13 (version 2.4.2.3) - Rolled out a new default splash screen. - Rolled out access to the **Appearance** setting screen to switch between dark and light themes. #### 2022-04-13 (version 2.2.3.0) - Improved reliability and security of Stripe SDK to reader connectivity. - Improved support for custom splash screens by applying opacity to the status bar. ## Accessories for the reader You can design your own accessories for the BBPOS WisePOS E. To download the BBPOS WisePOS E mechanical design files (.STP), you must first review and accept our [Terminal Design File License Agreement](https://stripe.com/legal/terminal-design). By downloading the file below, you agree to the terms outlined in the license. [Download Stripe design files](https://d37ugbyn3rpeym.cloudfront.net/terminal/bbpos_wpe_mechanical_design_files_and_guidelines.zip) ## See also - [Set up BBPOS WisePOS E](https://docs.stripe.com/terminal/payments/setup-reader/bbpos-wisepos-e.md) - [Set up your integration](https://docs.stripe.com/terminal/payments/setup-integration.md) - [Connect to a reader](https://docs.stripe.com/terminal/payments/connect-reader.md) - [Collect payments](https://docs.stripe.com/terminal/payments/collect-card-payment.md) The BBPOS and Chipper™ name and logo are trademarks or registered trademarks of BBPOS Limited in the United States or other countries. The Verifone® name and logo are either trademarks or registered trademarks of Verifone in the United States and/or other countries. Use of the trademarks doesn’t imply any endorsement by BBPOS or Verifone. --- # Source: https://docs.stripe.com/identity/before-going-live.md # Before going live Best practices to build a production-ready Stripe Identity integration. As you complete each item and check it off, the state of each checkbox is stored within your browser’s cache. You can refer back to this page at any time to see what you have completed so far. ### Before going live - [ ] Make sure your use case and business are supported Review the [supported use cases](https://docs.stripe.com/identity/use-cases.md) and [terms of service](https://stripe.com/identity/legal) to make sure that your business can use Stripe Identity. - [ ] Setup branding The verification experience shows your company name, logo, and color. Make sure to configure the [branding settings](https://dashboard.stripe.com/settings/branding) for your account before going live. - [ ] Understand pricing & billing [Stripe Identity](https://stripe.com/pricing#identity) pricing is usage-based and charges apply for each *completed* verification. Make sure you understand how these charges appear on your invoice and how they interact with other Stripe products. See [Billing for Stripe Identity](https://support.stripe.com/questions/billing-for-stripe-identity) for a detailed breakdown of costs and billing descriptors. - [ ] Limit the number of submission attempts To prevent fraudsters from abusing your verification flow and incurring charges on your account, we recommend that you limit the number of times a user can verify themselves. - [ ] Limit how much sensitive information you store As much as possible, store only references to the verification and use the API to [retrieve the VerificationSession](https://docs.stripe.com/api/identity/verification_sessions/retrieve.md) when you need access to sensitive information. This simplifies your integration and limits your exposure from a security perspective, and helps you comply with privacy laws (such as GDPR) that require you to minimize data retention. - [ ] Always authenticate your user We recommend that you authenticate your user before showing or sending them to Stripe Identity. This allows you to keep relevant internal references and adds a layer of security to prevent fraudsters from abusing your verification flow. - [ ] Handle session link expiration If your integration uses the [web redirect session url](https://docs.stripe.com/identity/verify-identity-documents.md?platform=web&type=modal#create-a-verificationsession) or you [create verification links from the Stripe Dashboard](https://docs.stripe.com/identity/verify-identity-documents.md?platform=no-code&type=dashboard#share-verification-link), you must handle link expiration. The links expire 48 hours after creation and are single-use. You can refresh a link in the API using [retrieve the verification session](https://docs.stripe.com/api/identity/verification_sessions/retrieve.md) or by clicking **Copy link** on the verification session’s detail page in the [Dashboard](https://dashboard.stripe.com/identity/verification-sessions). - [ ] Update your support process with an alternative verification method Stripe Identity might not be able to verify all of your users. For example, your user might decline to be verified using biometric technology, they might attempt to verify with an unsupported document type, or they might not be covered by Identity’s [verification checks](https://docs.stripe.com/identity/verification-checks.md). We recommend that you provide alternative ways to verify your user, and update your support process to handle new questions from users. In some jurisdictions, privacy laws (such as GDPR) might require you to offer a non-biometric verification option for users who decline to consent to using their biometric information. - [ ] Follow webhook best practices If your integration depends on [webhooks](https://docs.stripe.com/webhooks.md), make sure you’ve [tested](https://docs.stripe.com/identity/handle-verification-outcomes.md#test) that your integration handles Identity events correctly and that you’re following the [Best practices for using webhooks](https://docs.stripe.com/webhooks.md#best-practices). - [ ] Follow the Stripe development checklist Follow the [Development checklist](https://docs.stripe.com/get-started/checklist/go-live.md) to ensure a smooth transition when taking your integration live. - [ ] Update your privacy policy if necessary Stripe Identity collects sensitive information, such as facial and identity document images. Make sure that your own privacy policy tells your customers about all the ways you may use or reuse the collected identity data and that this data is shared with Stripe. You could add the following paragraph to your policy if it doesn’t already include information about how their data is disclosed to Stripe: > We use Stripe for identity document verification. Stripe collects identity document images, facial images, ID numbers and addresses as well as advanced fraud signals and information about the devices that connect to its services. Stripe shares this information with us and also uses this information to operate and improve the services it provides, including for fraud detection. You may also choose to allow Stripe to use your data to improve Stripe’s biometric verification technology. You can learn more about Stripe and read its privacy policy at https://stripe.com/privacy. - [ ] Provide a URL to your privacy policy Make sure your [account settings](https://dashboard.stripe.com/settings/account?support_details=true) include a link to your privacy policy. This URL will be linked from Stripe Identity. - [ ] Explain ID verification and Stripe Identity to your customers Add information to your site answering common questions about identity verification and your use of Stripe Identity. See the [FAQ template](https://docs.stripe.com/identity/explaining-identity.md). - [ ] Explain to your users how to delete their data from Stripe's servers When your users request their data to be deleted, [redact the VerificationSession](https://docs.stripe.com/identity/verification-sessions.md#redact) and let your users know that they’ll need to contact Stripe support to remove their data from Stripe’s servers. You could add the following paragraph to your application: > We use Stripe for identity document verification. Stripe retains a copy of all the data provided as part of a verification. You may also have consented to allow Stripe to use your data to improve their technology. You can delete your information from Stripe’s servers or revoke your consent by contacting us using the form at Stripe support: https://support.stripe.com. ## See also - [Is my use case supported?](https://docs.stripe.com/identity/use-cases.md) - [Development checklist](https://docs.stripe.com/get-started/checklist/go-live.md) - [Take webhooks live](https://docs.stripe.com/webhooks.md#register-webhook) --- # Source: https://docs.stripe.com/disputes/prevention/best-practices.md # Best practices for preventing fraud Learn how to use best practices to protect against disputes and fraudulent payments. Creating an effective dispute and fraud prevention strategy that best suits your business can help prevent fraud from occurring. By employing some of these best practices as part of your overall strategy, you can avoid excessive chargebacks and reduce potential customer burden and losses. ## Tools for everyone These are tools that any Stripe user—whether or not they’re a developer, and whether or not they use any specialized Stripe tools like *Radar* (Stripe Radar helps detect and block fraud for any type of business using machine learning that trains on data across millions of global companies. It’s built into Stripe and requires no additional setup to get started)—can leverage to reduce fraud and dispute incidents. ### Be clear and transparent with your customers Clear and frequent contact with your customers can help prevent many of the [reasons](https://docs.stripe.com/disputes/categories.md) for disputes. By responding to issues and processing refunds or replacement orders quickly, your customers are far less likely to take the time to dispute a payment. Make your customer service contact information easy to find, keep customers updated throughout their order process, and provide updates about deliveries. > Include a clear description of your refund and cancellation policies in your terms of service. You can require your users to agree to your terms of service to increase the likelihood that card issuers respect your policies in the event of a dispute. - [ ] Require ToS Agreement In general, make your terms of service and policies easy to find on your website, and require customers to agree to them. Rather than only linking to them during checkout, provide a full version of them on the checkout page or as a pop-up with a requirement to agree to them prior to submitting the order. - [ ] Show complete policy Card issuers can be very specific about how you present your policies. If you have a checkbox your customer must accept that only contains a link, the issuer might reject it as unsatisfactory evidence that your customer was aware of your policies. There must be reasonable evidence that you presented your customer with a full copy of your policies prior to their purchase. - [ ] Track shipping When shipping physical goods to customers, use carriers and services that provide online tracking and delivery confirmation whenever possible. Provide this information to your customers as soon as it’s available (if you need to submit tracking information as dispute evidence, be aware that card issuers don’t follow links so screenshots must be provided). - [ ] Use clear statement descriptors Set a recognizable name for your [statement descriptor](https://docs.stripe.com/get-started/account/activate.md#public-business-information) through your [account settings](https://dashboard.stripe.com/settings/account/?support_details=true). We recommend using your website domain or business name to make sure customers can easily identify their purchase when they look at their statement. Statement descriptors are limited to between 5 and 22 characters. They must contain at least 5 letters and can’t use the special characters `<`, `>`, `\`, `'`, or `"`. - [ ] Separate your business accounts Avoid using the same Stripe account for separate businesses. Each Stripe account should represent a single business, which allows for separate statement descriptors and contact information. If you need to process payments for multiple businesses, create [additional accounts](https://docs.stripe.com/get-started/account/multiple-accounts.md) for each. ### Consider proactively refunding suspicious payments You should immediately refund any payment you’re [sure is fraud](https://docs.stripe.com/disputes/prevention/identifying-fraud.md) (unless you’re covered by some form of *liability shift* (With some 3D Secure transactions, the liability for fraudulent chargebacks (stolen or counterfeit cards) shifts from you to the card issuer), such as with [3D Secure](https://docs.stripe.com/payments/3d-secure/authentication-flow.md#disputed-payments)). If you know you’re going to receive a fraud dispute on it, you can save yourself the [dispute fee](https://docs.stripe.com/disputes/how-disputes-work.md#dispute-fees), the increase to your [dispute rate](https://docs.stripe.com/disputes/measuring.md#dispute-rate-usage), and the potential loss of product by fully refunding the fraudulent payment. > While customers can’t dispute fully refunded payments, they can still dispute partially refunded payments. Card network rules even allow for a payment that has been partially refunded to be disputed for the full payment amount. However, sometimes you might suspect a payment is fraud, but your suspicions fall short of absolute certainty. Sometimes it makes sense to aggressively refund every charge that falls into this gray area and sometimes it doesn’t. You might want to pursue an aggressive refund strategy if any of the following apply: - **Order not yet fulfilled**. The loss of your product could be prevented by a refund. That is, if you haven’t already committed your product or service in some irreversible way by the time you suspect fraud, you might want to be more aggressive in refunding. Whereas if your product or service was irretrievable—for example, the product already shipped, or the service has already been used—it might make more sense *not* to refund, and to wait and see if it does turn out to be fraud. - **Excessive disputes**. Your recent dispute activity has been [excessive](https://docs.stripe.com/disputes/measuring.md#excessive-dispute-activity) by *card network* (A network that processes the transactions of a particular card brand. It might be an intermediary in front of an issuing bank as with Visa or Mastercard, or a standalone entity as with American Express) definitions, which could put your account standing with Stripe at risk or put you at risk of being identified into a chargeback monitoring program. - **Chargeback monitoring program**. You’re already in a [chargeback monitoring program](https://docs.stripe.com/disputes/monitoring-programs.md) and need to exit the program. - **New or small business**. Your business has small enough payment volume (say, fewer than 100 payments per month) that one or two fraud disputes can have a very outsized impact on your [dispute rate](https://docs.stripe.com/disputes/measuring.md#dispute-rate-usage), even if you otherwise have little dispute activity. If none of the above apply, you might want to be more conservative with how frequently you proactively refund charges you suspect are fraudulent. > #### Refunding a payment as fraud > > To refund a payment, in the [Dashboard](https://dashboard.stripe.com), select the payment and click **Refund as fraud**. This refunds the payment and reports it as fraudulent to Stripe so that we can further improve our fraud detection. ### Delay shipping orders If you ship physical goods, consider delaying the shipment by 24-48 hours. This time gives cardholders a chance to spot and report any fraud on their accounts. You would still receive a fraud dispute in this scenario, but at least you wouldn’t also lose the merchandise. Not all cardholders check their statements on a daily basis, however, and their card issuer might not proactively notify them about the transaction. *Customers* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) that request overnight or expedited shipping should be considered higher risk, as the increased cost of such services is of no consequence to fraudsters. One tactic you can use to identify these types of payments is to offer same day or overnight shipping at a very high cost–many times more expensive than any other shipping option you provide. It’s far less likely that any legitimate customer would pay such a high cost, but a fraudster would want the goods to be shipped as soon as possible and have no regard for the additional cost. You can then manually screen any customers that opt for the anomalously expensive shipping option and scrutinize the order to determine if it looks genuine. Using a [separate auth and capture process](https://docs.stripe.com/disputes/prevention/best-practices.md#use-auth-and-capture-when-creating-payments) together with [Radar reviews](https://docs.stripe.com/disputes/prevention/best-practices.md#manually-review-payments) is a good way to do so. ### Ship to a verified address Shipping to a [verified billing address](https://docs.stripe.com/disputes/prevention/verification.md#avs-check) which has passed postal code and street address checks is the safest option. When using an address that hasn’t been verified, you can’t prove that the order was shipped to the legitimate cardholder if the payment is later disputed. This doesn’t prevent you shipping to a different address, though you should do all you can to mitigate the risks involved. For instance, you may only want to ship orders to a different address for returning customers you already know to be legitimate, or who provide a fully verifiable billing address. In addition, any of the following could indicate the payment is suspicious: - The order is much larger than normal, or is only for your most expensive products - The customer changed the shipping address after placing the order - The customer requested expedited shipping - The products ordered have a high resale value - The shipping destination is different from the billing address or the card’s country of origin (for example, the billing address is in Spain, but the shipping address is in France) Reviewing the order and the shipping address information can help you determine whether or not the order presents an unacceptable risk to you. ### Benchmarking your dispute rate Your account’s [dispute rate](https://docs.stripe.com/disputes/measuring.md#dispute-rate-usage) is an important metric to use when reviewing the efficacy of your disputes and fraud prevention methods. You can regularly review these metrics in your Stripe Dashboard to see the impact your dispute prevention strategies are having. ## Tools for users of Radar for Fraud Teams [Radar](https://stripe.com/radar) is a suite of features and tools for fighting fraud that is built into Stripe and requires no additional integration work. ### Manually review payments [Radar for Fraud Teams](https://stripe.com/radar/fraud-teams) includes a [review](https://docs.stripe.com/radar/reviews.md) feature that allows you to place certain payments into review—though keep in mind that these payments are still processed and the credit card charged, unless you are using a separate auth and capture process. These payments are placed into the [review queue](https://dashboard.stripe.com/radar) for you to take a closer look at. If you suspect the payment is fraudulent, you can refund it. You should review payments that Stripe has placed into your [review queue](https://dashboard.stripe.com/radar) as soon as possible. Payments with an [elevated risk](https://docs.stripe.com/radar/risk-evaluation.md#elevated-risk) of fraud are automatically marked for review. You can also create additional rules to customize the types of payments that should be placed in your review queue. Here are some considerations when reviewing a payment: - Does the billing address match the shipping address? - Has the billing address been verified by AVS? Does it also match the card’s country of origin? - Does the customer’s email address match the cardholder’s name? - Is this an order that the customer has asked to be expedited? - Have multiple orders from different credit cards originated from this same IP address? - Has this customer made many order attempts that have been declined? If you’re unsure about a payment when you’re reviewing it, you should always contact the customer by phone or email. If a payment’s billing and shipping address don’t match, look into the shipping address using [Google Maps & Street View](https://www.google.com/maps/streetview) to find out more. A common tactic that fraudsters use is to have orders shipped to a freight or mail forwarding service or storage facility that forwards the goods to their actual location. ### Use Radar rules to automatically block payments or place them in review [Radar for Fraud Teams](https://stripe.com/radar/fraud-teams), is built directly into the payment flow and combines a customizable rules engine with AI algorithms. It can detect patterns across payments from every business processing payments with Stripe, assessing the risk of each one. Using [rules](https://docs.stripe.com/radar/rules.md), you can automatically evaluate payments based on your specific detection criteria and take the appropriate action on them. You can also create rules that use multiple criteria, allowing you to allow or block payments that meet multiple conditions. Each business has different risks. ### Country and card type limiting If you’re experiencing increased fraud coming from certain countries, you can set up rules to block payments from any country you do not want to accept payments from, using the `:ip_country:` and `:card_country:` rule attributes. For example, you can create the following rule to block all payments and cards originating from Canada: `Block if :ip_country: = ca and :card_country: = 'ca'`. Similarly, if your business only supports the country it operates in, you can create a rule that blocks any payments from all other countries. For example, a rule to block payments that don’t originate from Australia is: `Block if :ip_country: != au and :card_country: != 'au'`. You can set limits on which type of cards to accept, either by brand, (for example, Mastercard), or by funding type (for example, pre-paid). This can be particularly helpful if you see excessive fraud from certain card types. To block payments from all Visa-issued debit cards, an example rule would be: `Block if :card_brand: = visa and :card_funding: = 'debit'`. ## Tools for developers These are tools that require some development work to implement. If you rely on a [Stripe partner](https://stripe.com/partners) to provide your payments integration, you might not have the ability to directly implement these on your own. ### Process your transactions on Stripe The [Visa Compelling Evidence 3.0](https://docs.stripe.com/disputes/best-practices.md#visa-ce-30) rules rely on transaction history to dispute [friendly fraud](https://docs.stripe.com/disputes/prevention/fraud-types.md#friendly-fraud) by showing previous non-fraud transactions with the same cardholder within a specified period. When you get a Visa fraud dispute, Stripe can identify qualifying transactions in your history on our platform and pre-populate the dispute response with most of the required evidence you need. You can use this evidence to significantly increase your likelihood of overturning the dispute in your favor. Stripe can’t determine eligibility or submit evidence for externally processed transactions, so we recommend: - Using Stripe processing whenever possible - Including the customer IP address, email address, shipping address, and product descriptions in your transactions with Stripe ### Collect as much payment information as possible Some disputes are lost because only the minimum information was required during checkout. This makes it difficult (sometimes impossible) for Stripe or the card issuer to verify that the customer is legitimate. For instance, while a billing postal code isn’t always necessary to process a card payment, including it allows the payment to be verified by the card issuer. If verification fails, consider rejecting the payment because this might indicate fraud. Use [Checkout](https://docs.stripe.com/payments/checkout.md) or [Advanced fraud detection](https://docs.stripe.com/disputes/prevention/advanced-fraud-detection.md) to make sure your integration is best equipped to provide relevant payment information, such as: - *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) name - Customer email address - CVC number - Full billing address and postal code - Shipping address (if different from billing address) - Tracking information ### Implement a cardholder authentication method such as 3D Secure *3D Secure* (3D Secure (3DS) provides an additional layer of authentication for credit card transactions that protects businesses from liability for fraudulent card payments) is a way to add a verification step between the customer and the *card issuer* (The entity that issued a payment card to a cardholder. This could be a bank, such as with the Visa or Mastercard network, or it could be the card network itself, such as with American Express) to your checkout flow. Payments that have been authenticated with 3D Secure might be protected from most fraudulent disputes through a rule known as [liability shift](https://docs.stripe.com/payments/3d-secure/authentication-flow.md#disputed-payments). You will, however, still receive [Early Fraud Warnings](https://docs.stripe.com/disputes/how-disputes-work.md#early-fraud-warnings) that can count against [card brand monitoring programs](https://docs.stripe.com/disputes/monitoring-programs.md). Learn more at [Card Authentication and 3D Secure](https://docs.stripe.com/payments/3d-secure.md). ### Programmatically verify your customer’s identity For some, verifying the identity of customers can be beneficial. Consider using [Stripe Identity](https://docs.stripe.com/identity.md) to verify a government ID and match with a selfie of the document holder. Alternatively, you can ask customers to connect their [Facebook](https://developers.facebook.com/docs/facebook-login/overview/) or [LinkedIn](https://developer.linkedin.com/docs/oauth2) accounts as a further proof of identity. This is an extra step that a fraudulent actor might not take. Some legitimate customers might not want to go through this additional step either, and your conversion rate might suffer as a result. ### Use auth and capture when creating payments Credit card charge attempts are processed in two parts. The charge is first *authorized* by requesting authorization for the amount to charge from the *card issuer* (The entity that issued a payment card to a cardholder. This could be a bank, such as with the Visa or Mastercard network, or it could be the card network itself, such as with American Express). After a charge is approved, by default it’s then *captured* immediately afterwards and the amount deducted from the card. A [capture later](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md) payment flow (sometimes called “auth and capture”) is the process of performing these two steps at separate times. The authorization can be made first, which holds the amount on the card and appears on a customer’s statement as a pending transaction, but doesn’t actually move money out of their account. The charge can then be captured any time up to 7 days after the authorization. Capturing a charge completes the payment and the funds are deducted from the customer’s card. If a charge isn’t captured within the time limit, the authorization is automatically released. Similar to delayed shipping, this method can allow enough time for potential fraud to come to light, giving you the option to carefully review—and potentially refund—the transaction. Cardholders can’t dispute uncaptured authorizations, only fully captured payments. With Radar for Fraud Teams you can manually capture these payments in the [review process](https://docs.stripe.com/disputes/prevention/best-practices.md#manually-review-payments). ### Set a custom statement descriptor for each payment The statement descriptor is the text that appears on customers’ card statements with information about the company that’s associated with a payment. One way to use a statement descriptor is to insert a short, random code that your customer then has to verify. When you suspect a transaction might be fraudulent, you can contact your customer and ask them to give you the code that is shown on their online statement, and if they do not, you would refund the payment. You can either edit your [default statement descriptor](https://dashboard.stripe.com/settings/public) within the Dashboard or set a [dynamic statement descriptor](https://docs.stripe.com/get-started/account/statement-descriptors.md#dynamic) whenever a payment is created through the API. While this method can’t help against a fraudster who may have access to a cardholder’s online card issuer or credit account, this is rare. Using the statement descriptor in this manner can provide reassurance that the customer is likely to be genuine. As with some other prevention methods, the added customer friction of this method could lead to some legitimate payments being refunded. ### Review fraud rate increase alerts When you receive alerts from [Stripe health alerts](https://docs.stripe.com/health-alerts.md), you can review incoming disputes for common patterns first. If any of your incoming payments share similar patterns, you can consider refunding them to avoid potential disputes. Stripe alerts you to the following attack types: | Attack type | Description | | ------------------ | ------------------------------------------------------------------- | | `spike` | Stripe detects a single day increase in your fraud rate. | | `sustained_attack` | Stripe detects an ongoing or multi-day increase in your fraud rate. | > Your reliance on fraudulent transaction alerts is at your own risk. Stripe isn’t liable for any losses, damages, or costs relating to the accuracy or inaccuracy of the alerts, and any actions that you might take or refrain from taking based on the alerts. --- # Source: https://docs.stripe.com/billing/billing-apis.md # About the Billing APIs Understand how the Billing API objects work together. If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. *Subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) automatically create *Invoices* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) and *Payment Intents* (API object that represents your intent to collect payment from a customer, tracking charge attempts and payment state changes throughout the process) for you. They have the following parts: - A *Product* (Products represent what your business sells—whether that's a good or a service) to model what is being sold. - A *Price* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) to determine the interval and amount to charge. - A *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) to store the *Payment Methods* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) used to make each recurring payment. A diagram illustrating common billing objects and their relationships (See full diagram at https://docs.stripe.com/billing/billing-apis) ## API object definitions | Resource | Definition | | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Customer](https://docs.stripe.com/api/customers.md) | Represents a customer who purchases a subscription. Use the Customer object associated with a subscription to make and track recurring charges and to manage the products that they subscribe to. | | [Entitlement](https://docs.stripe.com/api/entitlements/active-entitlement.md) | Represents a customer’s access to a feature included in a service product that they subscribe to. When you create a subscription for a customer’s recurring purchase of a product, an active entitlement is automatically created for each feature associated with that product. When a customer accesses your services, use their active entitlements to enable the features included in their subscription. | | [Feature](https://docs.stripe.com/api/entitlements/feature.md) | Represents a function or ability that your customers can access when they subscribe to a service product. You can include features in a product by creating ProductFeatures. | | [Invoice](https://docs.stripe.com/api/invoices.md) | A statement of amounts a customer owes that tracks payment statuses from draft through paid or otherwise finalized. Subscriptions automatically generate invoices. | | [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) | A way to build dynamic payment flows. A PaymentIntent tracks the lifecycle of a customer checkout flow and triggers additional authentication steps when required by regulatory mandates, custom Radar fraud rules, or redirect-based payment methods. Invoices automatically create PaymentIntents. | | [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) | A customer’s payment methods that they use to pay for your products. For example, you can store a credit card on a Customer object and use it to make recurring payments for that customer. Typically used with the Payment Intents or Setup Intents APIs. | | [Price](https://docs.stripe.com/api/prices.md) | Defines the unit price, currency, and billing cycle for a product. | | [Product](https://docs.stripe.com/api/products.md) | A good or service that your business sells. A service product can include one or more features. | | [ProductFeature](https://docs.stripe.com/api/product-feature.md) | Represents a single feature’s inclusion in a single product. Each product is associated with a ProductFeature for each feature that it includes, and each feature is associated with a ProductFeature for each product that includes it. | | [Subscription](https://docs.stripe.com/api/subscriptions.md) | Represents a customer’s scheduled recurring purchase of a product. Use a subscription to collect payments and provide repeated delivery of or continuous access to a product. | Here’s an example of how products, features, and entitlements work together. Imagine that you want to set up a recurring service that offers two tiers: a standard product with basic functionality, and an advanced product that adds extended functionality. 1. You create two features: `basic_features` and `extended_features`. 1. You create two products: `standard_product` and `advanced_product`. 1. For the standard product, you create one ProductFeature that associates `basic_features` with `standard_product`. 1. For the advanced product, you create two ProductFeatures: one that associates `basic_features` with `advanced_product` and one that associates `extended_features` with `advanced_product`. A customer, `first_customer`, subscribes to the standard product. When you create the subscription, Stripe automatically creates an Entitlement that associates `first_customer` with `basic_features`. Another customer, `second_customer`, subscribes to the advanced product. When you create the Subscription, Stripe automatically creates two Entitlements: one that associates `second_customer` with `basic_features`, and one that associates `second_customer` with `extended_features`. You can determine which features to provision for a customer by [retrieving their active entitlements or listening to the Active Entitlement Summary event](https://docs.stripe.com/billing/entitlements.md#entitlements). You don’t have to retrieve their subscriptions, products, and features. --- # Source: https://docs.stripe.com/billing/subscriptions/billing-cycle.md # Source: https://docs.stripe.com/payments/checkout/billing-cycle.md # Set the billing cycle date Set a subscription's billing cycle anchor to a fixed date. # Stripe-hosted page > This is a Stripe-hosted page for when payment-ui is stripe-hosted. View the full page at https://docs.stripe.com/payments/checkout/billing-cycle?payment-ui=stripe-hosted. You can explicitly set a subscription’s [billing cycle anchor](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-subscription_data-billing_cycle_anchor) to a fixed date (for example, the 1st of the next month) when creating a Checkout Session. The billing cycle anchor determines the first full invoice date, when customers are billed the full subscription amount. The billing cycle anchor and the recurring interval of its [price](https://docs.stripe.com/products-prices/overview.md) also determine a subscription’s future billing dates. For example, a monthly subscription created on May 15 with an anchor at June 1 is billed on May 15, then always on the 1st of the month. For the initial billing period up until the first full invoice date, you can customize how to handle [prorations](https://docs.stripe.com/billing/subscriptions/prorations.md) with the [proration_behavior](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-subscription_data-proration_behavior) parameter. By default, `proration_behavior` is set to `create_prorations`, and customers receive a prorated *invoice* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice). If `proration_behavior` is `none`, customers receive the initial period up to the first full invoice date for free. ## Create a Checkout Session with a billing cycle anchor To configure a billing cycle anchor, set the `subscription_data.billing_cycle_anchor` parameter when you create a Checkout Session in `subscription` mode. The anchor must be a future UNIX timestamp before the next natural subscription billing date. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d mode=subscription \ --data-urlencode success_url="https://example.com/success?session_id={CHECKOUT_SESSION_ID}" \ -d "subscription_data[billing_cycle_anchor]"=1611008505 ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ --mode=subscription \ --success-url="https://example.com/success?session_id={CHECKOUT_SESSION_ID}" \ -d "subscription_data[billing_cycle_anchor]"=1611008505 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'subscription', success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', subscription_data: {billing_cycle_anchor: 1611008505}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "subscription", "success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}", "subscription_data": {"billing_cycle_anchor": 1611008505}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'subscription', 'success_url' => 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', 'subscription_data' => ['billing_cycle_anchor' => 1611008505], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.SUBSCRIPTION) .setSuccessUrl("https://example.com/success?session_id={CHECKOUT_SESSION_ID}") .setSubscriptionData( SessionCreateParams.SubscriptionData.builder() .setBillingCycleAnchor(1611008505L) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'subscription', success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', subscription_data: { billing_cycle_anchor: 1611008505, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModeSubscription), SuccessURL: stripe.String("https://example.com/success?session_id={CHECKOUT_SESSION_ID}"), SubscriptionData: &stripe.CheckoutSessionCreateSubscriptionDataParams{ BillingCycleAnchor: stripe.Int64(1611008505), }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "subscription", SuccessUrl = "https://example.com/success?session_id={CHECKOUT_SESSION_ID}", SubscriptionData = new Stripe.Checkout.SessionSubscriptionDataOptions { BillingCycleAnchor = DateTimeOffset.FromUnixTimeSeconds(1611008505).UtcDateTime, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` If the billing cycle anchor is during a session’s active period and a customer attempts payment after it has passed, Checkout displays and charges for the full period starting with the billing cycle anchor instead of the prorated period before the billing cycle anchor. ## Disable prorations To disable prorations, set the `subscription_data.proration_behavior` parameter to `none` when creating a Checkout Session. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d mode=subscription \ --data-urlencode success_url="https://example.com/success?session_id={CHECKOUT_SESSION_ID}" \ -d "subscription_data[billing_cycle_anchor]"=1611008505 \ -d "subscription_data[proration_behavior]"=none ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ --mode=subscription \ --success-url="https://example.com/success?session_id={CHECKOUT_SESSION_ID}" \ -d "subscription_data[billing_cycle_anchor]"=1611008505 \ -d "subscription_data[proration_behavior]"=none ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'subscription', success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', subscription_data: { billing_cycle_anchor: 1611008505, proration_behavior: 'none', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "subscription", "success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}", "subscription_data": {"billing_cycle_anchor": 1611008505, "proration_behavior": "none"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'subscription', 'success_url' => 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', 'subscription_data' => [ 'billing_cycle_anchor' => 1611008505, 'proration_behavior' => 'none', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.SUBSCRIPTION) .setSuccessUrl("https://example.com/success?session_id={CHECKOUT_SESSION_ID}") .setSubscriptionData( SessionCreateParams.SubscriptionData.builder() .setBillingCycleAnchor(1611008505L) .setProrationBehavior(SessionCreateParams.SubscriptionData.ProrationBehavior.NONE) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'subscription', success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}', subscription_data: { billing_cycle_anchor: 1611008505, proration_behavior: 'none', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModeSubscription), SuccessURL: stripe.String("https://example.com/success?session_id={CHECKOUT_SESSION_ID}"), SubscriptionData: &stripe.CheckoutSessionCreateSubscriptionDataParams{ BillingCycleAnchor: stripe.Int64(1611008505), ProrationBehavior: stripe.String("none"), }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "subscription", SuccessUrl = "https://example.com/success?session_id={CHECKOUT_SESSION_ID}", SubscriptionData = new Stripe.Checkout.SessionSubscriptionDataOptions { BillingCycleAnchor = DateTimeOffset.FromUnixTimeSeconds(1611008505).UtcDateTime, ProrationBehavior = "none", }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` Similar to a free trial, the initial period up to the billing cycle anchor is free. Unlike a trial, no 0 USD invoice is generated. Customers receive an invoice with the full subscription amount on the billing cycle anchor date. In the Checkout Session response object, amounts attached to the [line items](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-line_items) and [total details](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-total_details) are always 0 when prorations are disabled. Additionally, the [payment status](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-payment_status) of the Session is set to `no_payment_required` to reflect that payment is delayed to a future date. ## Limitations - You can’t use trials in Checkout Sessions with a billing cycle anchor. - You can’t use one-time prices in Checkout Sessions when `proration_behavior` is `none`. - You can’t apply [amount_off coupons](https://docs.stripe.com/api/coupons/create.md#create_coupon-amount_off) to Checkout Sessions with a default `proration_behavior` of `create_prorations`. # Embedded form > This is a Embedded form for when payment-ui is embedded-form. View the full page at https://docs.stripe.com/payments/checkout/billing-cycle?payment-ui=embedded-form. You can explicitly set a subscription’s [billing cycle anchor](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-subscription_data-billing_cycle_anchor) to a fixed date (for example, the 1st of the next month) when creating a Checkout Session. The billing cycle anchor determines the first full invoice date, when customers are billed the full subscription amount. The billing cycle anchor and the recurring interval of its [price](https://docs.stripe.com/products-prices/overview.md) also determine a subscription’s future billing dates. For example, a monthly subscription created on May 15 with an anchor at June 1 is billed on May 15, then always on the 1st of the month. For the initial billing period up until the first full invoice date, you can customize how to handle [prorations](https://docs.stripe.com/billing/subscriptions/prorations.md) with the [proration_behavior](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-subscription_data-proration_behavior) parameter. By default, `proration_behavior` is set to `create_prorations`, and customers receive a prorated *invoice* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice). If `proration_behavior` is `none`, customers receive the initial period up to the first full invoice date for free. ## Create a Checkout Session with a billing cycle anchor To configure a billing cycle anchor, set the `subscription_data.billing_cycle_anchor` parameter when you create a Checkout Session in `subscription` mode. The anchor must be a future UNIX timestamp before the next natural subscription billing date. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d mode=subscription \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return?session_id={CHECKOUT_SESSION_ID}" \ -d "subscription_data[billing_cycle_anchor]"=1611008505 ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ --mode=subscription \ --ui-mode=embedded \ --return-url="https://example.com/return?session_id={CHECKOUT_SESSION_ID}" \ -d "subscription_data[billing_cycle_anchor]"=1611008505 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'subscription', ui_mode: 'embedded', return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', subscription_data: {billing_cycle_anchor: 1611008505}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "subscription", "ui_mode": "embedded", "return_url": "https://example.com/return?session_id={CHECKOUT_SESSION_ID}", "subscription_data": {"billing_cycle_anchor": 1611008505}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'subscription', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', 'subscription_data' => ['billing_cycle_anchor' => 1611008505], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.SUBSCRIPTION) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return?session_id={CHECKOUT_SESSION_ID}") .setSubscriptionData( SessionCreateParams.SubscriptionData.builder() .setBillingCycleAnchor(1611008505L) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'subscription', ui_mode: 'embedded', return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', subscription_data: { billing_cycle_anchor: 1611008505, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModeSubscription), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return?session_id={CHECKOUT_SESSION_ID}"), SubscriptionData: &stripe.CheckoutSessionCreateSubscriptionDataParams{ BillingCycleAnchor: stripe.Int64(1611008505), }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "subscription", UiMode = "embedded", ReturnUrl = "https://example.com/return?session_id={CHECKOUT_SESSION_ID}", SubscriptionData = new Stripe.Checkout.SessionSubscriptionDataOptions { BillingCycleAnchor = DateTimeOffset.FromUnixTimeSeconds(1611008505).UtcDateTime, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` If the billing cycle anchor is during a session’s active period and a customer attempts payment after it has passed, Checkout displays and charges for the full period starting with the billing cycle anchor instead of the prorated period before the billing cycle anchor. ## Disable prorations To disable prorations, set the `subscription_data.proration_behavior` parameter to `none` when creating a Checkout Session. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d mode=subscription \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return?session_id={CHECKOUT_SESSION_ID}" \ -d "subscription_data[billing_cycle_anchor]"=1611008505 \ -d "subscription_data[proration_behavior]"=none ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ --mode=subscription \ --ui-mode=embedded \ --return-url="https://example.com/return?session_id={CHECKOUT_SESSION_ID}" \ -d "subscription_data[billing_cycle_anchor]"=1611008505 \ -d "subscription_data[proration_behavior]"=none ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'subscription', ui_mode: 'embedded', return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', subscription_data: { billing_cycle_anchor: 1611008505, proration_behavior: 'none', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "subscription", "ui_mode": "embedded", "return_url": "https://example.com/return?session_id={CHECKOUT_SESSION_ID}", "subscription_data": {"billing_cycle_anchor": 1611008505, "proration_behavior": "none"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'subscription', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', 'subscription_data' => [ 'billing_cycle_anchor' => 1611008505, 'proration_behavior' => 'none', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.SUBSCRIPTION) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return?session_id={CHECKOUT_SESSION_ID}") .setSubscriptionData( SessionCreateParams.SubscriptionData.builder() .setBillingCycleAnchor(1611008505L) .setProrationBehavior(SessionCreateParams.SubscriptionData.ProrationBehavior.NONE) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'subscription', ui_mode: 'embedded', return_url: 'https://example.com/return?session_id={CHECKOUT_SESSION_ID}', subscription_data: { billing_cycle_anchor: 1611008505, proration_behavior: 'none', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModeSubscription), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return?session_id={CHECKOUT_SESSION_ID}"), SubscriptionData: &stripe.CheckoutSessionCreateSubscriptionDataParams{ BillingCycleAnchor: stripe.Int64(1611008505), ProrationBehavior: stripe.String("none"), }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "subscription", UiMode = "embedded", ReturnUrl = "https://example.com/return?session_id={CHECKOUT_SESSION_ID}", SubscriptionData = new Stripe.Checkout.SessionSubscriptionDataOptions { BillingCycleAnchor = DateTimeOffset.FromUnixTimeSeconds(1611008505).UtcDateTime, ProrationBehavior = "none", }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` Similar to a free trial, the initial period up to the billing cycle anchor is free. Unlike a trial, no 0 USD invoice is generated. Customers receive an invoice with the full subscription amount on the billing cycle anchor date. In the Checkout Session response object, amounts attached to the [line items](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-line_items) and [total details](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-total_details) are always 0 when prorations are disabled. Additionally, the [payment status](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-payment_status) of the Session is set to `no_payment_required` to reflect that payment is delayed to a future date. ## Limitations - You can’t use trials in Checkout Sessions with a billing cycle anchor. - You can’t use one-time prices in Checkout Sessions when `proration_behavior` is `none`. - You can’t apply [amount_off coupons](https://docs.stripe.com/api/coupons/create.md#create_coupon-amount_off) to Checkout Sessions with a default `proration_behavior` of `create_prorations`. ## See also - [Prorations](https://docs.stripe.com/billing/subscriptions/prorations.md) --- # Source: https://docs.stripe.com/terminal/features/apps-on-devices/build.md # Build and test your app Learn how to build and test your app using a DevKit. Access the Apps on Devices sample integration repository on [GitHub](https://github.com/stripe-samples/terminal-apps-on-devices). Use your SmartPOS DevKit device to test and iterate your application without going through the deployment, app review, or signing process. If you need a DevKit device, you can [order up to five per user](https://docs.stripe.com/terminal/fleet/order-and-return-readers.md) from the [Readers](https://dashboard.stripe.com/terminal) section in your Dashboard. > Verifone reader support is in public preview for the US and CA. To join the preview, you must [contact the Sales team to order the applicable reader](https://stripe.com/contact/sales). ## Set up the DevKit Before you can use your DevKit for app development, you must do the following: 1. Follow the on-screen prompts to connect to a network. 1. [Register](https://docs.stripe.com/terminal/payments/connect-reader.md?terminal-sdk-platform=android&reader-type=internet#register-reader) the device to your Stripe account. 1. Install all available updates. After the initial setup, you can register your DevKit to another account or location at any time. To do so, connect the DevKit to the internet and follow the steps to [register a reader](https://docs.stripe.com/terminal/payments/connect-reader.md?terminal-sdk-platform=android&reader-type=internet#register-reader). While similar to production devices, DevKit devices: - Can only operate in [sandboxes](https://docs.stripe.com/keys.md#test-live-modes). - Ship with [developer options](https://developer.android.com/studio/debug/dev-options) and [Android Debug Bridge](https://developer.android.com/studio/command-line/adb) (`adb`) enabled by default. - Display an on-screen watermark to indicate that the device is only used for testing. The watermark moves around the screen while the device is in use so that you can see all parts of the screen. The Terminal API supports targeting registered DevKit devices. ## Develop your app for Stripe devices Use the following steps to develop your app for Stripe Android devices, including setting up the app and handing it off to the Stripe Reader app. ## Set up the app [Client-side] #### Android First, [set up your integration](https://docs.stripe.com/terminal/payments/setup-integration.md?terminal-sdk-platform=android) for in-person payments. Then, follow the guidance below for Apps on Devices integrations. ### Add dependencies Add the following dependencies to your project’s Gradle build script. Apps on Devices integrations require [Terminal Android SDK](https://github.com/stripe/stripe-terminal-android) version `2.22.0` or later. We recommend that you integrate with the [latest version](https://github.com/stripe/stripe-terminal-android/releases). #### Kotlin ```kotlin dependencies { implementation("com.stripe:stripeterminal-core:5.2.0") implementation("com.stripe:stripeterminal-appsondevices:5.2.0") } ``` #### Groovy ```groovy dependencies { implementation "com.stripe:stripeterminal-core:5.2.0" implementation "com.stripe:stripeterminal-appsondevices:5.2.0" } ``` Make sure that you aren’t using any other Stripe Terminal SDK dependencies. For example, if you previously integrated the Terminal Android SDK, don’t use the top-level `com.stripe:stripeterminal` dependency (for example, `com.stripe:stripeterminal:5.2.0`). See an example of [including dependencies in your app’s build script](https://github.com/stripe-samples/terminal-apps-on-devices/blob/718c2de38c7b8003fcf58c536c266bb990ad43a7/app/build.gradle.kts#L66). ### Configure your application To inform the Stripe SDK of lifecycle events, add a [TerminalApplicationDelegate.onCreate()](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal-application-delegate/on-create.html) call to the [onCreate()](https://developer.android.com/reference/android/app/Application#onCreate\(\)) method for your application subclass. #### Kotlin ```kotlin class MyApplication : Application() { override fun onCreate() { super.onCreate() TerminalApplicationDelegate.onCreate(this) } } ``` #### Java ```java public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); TerminalApplicationDelegate.onCreate(this); } } ``` In your [app manifest](https://developer.android.com/guide/topics/manifest/manifest-intro), specify the name of your `Application` subclass with the `android:name` attribute. > To ensure your `Application` supports devices running Android 15, set the `targetSdkVersion` to `24` or later. ```xml ``` Learn more about [setting up your integration](https://docs.stripe.com/terminal/payments/setup-integration.md?terminal-sdk-platform=android) or see the Apps on Devices sample app GitHub repository for an example of [configuring the Application subclass](https://github.com/stripe-samples/terminal-apps-on-devices/blob/718c2de38c7b8003fcf58c536c266bb990ad43a7/app/src/main/java/com/stripe/aod/sampleapp/MyApp.kt#L10). #### React Native First, [set up your integration](https://docs.stripe.com/terminal/payments/setup-integration.md?terminal-sdk-platform=react-native) for in-person payments. Then, follow the guidance below for Apps on Devices integrations. ### Configure your application To inform the Stripe SDK of lifecycle events, add a `TerminalApplicationDelegate.onCreate()` call to the [onCreate()](https://developer.android.com/reference/android/app/Application#onCreate\(\)) method for your application subclass. #### Kotlin ```kotlin import com.stripeterminalreactnative.TerminalApplicationDelegate class MyApplication : Application() { override fun onCreate() { super.onCreate() TerminalApplicationDelegate.onCreate(this) } } ``` #### Java ```java import com.stripeterminalreactnative.TerminalApplicationDelegate; public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); TerminalApplicationDelegate.onCreate(this); } } ``` In your [app manifest](https://developer.android.com/guide/topics/manifest/manifest-intro), specify the name of your `Application` subclass with the `android:name` attribute. ```xml ``` Learn more about [setting up your integration](https://docs.stripe.com/terminal/payments/setup-integration.md?terminal-sdk-platform=react-native) or see the sample app on React Native GitHub repository for an example of [configuring the Application subclass](https://github.com/stripe/stripe-terminal-react-native/blob/main/dev-app/android/app/src/main/java/com/dev/app/stripeterminalreactnative/MainApplication.java#L58). ## Build the app [Client-side] Follow the guidance below for Apps on Devices integrations. ### Discover and connect a reader #### Android > In version `5.0.0` of the Android SDK, you can use the `easyConnect` method to combine reader discovery and connection into a single API call to simplify integration. See the [SDK migration guide](https://docs.stripe.com/terminal/references/sdk-migration-guide.md#update-your-reader-connection-usage) for details. You must register a new Stripe device to your account as a new [Reader object](https://docs.stripe.com/api/terminal/readers/object.md). Use the pairing code provided in the device’s admin settings to [create the Reader object](https://docs.stripe.com/api/terminal/readers/create.md). Your app uses the Stripe Terminal Android SDK to discover and connect to your device: See more examples of how to [discover](https://github.com/stripe-samples/terminal-apps-on-devices/blob/718c2de38c7b8003fcf58c536c266bb990ad43a7/app/src/main/java/com/stripe/aod/sampleapp/model/MainViewModel.kt#L90) and [connect](https://github.com/stripe-samples/terminal-apps-on-devices/blob/718c2de38c7b8003fcf58c536c266bb990ad43a7/app/src/main/java/com/stripe/aod/sampleapp/model/MainViewModel.kt#L106) using handoff mode in the Apps on Devices sample integration repository on [GitHub](https://github.com/stripe-samples/terminal-apps-on-devices). 1. Your app runs on your registered device. 1. Your app discovers the reader by calling [discoverReaders](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/discover-readers.html) with [AppsOnDevicesDiscoveryConfiguration](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-discovery-configuration/-apps-on-devices-discovery-configuration/index.html). 1. Your app connects to the reader by using [connectReader](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/connect-reader.html). The following example shows how to discover and connect to a Stripe reader using handoff mode in an Android app: #### Kotlin ```kotlin private fun discoverReaders() { Terminal.getInstance().discoverReaders(config = AppsOnDevicesDiscoveryConfiguration(), discoveryListener = object : DiscoveryListener { override fun onUpdateDiscoveredReaders(readers: List) { // In Apps on Devices discovery, the list will // contain a single reader. Connect to // the reader after it is discovered. readers.firstOrNull()?.let { reader -> connectReader(reader) } } }, callback = object : Callback { override fun onSuccess() { // Handle successfully discovering readers } override fun onFailure(e: TerminalException) { // Handle exception while discovering readers } } ) } private fun connectReader(reader: Reader) { Terminal.getInstance().connectReader( reader,AppsOnDevicesConnectionConfiguration( object : AppsOnDevicesReaderListener { override fun onDisconnect(reason: DisconnectReason) { // Optionally get notified about reader disconnects (for example, reader was rebooted) } override fun onReportReaderEvent(event: ReaderEvent) { // Optionally get notified about reader events (for example, a card was inserted) } } ), object : ReaderCallback { override fun onSuccess(reader: Reader) { // Handle successfully connecting to the reader } override fun onFailure(e: TerminalException) { // Handle exception when connecting to the reader } } ) } ``` #### Java ```java private void discoverReaders(@Nullable String locationId) { Terminal.getInstance().discoverReaders( new AppsOnDevicesDiscoveryConfiguration(), readers - > { if (!readers.isEmpty()) { connectReader(readers.get(0)); } }, new Callback() { @Override public void onSuccess() { // Handle successfully discovering readers } @Override public void onFailure(@NotNull TerminalException e) { // Handle exception while discovering readers } } ); } private void connectReader(@NotNull Reader reader) { Terminal.getInstance().connectReader( reader,new AppsOnDevicesConnectionConfiguration( new AppsOnDevicesReaderListener() { @Override public void onDisconnect(@NotNull DisconnectReason reason) { // Optionally get notified about reader disconnects (for example, reader was rebooted) } @Override public void onReportReaderEvent(@NotNull ReaderEvent event) { // Optionally get notified about reader events (for example, a card was inserted) } } ), new ReaderCallback() { @Override public void onSuccess(@NotNull Reader reader) { // Handle successfully connecting to the reader } @Override public void onFailure(@NotNull TerminalException e) { // Handle exception when connecting to the reader } } ); } ``` #### React Native You must register a new Stripe device to your account as a new [Reader object](https://docs.stripe.com/api/terminal/readers/object.md). Use the pairing code provided in the device’s admin settings to [create the Reader object](https://docs.stripe.com/api/terminal/readers/create.md). Your app uses the Stripe Terminal React Native SDK to discover and connect to your device: 1. Your app runs on your registered device. 1. Your app discovers the reader by calling [discoverReaders](https://stripe.dev/stripe-terminal-react-native/api-reference/interfaces/StripeTerminalSdkType.html#discoverReaders) with `handoff` [discovery method](https://stripe.dev/stripe-terminal-react-native/api-reference/modules/Reader.Android.html#DiscoveryMethod). 1. Your app connects to the reader by using [connectReader](https://stripe.dev/stripe-terminal-react-native/api-reference/interfaces/StripeTerminalSdkType.html#connectreader-1). The following example shows how to discover and connect to a Stripe reader using handoff mode in a React Native app: ```js const { discoverReaders, connectReader, discoveredReaders } = useStripeTerminal({ onUpdateDiscoveredReaders: async (readers) => { // After the SDK discovers a reader, your app can connect to it. // The discoverReaders method doesn't resolve until discovery completes, // so use this callback to handle discovered readers. if (readers.length > 0) { const { reader, error } = await connectReader( { reader: readers[0] }, 'handoff' ); if (error) { console.log('connectReader error:', error); return; } console.log('Reader connected successfully', reader); } }, }); const handleDiscoverReaders = async () => { const { error } = await discoverReaders({ discoveryMethod: 'handoff', }); if (error) { console.log('discoverReaders error:', error); } }; useEffect(() => { handleDiscoverReaders(); }, [discoverReaders]); ``` ### Collect payments After you connect to the reader using handoff mode, you can start [collecting payments](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=android#create-payment). The Stripe Reader app handles payment collection and other payment operations, such as [saving payment details](https://docs.stripe.com/terminal/features/saving-payment-details/overview.md). When initiating a payment operation, the Stripe Reader app becomes the primary and launches in full screen. Then, the Stripe Reader app guides the customer through the flow and returns control to your app after completion (success or failure) or customer cancellation. When control returns to your app, the Stripe Reader app continues to run in the background. See an example of [collecting payment in an Apps on Devices app](https://github.com/stripe-samples/terminal-apps-on-devices/blob/718c2de38c7b8003fcf58c536c266bb990ad43a7/app/src/main/java/com/stripe/aod/sampleapp/model/CheckoutViewModel.kt#L82). #### Collect payments while offline Apps on Devices supports [offline payment collection](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md?terminal-sdk-platform=android&reader-type=internet). ## Device management [Client-side] You can access the device’s admin settings by launching the `stripe://settings/` deep-link URI from your app. See an example of [launching the admin settings deep-link URI](https://github.com/stripe-samples/terminal-apps-on-devices/blob/718c2de38c7b8003fcf58c536c266bb990ad43a7/app/src/main/java/com/stripe/aod/sampleapp/fragment/HomeFragment.kt#L30). #### Kotlin ```kotlin startActivity( Intent(Intent.ACTION_VIEW) .setData(Uri.parse("stripe://settings/")) ) ``` #### Java ```java startActivity( new Intent(Intent.ACTION_VIEW); .setData(Uri.parse("stripe://settings/")) ) ``` ## Instrument the app [Client-side] Stripe doesn’t provide an application-level instrumentation solution. To keep track of crashes and other logs from your application, you can use a third-party library such as Sentry or Crashlytics. ## Set the device locale [Client-side] The device user’s language selection (not country) informs the value returned by [Locale.getDefault()](https://developer.android.com/reference/java/util/Locale#getDefault\(\)). You can change the device language in the admin settings. ## Screen orientation [Client-side] Stripe Android devices have the *Auto-rotate screen* setting enabled by default. Your app can override this setting by locking the UI to a specific screen orientation. This can be achieved by setting the [screenOrientation](https://developer.android.com/guide/topics/manifest/activity-element#screen) attribute on the relevant `` tags in the manifest. ```xml ``` Alternatively, this can be set programmatically using [Activity::setRequestedOrientation](https://developer.android.com/reference/android/app/Activity#setRequestedOrientation\(int\)) in your `Activity` class. #### Kotlin ```kotlin class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Lock to portrait orientation requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT // Or, lock to landscape orientation // requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE } } ``` #### Java ```java public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Lock to portrait orientation setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // Or, lock to landscape orientation // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } } ``` ## Limitations [Client-side] Stripe Android devices don’t render a system UI, including a back button or status bar. If your app needs to communicate battery level, charging state, and connectivity status to the user, refer to the following Android API docs for guidance: - [Monitor the Battery Level and Charging State](https://developer.android.com/training/monitoring-device-state/battery-monitoring) - [Monitor connectivity status and connection metering](https://developer.android.com/training/monitoring-device-state/connectivity-status-type) ## Working with device accessories [Client-side] When the Stripe reader connects or disconnects from a dock, the Android operation system triggers a [configuration change](https://developer.android.com/guide/topics/resources/runtime-changes). By default, your app’s activity is automatically recreated on a configuration change. To disable automatic activity recreation when connecting to or disconnecting from a dock, add `android:configChanges="uiMode"` in the `` entry in your `AndroidManifest.xml` file. ```xml ``` Your activity can be notified of configuration changes by implementing [Activity::onConfigurationChanged](https://developer.android.com/reference/android/app/Activity#onConfigurationChanged\(android.content.res.Configuration\)). This method is only called if you’ve specified configurations you want to handle with the `android:configChanges` attribute in your manifest. ```kotlin class MainActivity : Activity() { override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // implement custom configuration change handling logic } } ``` ## Test your app Use your S700 DevKit device to test your app in the Stripe Dashboard or using the Android Debug Bridge (`adb`). #### Android Debug Bridge (adb) You can connect your DevKit device to your computer using a USB-A to USB-C cable. Then, use `adb` to directly install your app’s assembled APK onto the DevKit device. The following examples assume your application’s [package name](https://developer.android.com/studio/build/configure-app-module) is `com.example.myapp` and the [main activity](https://developer.android.com/reference/android/content/Intent.html#ACTION_MAIN) is `MainActivity`. ``` $ adb install myapp.apk ``` After installation completes, launch your app: ``` $ adb shell am start com.example.myapp/.MainActivity ``` Start admin settings: ``` $ adb shell am start -d "stripe://settings/" ``` If needed, uninstall your app: ``` $ adb uninstall com.example.myapp ``` Google’s [Android Debug Bridge documentation](https://developer.android.com/studio/command-line/adb) provides a comprehensive guide to using `adb`. #### Dashboard Follow these steps to test your app in the Dashboard: 1. In a sandbox, open the [Terminal readers](https://dashboard.stripe.com/test/terminal/readers) page. 1. If you haven’t already, click **Register reader** to [register](https://docs.stripe.com/terminal/payments/connect-reader.md?reader-type=internet#register-reader) the DevKit device to your account. 1. Click **Terminal** > **Software**. 1. On the [Software](https://dashboard.stripe.com/terminal/software) tab, choose the app that you want to deploy. You can also create a new app to deploy. 1. On the app details page, click **Deploy version**. 1. Choose the latest version of your app, then click **Next**. 1. Choose the [deploy group](https://docs.stripe.com/terminal/features/apps-on-devices/deploy-in-Dashboard.md) for your DevKit device, then click **Next**. 1. Choose your preferred kiosk app, then click **Next**. This is the default app that launches when the Stripe reader turns on. If there’s only one app to deploy, choose that app instead. 1. Confirm the deployment details, then click **Deploy**. 1. Restart your DevKit device to deploy your app to the device. ### Troubleshooting If you previously installed your app by sideloading and attempt to deploy it again, you might receive the following error: `Failed to apply updates. Code: A9-com.example.posapp`. You must manually uninstall the sideloaded app by running the following command: ``` adb uninstall com.example.posapp ``` ## Test payments DevKit devices can process test payments using a Stripe physical test card, which you can order in the [Dashboard](https://dashboard.stripe.com/terminal/shop/thsku_FmpZaTqwezTFvS). When [testing payments](https://docs.stripe.com/terminal/references/testing.md#physical-test-cards), you can use decimal amounts to produce specific outcomes. > Don’t use real cards for test payments on DevKit devices. ## Next steps - [Prepare for app review](https://docs.stripe.com/terminal/features/apps-on-devices/app-review.md) - [Submit your app](https://docs.stripe.com/terminal/features/apps-on-devices/submit.md) --- # Source: https://docs.stripe.com/invoicing/bulk-update-line-item.md # Manage bulk invoice line items Add, update and remove multiple invoice line items with the Invoices API. You can edit multiple line items on an invoice by bulk adding, updating, and removing line items with the [Invoices API](https://docs.stripe.com/api/invoices.md). ## Create an invoice To update an invoice, you need to create one first. You can [create an invoice in the Dashboard ](https://docs.stripe.com/invoicing/dashboard.md#create-invoice)or with the [Invoices API](https://docs.stripe.com/api/invoices/create.md). You can only update invoices in a [draft state](https://docs.stripe.com/invoicing/overview.md#invoice-lifecycle). ## Add line items To create multiple line items on the same invoice, reference the [invoice ID](https://docs.stripe.com/api/invoices/object.md#invoice_object-). You can also assign a preexisting unassigned invoice item with the [invoice item ID](https://docs.stripe.com/api/invoiceitems/object.md#invoiceitem_object-). Here’s how to create two new line items and assign an existing invoice item to this invoice. #### curl ```bash curl https://api.stripe.com/v1/invoices/{{INVOICE_ID}}/add_lines \ -u <>: \ -d "lines[0][amount]"=7500 \ -d "lines[0][currency]"="usd" \ -d "lines[1][price]"={{PRICE_ID}} \ -d "lines[1][description]"="New line item" \ -d "lines[2][invoice_item]"={{INVOICE_ITEM_1}} ``` > Ensure that you are using the invoice item ID, using a line item ID here will result in an error. ## Update line items From here, you can update multiple line items on the same invoice based on the invoice ID and line item IDs like the following: #### curl ```bash curl https://api.stripe.com/v1/invoices/{{INVOICE_ID}}/update_lines \ -u <>: \ -d "lines[0][id]"={{LINE_ITEM_1}} \ -d "lines[0][description]"="New description" \ -d "lines[0][metadata][key]"="new value" \ -d "lines[1][id]"={{LINE_ITEM_2}} \ -d "lines[1][price]"={{PRICE_ID}} \ -d "lines[2][id]"={{LINE_ITEM_3}} \ -d "lines[2][discountable]"=true ``` The example above updates the description and metadata for line item 1, the price for line item 2, and whether it’s discountable for line item 3. ## Remove line items You can delete or unassign multiple line items on the same invoice by referencing the invoice ID and line item IDs and distinguishing between different removal types with the `behavior` key. Here’s how to permanently delete `LINE_ITEM_1` and unassign `LINE_ITEM_2`. You can reassign `LINE_ITEM_2` to another invoice in another request. #### curl ```bash curl https://api.stripe.com/v1/invoices/{{INVOICE_ID}}/remove_lines \ -u <>: \ -d "lines[0][id]"={{LINE_ITEM_1}} \ -d "lines[0][behavior]"="delete" \ -d "lines[1][id]"={{LINE_ITEM_2}} \ -d "lines[1][behavior]"="unassign" ``` ## Restrictions There are some restrictions when using this feature - The invoice must still be in a draft state - There are two [types of invoice line items](https://docs.stripe.com/api/invoices/line_item.md#invoice_line_item_object-type) 1. `type: invoiceitem`: Generated when an [invoice item](https://docs.stripe.com/api/invoiceitems.md) is added to an invoice. 1. `type: subscription`: Automatically generated for a subscription invoice from each subscription item. This is the [full list of fields that are available](https://docs.stripe.com/api/invoices/update_lines.md#bulk_update_lines-lines) to update for each line item. While all fields are supported for `invoiceitem` line items, you can only update a small subset for `subscription` line items. Fields that are supported for `subscription` line items are `tax_rates`, or `discounts`. - You can update a maximum of 50 line items in one API call. This limit is subject to change and might increase or decrease. ## Invoice metadata You can set invoice metadata in the same request for any of the above endpoints. Here’s an example calling [update_lines](https://docs.stripe.com/api/invoices.md). #### curl ```bash curl https://api.stripe.com/v1/invoices/{{INVOICE_ID}}/update_lines \ -u <>: \ -d "lines[0][id]"={{LINE_ITEM_1}} \ -d "lines[0][description]"="New description" \ -d "lines[1][id]"={{LINE_ITEM_1}} \ -d "lines[2][description]"="Another description" \ -d "invoice_metadata[is_processed]"="true" ``` --- # Source: https://docs.stripe.com/atlas/business-taxes.md # Business taxes Business tax basics for startup founders. > #### Note > > Stripe Atlas doesn’t provide tax or legal accounting advice. Consult tax and legal professionals for advice on how to meet ongoing legal, tax, and accounting obligations that apply to you and your company. Companies formed in Delaware are subject to yearly tax obligations, including: - US federal and state corporate income tax as applicable. - Delaware franchise tax (for C corporations) or annual LLC tax (for Limited Liability Companies). - An annual tax if your company also operates in other US states. [Our partners](https://support.stripe.com/questions/legal-and-tax-advice-for-your-stripe-atlas-company) can help with meeting tax requirements for states outside Delaware. Review [key tax season dates](https://docs.stripe.com/atlas/business-taxes.md#tax-timing) to meet any tax deadlines that apply to your business. ## File US Income Tax The information you need to prepare your US income taxes depends on your company structure as [C corporations](https://docs.stripe.com/atlas/company-types.md?business-type=ccorp) and [LLCs](https://docs.stripe.com/atlas/company-types.md?business-type=llc) have different tax requirements. Before meeting with an accountant, gather your company’s year-end financial data as part of your [bookkeeping](https://stripe.com/atlas/guides/bookkeeping-and-accounting#what-is-bookkeeping-what-is-accounting) responsibilities. #### C corporation Be sure to have the following information for your corporation (as of the last day of the fiscal year that you’re filing for): - **General business information**: This includes your EIN. - **Company financials**: You can learn about year-end financial reports in our guide [tax season](https://stripe.com/atlas/guides/tax-season#before-you-speak-to-an-accountant). If you don’t have any revenue or expenses for the past fiscal year, you might still need to file taxes. - **Company ownership**: Your corporation might have shares held by individual shareholders or business entities. Make sure the information reflects the current ownership. - **Additional information**: If your company employs people, owns property, operates locally in the US, or operates abroad, you might have additional tax and reporting requirements. Some of the taxes you might want to ask about include: - Transfer pricing (if you’re based outside the US). - State taxes (if you have business activity in any US state). - Sales taxes. - Employment taxes. #### LLC Be sure to have the following information for your LLC as it stands on the last day of your filing fiscal year: - **General business information**: This includes your EIN. - **Company financials**: You can learn about year-end financial reports in our [guide to tax season](https://stripe.com/atlas/guides/tax-season#before-you-speak-to-an-accountant). - **Company ownership**: Your LLC might have multiple owners (“members”). Make sure the information reflects the current ownership. - **Additional information**: If your company employs people, owns property, operates locally in the US, or operates abroad, you might have additional tax and reporting requirements. Some of the taxes you might want to ask your accountant about include: - Transfer pricing (if you’re based outside the US). - State taxes (if you have business activity in any US state). - Sales taxes. - Employment taxes. If you’re still waiting for your EIN, you can enter **Applied For** and the application date (which you can find on your Form SS-4 in the Dashboard) in your tax forms. ## Tax partners Atlas partners with [startup-focused tax and accounting services](https://support.stripe.com/questions/legal-and-tax-advice-for-your-stripe-atlas-company) who can help you with corporate income taxes. These services offer discounts to Atlas users. ## File taxes in Delaware Your company’s tax and reporting obligations in Delaware depend on whether your company is a [C corporation](https://docs.stripe.com/atlas/company-types.md?business-type=ccorp) or an [LLC](https://docs.stripe.com/atlas/company-types.md?business-type=llc). #### C Corporation All Delaware C corporations are required to pay the Delaware franchise tax and to file an annual report, which you can [pay online](https://corp.delaware.gov/paytaxes/) if you want to complete it yourself. Even companies with no revenue in the previous fiscal year should expect to pay some amount. You can file this tax yourself, or work with one of our [tax partners](https://support.stripe.com/questions/legal-and-tax-advice-for-your-stripe-atlas-company), or a tax advisor of your choice. ### Delaware franchise tax You have the option to recalculate your taxes due on the Delaware website. Delaware sends notices using a calculation method that results in large tax bills for companies with more than 5,000 shares. Most Atlas companies find they pay less tax when they use the [Assumed Par Value Capital](https://corp.delaware.gov/frtaxcalc/) method instead of the default Authorized Shares method. You can read about [these methods](https://corp.delaware.gov/frtaxcalc.shtml) on Delaware’s website. If the franchise tax isn’t submitted by March 1 2026, there is a 200 USD late fee and interest of 1.5% per month on the tax amount originally due. #### Pay Delaware franchise tax Complete the following steps to pay your Delaware franchise tax. You can save your work and return to it later. Make sure to save your session number. The Delaware portal gives you the option of sending this number to an email address for easier access. - Login to [the state of Delaware’s website](https://icis.corp.delaware.gov/ecorp/logintax.aspx?FilingType=FranchiseTax) with your seven digit Delaware Business Entity File Number. - You can easily find your company’s file number in two ways: - Use [Delaware’s entity search tool](https://icis.corp.delaware.gov/ecorp/EntitySearch/NameSearch.aspx) with your company’s legal name. - Find the State of Delaware stamp on the second page of your Filed Certificate of Incorporation. You can find this in the [Dashboard](https://dashboard.stripe.com/atlas/company). - Click on the “File annual report” link. - Enter your company information: - Complete the Stock information section to adjust your taxes owed shown in the upper right corner: enter the number of shares your company has issued, your gross assets (your Total assets on your corporate income tax return), and your Asset date (the same as your end of fiscal year). Then click the Recalculate tax button (can take some time to reload). - Complete all of the remaining required fields indicated with a red star. - If you haven’t adjusted your list of officers or directors since you incorporated, you can find these individuals in your Board Approval document in your [Dashboard](https://dashboard.stripe.com/atlas/company). - When all required information is complete, press the green “Continue filing” button to review your information for accuracy. - After verifying your information is correct, click the green “Proceed” to payment button. - You can pay Delaware franchise tax and annual report filing fee either by credit card or ACH. - After entering your payment information, push the green “Submit” button to finalize your Delaware state taxes. #### LLC Delaware LLCs pay an annual LLC tax, sometimes referred to as the Business Entity Tax. You can file this tax yourself, or work with one of our [tax partners](https://support.stripe.com/questions/legal-and-tax-advice-for-your-stripe-atlas-company), or a tax advisor of your choice. ### Annual LLC tax All LLCs formed or registered in Delaware must pay an annual LLC tax, currently at a flat rate of 300 USD. There’s no requirement to file an annual report. If the annual LLC tax isn’t submitted by June 1 2025, there is a 200 USD penalty and interest of 1.5% per month on the tax amount (and penalty) originally due. #### Pay the annual Delaware LLC tax Complete the following steps to pay your annual Delaware LLC tax. You can save your work and return to it later. Make sure to save your session number. The Delaware portal gives you the option of sending this number to an email address for easier access. - Login to [the State of Delaware’s website](https://icis.corp.delaware.gov/ecorp/logintax.aspx?FilingType=FranchiseTax) with your seven digit Delaware Business Entity File Number. - You can find your company’s file number in two ways: - Use [Delaware’s entity search tool](https://icis.corp.delaware.gov/ecorp/EntitySearch/NameSearch.aspx) with your company’s legal name. - Find the State of Delaware stamp on page 2 of your Filed Certificate of Incorporation, accessible in your [Dashboard](https://dashboard.stripe.com/atlas/company). - Click the green **Pay taxes** button. You should see a flat 300 USD fee for LLCs. - You can pay your Delaware LLC tax fee either by credit card or ACH. - After entering your payment information, click the green **Submit** button to finalize your Delaware state taxes. ## State taxes beyond Delaware If your company operates in any US states other than Delaware, it might be subject to annual taxation, registration, and reporting requirements in the other states. [Our partners](https://support.stripe.com/questions/legal-and-tax-advice-for-your-stripe-atlas-company) can help you understand the requirements that apply to your business. ## 2026 key tax season dates Plan ahead to meet any tax deadlines that apply to your business. Refer to the following information if your company was active in 2025. #### C Corporation - March 1, 2026: [Delaware franchise tax](https://docs.stripe.com/atlas/business-taxes.md#file-delaware-tax) due (penalty for late payments: $200 fee and interest of 1.5% per month on the tax amount originally due). - April 15, 2026: [US federal corporate income tax](https://docs.stripe.com/atlas/business-taxes.md?business-type=ccorp#file-us-corp-tax) due date. - October 15, 2026: If you filed for an extension, this is the due date for filing [US corporate income taxes](https://docs.stripe.com/atlas/business-taxes.md#file-us-corp-tax). #### LLC - March 15, 2026: [US LLC partnership income tax](https://docs.stripe.com/atlas/business-taxes.md?business-type=llc) due, or due date to submit an extension to file taxes later in the year. - April 15, 2026: US individual income tax due date. - June 1, 2026: [Delaware annual LLC tax](https://docs.stripe.com/atlas/business-taxes.md?business-type=llc#annual-llc-tax) due. - September 15, 2026: If you filed for an extension, this is the due date for filing [US LLC partnership income tax](https://docs.stripe.com/atlas/business-taxes.md?business-type=llc). If your US company has employees or makes payments to US vendors, you might also be required to file a US W-2 or 1099 form by January 31, 2026. ### Tax obligations when dissolving your company Even if you are no longer operating your company, you might need to file taxes annually until you officially dissolve your company. Dissolution itself might trigger final tax obligations. Our [tax partners](https://support.stripe.com/questions/legal-and-tax-advice-for-your-stripe-atlas-company) can help determine your specific requirements. C corporations need to pay franchise tax and file an annual report before dissolution. LLCs can be dissolved only after they pay the annual LLC tax (no annual report is required). To start the dissolution process, visit the [Company tab](https://dashboard.stripe.com/atlas/company) in your Atlas Dashboard. Consider consulting a lawyer to ensure your company is fully dissolved. ## See also - [Tax season guide](https://stripe.com/atlas/guides/tax-season) - [Business taxes guide](https://stripe.com/atlas/guides/business-taxes) - [Bookkeeping and accounting guide](https://stripe.com/guides/atlas/bookkeeping-and-accounting) - [State of Delaware’s tax FAQ](https://corp.delaware.gov/taxfaq/) --- # Source: https://docs.stripe.com/payment-links/buy-button.md # Create an embeddable buy button Use Payment Links to create an embeddable buy button for your website. Create an embeddable buy button to sell a product, subscription, or accept a payment on your website. Start by selecting an existing link from the [Payment Links list view](https://dashboard.stripe.com/payment-links) or by [creating a new link](https://dashboard.stripe.com/payment-links/create) where you can decide which products to sell and customize the checkout UI. After you create your link, click **Buy button** to configure the buy button design and generate the code that you can copy and paste into your website. ## Customize the button By default, your buy button uses the same branding and call to action configured for your payment link. You can: - Choose between a simple button and a card widget. - Set brand colors, shapes, and fonts to match your website. - Set the language of the button and payment page to match your website’s language. - Customize your button’s call to action. ![Customize the buy button](https://b.stripecdn.com/docs-statics-srv/assets/buy-button-card-layout.4003c3e9ffe3ce4378092dbdcd456ed9.png) Customize the buy button ## Embed the button Stripe provides an embed code composed of a ` ``` #### React ```html ``` ```jsx import * as React from 'react'; function BuyButtonComponent() { // Paste the stripe-buy-button snippet in your React component return ( ); } export default BuyButtonComponent; ``` ## Attributes to customize checkout | Parameter | Description | Syntax | | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `client-reference-id` | Use `client-reference-id` to attach a unique string of your choice to the Checkout Session. The string can be a customer ID or a cart ID (or similar) that you use to reconcile the Session with your internal systems. If you pass this parameter to your ``, it’s sent in the [checkout.session.completed webhook](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) upon payment completion. | The `client-reference-id` can contain alphanumeric characters, dashes, or underscores, and be any value up to 200 characters. Invalid values are silently dropped, but your payment page continues to work as expected. | | `customer-email` | Use `customer-email` to prefill the email address on the payment page. When the property is set, the buy button passes it to the Checkout Session’s `customer_email` attribute. The customer can’t edit the email address on the payment page. | The `customer-email` must be a valid email. Invalid values are silently dropped, but your payment pages continues to work as expected. | | `customer-session-client-secret` | Use `customer-session-client-secret` to pass an existing [Customer](https://docs.stripe.com/api/customers.md) object. See the section below for more information. | The `customer-session-client-secret` value must be generated from the [client_secret](https://docs.stripe.com/api/customer_sessions/object.md#customer_session_object-client_secret). | > #### Compare Customers v1 and Accounts v2 references > > If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. ## Pass an existing customer You can provide an existing [Customer](https://docs.stripe.com/api/customers.md) object to `Checkout Sessions` created from the buy button. Create a `CustomerSession` for a customer you’ve already authenticated server-side, and return the [client_secret](https://docs.stripe.com/api/customer_sessions/object.md#customer_session_object-client_secret) to the client. ```curl curl https://api.stripe.com/v1/customer_sessions \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "components[buy_button][enabled]"=true ``` ```cli stripe customer_sessions create \ --customer="{{CUSTOMER_ID}}" \ -d "components[buy_button][enabled]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer_session = client.v1.customer_sessions.create({ customer: '{{CUSTOMER_ID}}', components: {buy_button: {enabled: true}}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer_session = client.v1.customer_sessions.create({ "customer": "{{CUSTOMER_ID}}", "components": {"buy_button": {"enabled": True}}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $customerSession = $stripe->customerSessions->create([ 'customer' => '{{CUSTOMER_ID}}', 'components' => ['buy_button' => ['enabled' => true]], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CustomerSessionCreateParams params = CustomerSessionCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .setComponents( CustomerSessionCreateParams.Components.builder() .setBuyButton( CustomerSessionCreateParams.Components.BuyButton.builder() .setEnabled(true) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. CustomerSession customerSession = client.v1().customerSessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const customerSession = await stripe.customerSessions.create({ customer: '{{CUSTOMER_ID}}', components: { buy_button: { enabled: true, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerSessionCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), Components: &stripe.CustomerSessionCreateComponentsParams{ BuyButton: &stripe.CustomerSessionCreateComponentsBuyButtonParams{ Enabled: stripe.Bool(true), }, }, } result, err := sc.V1CustomerSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CustomerSessionCreateOptions { Customer = "{{CUSTOMER_ID}}", Components = new CustomerSessionComponentsOptions { BuyButton = new CustomerSessionComponentsBuyButtonOptions { Enabled = true }, }, }; var client = new StripeClient("<>"); var service = client.V1.CustomerSessions; CustomerSession customerSession = service.Create(options); ``` Set the `customer-session-client-secret` attribute on the `` web component to the [client_secret](https://docs.stripe.com/api/customer_sessions/object.md#customer_session_object-client_secret) from the Customer Session. You must provide the [client_secret](https://docs.stripe.com/api/customer_sessions/object.md#customer_session_object-client_secret) within 30 minutes. After providing the client secret, you have an additional 30 minutes until the `Customer Session` expires. Any resulting `Checkout Sessions` created from the buy button will fail. Don’t cache the client secret, instead generate a new one every time you render each buy button. #### HTML ```html ``` #### React ```jsx import * as React from 'react'; function BuyButtonComponent() { return ( ); } export default BuyButtonComponent; ``` ## Content Security Policy If you’ve deployed a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), the policy directives that the buy button requires are: - frame-src, https://js.stripe.com - script-src, https://js.stripe.com ## Limitations Rendering the buy button requires a website domain. To test the buy button locally, run a local HTTP server to host your website’s `index.html` file over the localhost domain. To run a local HTTP server, use Python’s [SimpleHTTPServer](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server#running_a_simple_local_http_server) or the [http-server](https://www.npmjs.com/package/http-server) npm module. ## Track payments After your customer makes a payment using a payment link, you can see it in the [payments overview](https://dashboard.stripe.com/payments) in the Dashboard. If you’re new to Stripe, you’ll receive an email after your first payment. To receive emails for all successful payments, update your notification preferences in your [Personal details](https://dashboard.stripe.com/settings/user) settings. Stripe creates a new [guest customer](https://docs.stripe.com/payments/checkout/guest-customers.md) for one-time payments and a new [Customer](https://docs.stripe.com/api/customers.md) object when selling a subscription or [saving a payment method for future use](https://docs.stripe.com/payment-links/customize.md#save-payment-details-for-future-use). Learn more about handling [payment links post-payment](https://docs.stripe.com/payment-links/post-payment.md), like how to configure post-payment behavior for a buy button or payment link. --- # Source: https://docs.stripe.com/payments/buy-now-pay-later.md # Buy now, pay later Learn about buy now, pay later methods with Stripe. You can also use subscription schedules to set up [installment plans](https://docs.stripe.com/billing/subscriptions/subscription-schedules.md#installment-plans). Learn more about other options for [accepting payments in installments](https://docs.stripe.com/recurring-payments.md#installment-plans). Buy now, pay later methods let customers pay in installments over time. You’re paid immediately and in full and your customers pay nothing or a portion of the total at purchase time. Buy now, pay later methods are often used by: - Retailers selling high value goods and services like luxury items or travel fares that want to increase conversion. - Retailers selling low value goods and services that want to increase average cart size and reach new customers who might not have credit cards. - Regional banks that allow consumers to split credit card payments over multiple billing cycles. Read our [Buy Now, Pay Later Guide](https://stripe.com/guides/buy-now-pay-later) for more information. ## Get started You don’t have to integrate buy now, pay later payment methods individually. [Dynamic payment methods](https://docs.stripe.com/payments/payment-methods/dynamic-payment-methods.md) are enabled by default and let you configure payment methods in the [Dashboard](https://dashboard.stripe.com/settings/payment_methods) without writing code. Stripe handles the logic for dynamically displaying the most relevant eligible payment methods to each customer. You can use dynamic payment methods with [standard Checkout integrations](https://docs.stripe.com/payments/checkout.md). Get started by: - [Creating a Stripe-hosted page](https://docs.stripe.com/checkout/quickstart.md) - [Embedding a payment form on your site](https://docs.stripe.com/checkout/embedded/quickstart.md) - [Building a checkout page with embedded components](https://docs.stripe.com/payments/quickstart-checkout-sessions.md) - [Using the Hosted Invoice Page](https://docs.stripe.com/invoicing/hosted-invoice-page.md) You can manually list buy now, pay later payment methods if you build your own payments form. Read the docs for the specific payment method to understand how to add it to your integration. ## Payments In the buy now, pay later checkout process, the customer: 1. Chooses to pay by installments with a buy now, pay later service. 1. Creates or logs into an account with the buy now, pay later provider. 1. Accepts or declines the terms of the repayment plan. 1. Returns to the business’ site. ## Product support | Payment method | [Connect](https://docs.stripe.com/connect.md) | [Checkout](https://docs.stripe.com/payments/checkout.md) | [Payment Links](https://docs.stripe.com/payment-links.md) | [Payment Element](https://docs.stripe.com/payments/payment-element.md) | [Express Checkout Element](https://docs.stripe.com/elements/express-checkout-element.md) | [Mobile Payment Element](https://docs.stripe.com/payments/mobile.md) | [Subscriptions](https://docs.stripe.com/subscriptions.md) | [Invoicing](https://docs.stripe.com/invoicing.md) | [Customer Portal](https://docs.stripe.com/customer-management.md) | [Terminal](https://docs.stripe.com/terminal.md) | | -------------------------------------------------------------------------- | --------------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------------- | | [Affirm](https://docs.stripe.com/payments/affirm.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported 4 | ✓ Supported | - Unsupported | ✓ Supported | | [Afterpay/Clearpay](https://docs.stripe.com/payments/afterpay-clearpay.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | - Unsupported | (Private preview) | - Unsupported | - Unsupported | | [Alma](https://docs.stripe.com/payments/alma.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | | [Billie](https://docs.stripe.com/payments/billie.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | | [Capchase Pay](https://docs.stripe.com/payments/capchase-pay.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | | [Klarna](https://docs.stripe.com/payments/klarna.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | ✓ Supported3 | ✓ Supported | ✓ Supported 4 | ✓ Supported | - Unsupported | - Unsupported | | [Kriya](https://docs.stripe.com/payments/kriya.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | | [Mondu](https://docs.stripe.com/payments/mondu.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | | [Scalapay](https://docs.stripe.com/payments/scalapay.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | | [SeQura](https://docs.stripe.com/payments/sequra.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | | [Sunbit](https://docs.stripe.com/payments/sunbit.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | | [Zip](https://docs.stripe.com/payments/zip.md) | ✓ Supported | ✓ Supported 1,2 | ✓ Supported | ✓ Supported | - Unsupported | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | - Unsupported | 1 Not supported when using Checkout in subscription mode.2 Not supported when using Checkout in setup mode.3 Not supported when saving payment details during payment (`setup_future_usage`).4 Invoices and Subscriptions only support the [send_invoice](https://docs.stripe.com/api/invoices/object.md#invoice_object-collection_method) collection method. ## API support | Payment method | API enum | [PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) | [SetupIntents](https://docs.stripe.com/payments/setup-intents.md) | [Manual capture](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md) | [Setup future usage](https://docs.stripe.com/payments/save-during-payment.md?platform=web&ui=elements)1 | Requires redirect2 | | -------------------------------------------------------------------------- | ------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------ | | [Affirm](https://docs.stripe.com/payments/affirm.md) | `affirm` | ✓ Supported | - Unsupported | ✓ Supported | - Unsupported | Yes | | [Afterpay/Clearpay](https://docs.stripe.com/payments/afterpay-clearpay.md) | `afterpay_clearpay` | ✓ Supported | - Unsupported | ✓ Supported | - Unsupported | Yes | | [Alma](https://docs.stripe.com/payments/alma.md) | `alma` | ✓ Supported | - Unsupported | ✓ Supported | - Unsupported | Yes | | [Billie](https://docs.stripe.com/payments/billie.md) | `billie` | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported | Yes | | [Capchase Pay](https://docs.stripe.com/payments/capchase-pay.md) | `capchase_pay` | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported | Yes | | [Klarna](https://docs.stripe.com/payments/klarna.md) | `klarna` | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | Yes | | [Kriya](https://docs.stripe.com/payments/kriya.md) | `kriya` | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported | Yes | | [Mondu](https://docs.stripe.com/payments/mondu.md) | `mondu` | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported | Yes | | [SeQura](https://docs.stripe.com/payments/sequra.md) | `sequra` | ✓ Supported | - Unsupported | ✓ Supported | ✓ Supported | Yes | | [Sunbit](https://docs.stripe.com/payments/sunbit.md) | `sunbit` | ✓ Supported | - Unsupported | - Unsupported | ✓ Supported | Yes | | [Zip](https://docs.stripe.com/payments/zip.md) | `zip` | ✓ Supported | - Unsupported | - Unsupported | - Unsupported | Yes | 1 Cards and bank debit methods including SEPA debit, AU BECS direct debit, and ACSS debit support both `on_session` and `off_session` with [setup future usage](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-setup_future_usage). All other payment method types either don’t support `setup_future_usage` or only support `off_session`.2 Payment methods might require confirmation with [return_url](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-return_url) to indicate where Stripe should redirect your customer after they complete the payment. ## Transaction support | Payment method | Customer country | Repayment options | Transaction limit | | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | [Affirm](https://docs.stripe.com/payments/affirm.md)1 | Canada, United States | - Pay in 4 interest-free installments - Monthly payments for up to 36 months | 50 USD minimum; 30,000 USD maximum or local equivalent- | | [Afterpay/Clearpay](https://docs.stripe.com/payments/afterpay-clearpay.md) | Australia, Canada, New Zealand, United Kingdom, United States | - Pay in 4 interest-free installments - Monthly USD payments for up to 12 months | 1 USD minimum; 4,000 USD maximum or local equivalent | | [Klarna](https://docs.stripe.com/payments/klarna.md) | Australia, Austria, Belgium, Canada, Czechia, Denmark, Finland, France, Germany, Greece, Ireland, Italy, Netherlands, New Zealand, Norway, Poland, Portugal, Spain, Sweden, Switzerland, United Kingdom, United States | - Pay in 3 or 4 interest-free installments - Pay in 30 days - Pay in full with stored payment details - Monthly payments for up to 36 months | 10 USD minimum or local equivalent. (Amounts over 5,000 USD for financing possible; maximum varies by customer) | | [Meses sin intereses](https://docs.stripe.com/payments/mx-installments.md) | Mexico | Extend payments over 3 to 24 months of billing cycles | [Minimum transaction](https://docs.stripe.com/payments/mx-installments.md#fees) amount of 100 MXN per month of extension | | [Zip](https://docs.stripe.com/payments/zip.md)2 | Australia, United States | - Zip Pay: Pay using a 1,000 AUD credit, repay in your own time - Zip Money: Pay in a minimum of 3 monthly interest-free installments - Pay in 4 installments | 0.01 AUD minimum. 50,000 AUD maximum for Australia or 35 USD minimum and 1,500 USD maximum for United States** | 1 The maximum credit limit for Affirm is 20,000 USD or 20,000 CAD. However, Affirm supports transactions up to 30,000 USD or 30,000 CAD. These transactions require a down payment from the customer at time of purchase. Term lengths and cart ranges are determined by Affirm and may change at their discretion.2 Zip Australia offers two products, Zip Pay with a credit limit of 1,000 AUD and Zip Money with a maximum credit limit of 50,000 AUD depending on the users’ eligibility. Zip US offers Pay in 4 with transactions up to 1,500 USD. ## Adding on site messaging to your website Let your customers know you accept one or more of these payment methods by including the [Payment Method Messaging Element](https://docs.stripe.com/elements/payment-method-messaging.md) on your product and cart pages. --- # Source: https://docs.stripe.com/tax/calculating.md # Calculate tax Learn how to calculate tax with Stripe Tax. The most common forms of indirect taxes for your business are sales tax, *VAT* (A value-added tax (VAT), known in some countries as a goods and services tax (GST), is a type of tax levied on the price of a product or service at each stage of production, distribution, or sale to the end consumer. VAT and GST are also generally known as "consumption" taxes. The buyer pays the tax and the seller forwards it to the government), and *GST* (A goods and services tax (GST), known in some countries as a value added tax (VAT), is a type of tax levied on the price of a product or service at each stage of production, distribution, or sale to the end consumer. GST and VAT are also generally known as "consumption" taxes. The buyer pays the tax and the seller forwards it to the government). These taxes apply on the sale of physical goods, digital goods, and services. Stripe calculates tax on a transaction taking into account some or all of the following factors: - The location of the seller - The location of the customer - The location where the activity is performed - The type of the product sold - Whether the transaction involves a [reverse charge](https://docs.stripe.com/tax/zero-tax.md#reverse-charges) - The status of the customer (for example, whether they’re a VAT-registered business, private person or an exempt organization) ## Payment methods Stripe calculates tax for all supported payment methods, including Apple Pay and Google Pay wallet transactions. ## How Stripe uses addresses Stripe uses a single address as the customer’s location, or transaction destination, when calculating taxes. For more information, see [which customer address we use](https://docs.stripe.com/tax/customer-locations.md#address-hierarchy). In certain scenarios, it’s important to identify the origin of a transaction. Stripe generally uses the address where your business is located as the origin of a transaction. This address is defined as your head office address in the Dashboard or as `head_office` if using the tax settings object. You can also specify a performance location to calculate tax based on a location that differs from both your head office address and your customer’s address. For example, you might deliver products to your customer at a store, or sell tickets to an event or activity. ### How to use ship-from addresses You can add ship-from addresses that differ from your business address for tax calculation. To add them, use the `ship_from_address` transaction object. You can add ship-from locations only using the [Stripe Tax API](https://docs.stripe.com/tax/custom.md). They aren’t available in integrations of Stripe Tax with Payment Links, Checkout, or Billing and Invoicing. If you enter an unrecognized ship-from address, Stripe returns a `shipping_address_invalid` error. Stripe Tax can designate only one address as the origin of a transaction even though in some countries the determination of origin can vary by product type. If you provide the ship-from address, Stripe Tax uses it to calculate tax for both services and physical goods. If you don’t provide a ship-from address, Stripe Tax assumes that the origin of the transaction is the address where your business is located. When selling a combination of products that require different origin locations, consider splitting the transaction accordingly. ### How to use performance location You can calculate taxes based on [performance location addresses](https://docs.stripe.com/tax/tax-for-tickets/overview.md) that differ from your business address and your customer’s address. If you provide a performance location, Stripe Tax uses its address as the place of taxation for physical goods, services and events. To use performance locations: - You must define performance locations through the Stripe Tax API. - You can’t use performance locations with Payment Links, Checkout, or Billing and Invoicing. - Unrecognized performance location addresses return a tax calculation error. - You can’t use performance locations for digital product tax codes. - Some [product tax codes](https://docs.stripe.com/tax/tax-codes.md) **require** the performance location. Even if you provide a performance location, the business address and the customer address remain relevant in determining whether reverse charges might apply. ## Discounts and tax calculations Stripe Tax calculates tax after applying discounts to the subtotal. This ensures tax calculation on the actual amount paid by the customer. For example, with a product priced at 150 USD and a 20 USD discount: 1. The subtotal after discount is 130 USD. 1. Tax is calculated on the 130 USD amount. 1. The final total is the discounted subtotal plus the calculated tax. Discounts don’t affect the tax rates themselves, only the amount on which tax is calculated. When using the Tax API, calculate the discount before sending the request. ## Tax breakdowns Stripe Tax provides detailed tax breakdowns for each transaction. These breakdowns aren’t sorted in any specific order. All applicable taxes are calculated and applied simultaneously. The order of items in the breakdown doesn’t indicate priority or application sequence. [Specify product tax codes and tax behavior](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md): Learn how to set up products and prices to automatically calculate tax. [Collect customer addresses](https://docs.stripe.com/tax/customer-locations.md): Learn how to collect customer addresses to automatically calculate tax. [Zero tax amounts and reverse charges](https://docs.stripe.com/tax/zero-tax.md): Learn about cases when Stripe calculates zero tax. [Customize tax behavior](https://docs.stripe.com/tax/tax-customizations.md): Set up Tax to fit your business needs with tax customizations. [Countries supported by Stripe Tax](https://docs.stripe.com/tax/supported-countries.md): Learn how to use Stripe to calculate, collect, and report tax in different countries --- # Source: https://docs.stripe.com/billing/subscriptions/cancel.md # Cancel subscriptions Learn how to cancel existing subscriptions. Customers can also manage their subscriptions, invoices, and billing information through the Stripe-hosted [customer portal cancellation page](https://docs.stripe.com/customer-management/cancellation-page.md). This guide describes how to use the [Subscription API](https://docs.stripe.com/api.md#cancel_subscription) or the [Dashboard](https://dashboard.stripe.com/test/subscriptions) to manage customer subscriptions. If you want to keep a subscription active but temporarily stop collecting payment, you can [pause payment collection](https://docs.stripe.com/billing/subscriptions/pause-payment.md). Pausing payment collection doesn’t affect the [subscription status](https://docs.stripe.com/billing/subscriptions/overview.md#subscription-statuses), which we recommend using as the trigger for starting or stopping service to your customer. *Subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) cancel automatically after up to eight unsuccessful attempts to bill the customer. You can configure the number of attempts in your Dashboard [subscription settings](https://dashboard.stripe.com/settings/billing/automatic). Learn more about revenue recovery settings, such as [Smart Retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries.md#smart-retries) and configurable [customer emails](https://docs.stripe.com/billing/revenue-recovery/customer-emails.md#configure-emails). ## Cancel subscriptions You can cancel customer subscriptions manually with the [API](https://docs.stripe.com/api/subscriptions/cancel.md) or in the [Dashboard](https://dashboard.stripe.com/test/subscriptions). By default, cancellation takes effect immediately and *invoices* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) are no longer generated for canceled subscriptions. After it’s canceled, you can no longer update the subscription or its [metadata](https://docs.stripe.com/metadata.md). > If you set a custom cancellation date, you can’t provide a refund. A credit proration is always generated. To prevent a credit proration from generating, make sure the custom cancellation date is within the current billing period and `proration_behavior` is set to `none`. #### Dashboard To cancel a subscription in the Dashboard: 1. From the [Subscriptions](https://dashboard.stripe.com/test/subscriptions) page, click the overflow menu (⋯), then select **Cancel subscription**. 1. Choose when to end the subscription: immediately, at the end of the period, or on a custom day. 1. Choose to provide a refund for a [prorated](https://docs.stripe.com/billing/subscriptions/prorations.md) amount, refund the last payment in full, or provide no [refund](https://docs.stripe.com/refunds.md). 1. After finalizing all settings, click **Cancel subscription**. #### API To cancel a subscription using the API: ```curl curl -X DELETE https://api.stripe.com/v1/subscriptions/{{SUBSCRIPTION_ID}} \ -u "<>:" ``` ```cli stripe subscriptions cancel {{SUBSCRIPTION_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.cancel('{{SUBSCRIPTION_ID}}') ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.cancel("{{SUBSCRIPTION_ID}}") ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->cancel('{{SUBSCRIPTION_ID}}', []); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionCancelParams params = SubscriptionCancelParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().cancel("{{SUBSCRIPTION_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.cancel('{{SUBSCRIPTION_ID}}'); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionCancelParams{} result, err := sc.V1Subscriptions.Cancel( context.TODO(), "{{SUBSCRIPTION_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Cancel("{{SUBSCRIPTION_ID}}"); ``` ### Prorate for usage-based billing If a subscription is part of the way through a paid billing period, you can prorate the cancellation by passing the [prorate](https://docs.stripe.com/api/subscriptions/cancel.md#cancel_subscription-prorate) parameter. When you prorate a cancellation, you can optionally invoice for: - Outstanding prorations - [Metered usage](https://docs.stripe.com/products-prices/pricing-models.md#usage-based-pricing) If you don’t prorate the subscription, all metered usage gets discarded and the customer won’t receive credit for any potential prorations. Create a final invoice immediately using the [invoice_now](https://docs.stripe.com/api/subscriptions/cancel.md#cancel_subscription-invoice_now) parameter. If you owe the customer a credit after cancellation, you can add the credit to their credit balance to apply to future invoices. To [refund your customer](https://support.stripe.com/questions/refunding-credit-balance-to-customer-after-subscription-downgrade-or-cancellation), issue [refunds](https://docs.stripe.com/refunds.md#issuing) and then [adjust their account balance](https://docs.stripe.com/billing/customer/balance.md#modifying) back to zero. ### Cancel at the end of the current billing period To cancel a subscription at the end of the current billing period, set `cancel_at_period_end` to `true`: ```curl curl https://api.stripe.com/v1/subscriptions/{{SUBSCRIPTION_ID}} \ -u "<>:" \ -d cancel_at_period_end=true ``` ```cli stripe subscriptions update {{SUBSCRIPTION_ID}} \ --cancel-at-period-end=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.update( '{{SUBSCRIPTION_ID}}', {cancel_at_period_end: true}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.update( "{{SUBSCRIPTION_ID}}", {"cancel_at_period_end": True}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->update( '{{SUBSCRIPTION_ID}}', ['cancel_at_period_end' => true] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionUpdateParams params = SubscriptionUpdateParams.builder().setCancelAtPeriodEnd(true).build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().update("{{SUBSCRIPTION_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.update( '{{SUBSCRIPTION_ID}}', { cancel_at_period_end: true, } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionUpdateParams{CancelAtPeriodEnd: stripe.Bool(true)} result, err := sc.V1Subscriptions.Update( context.TODO(), "{{SUBSCRIPTION_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionUpdateOptions { CancelAtPeriodEnd = true }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Update("{{SUBSCRIPTION_ID}}", options); ``` This allows the subscription to complete the duration of time the customer has already paid for. You can reactivate subscriptions scheduled for cancellation by updating `cancel_at_period_end` to `false`. You can reactivate the subscription at any time up to the end of the period. ### Cancel after scheduled changes or future billing periods To schedule a subscription to end after a specified number of billing periods, [create a subscription schedule](https://docs.stripe.com/billing/subscriptions/subscription-schedules.md). Set the schedule length by specifying one or more phases and intervals, and set its [end_behavior](https://docs.stripe.com/api/subscription_schedules/create.md#create_subscription_schedule-end_behavior) attribute to `cancel`. With an end behavior of `cancel`, subscription schedules automatically manage the subscription’s [cancel_at](https://docs.stripe.com/billing/subscriptions/cancel.md#custom-cancel-date) attribute. When the schedule is in its last phase, the subscription’s cancel date is set to the phase’s end date, otherwise, the cancel date isn’t set on the subscription. As a result, adding a new phase to a schedule that’s currently in its last phase removes the cancel date. If the subscription is in its last billing period when extending or removing the cancel date, this might update the period end and billing cycle anchor. See how to [set a custom cancel date](https://docs.stripe.com/billing/subscriptions/cancel.md#custom-cancel-date) for more details. ### Configure automatic cancellation after a dispute > #### Limited support > > This feature is only supported for disputed credit and debit card payments opened in the *full amount*. The delay for any automatic cancellation isn’t compatible with [test clocks](https://docs.stripe.com/billing/testing/test-clocks/simulate-subscriptions.md). When a customer [disputes](https://docs.stripe.com/disputes.md) a charge for a subscription, the subscription continues to cycle, which can create more disputed charges. You can change this behavior in the [Dashboard](https://dashboard.stripe.com/settings/billing/automatic) to cancel subscriptions instead. Changes to the subscription take effect after approximately one hour. Under [Manage disputed payments](https://dashboard.stripe.com/settings/billing/automatic), select one of the following: - **cancel the subscription immediately without prorating** – The subscription cancels immediately without any prorating. You can’t restart a canceled subscription. You must create a new subscription for the customer if you want to continue billing them. - **cancel the subscription at the end of the period** – The subscription cancels at the end of the current billing period and [cancel_at_period_end](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-cancel_at_period_end) is set to `true`. This allows you time to work through the dispute process before the cancellation occurs. For subscriptions managed with [schedules](https://docs.stripe.com/billing/subscriptions/subscription-schedules.md), the subscription is first released from the schedule and then canceled. This means the rest of the scheduled changes won’t take effect. ## Handle invoice items when canceling subscriptions Your customer might still be billed for pending [invoice items](https://docs.stripe.com/billing/invoices/subscription.md#adding-draft-invoice-items) on a subscription in the following cases: - The subscription cancellation includes a final invoice - Your customer has another active subscription To prevent billing your customer for pending invoice items, you must [manually delete](https://docs.stripe.com/api.md#delete_invoiceitem) the invoice items. Similarly, any [usage](https://docs.stripe.com/billing/subscriptions/usage-based/recording-usage.md) reported during the billing period bills at the end of the period. To avoid a final usage charge, use the [clear_usage](https://docs.stripe.com/api.md#update_subscription-items-clear_usage) parameter to [update the subscription](https://docs.stripe.com/api.md#update_subscription) and remove the metered price. If you set the subscription to cancel at period end, any pending prorations are left in place and still collected at the end of the period. If you cancel the subscription before the end of the period, invoice items remain and won’t be processed unless you specifically generate an invoice that includes them. When you cancel a subscription, all `open` and `draft` invoices for that subscription have their `auto_advance` property set to `false`. This [pauses automatic collection](https://docs.stripe.com/invoicing/integration/automatic-advancement-collection.md) for these invoices and prevents automatic reminder emails from sending. You can still manually attempt to collect payment and send emails. ## Identify cancellation events Stripe sends the following events for canceled subscriptions. | Event | Description | | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `customer.subscription.updated` | Sent for any subscription update, including when `cancel_at_period_end` is set to `true`. | | `customer.subscription.deleted` | Sent when a subscription is canceled. The cancellation can result from a direct call to delete the subscription or when a subscription with `cancel_at_period_end: true` reaches the end of its billing period. | ## Stop a pending cancellation You can stop a scheduled cancellation through the [Update Subscription API](https://docs.stripe.com/api/subscriptions/update.md) or the [Dashboard](https://dashboard.stripe.com/test/subscriptions). You can’t reactivate a canceled subscription. #### Dashboard To stop a scheduled cancellation in the Dashboard: 1. On the [Subscriptions page](https://dashboard.stripe.com/test/subscriptions), select the subscription you want to update. 1. From the Subscription details page, click **Actions**, then select **Don’t cancel**. #### API To stop a scheduled cancellation using the API, set `cancel_at_period_end` to `false`. This action only affects subscriptions that haven’t reached the end of their billing period. ```curl curl https://api.stripe.com/v1/subscriptions/{{SUBSCRIPTION_ID}} \ -u "<>:" \ -d cancel_at_period_end=false ``` ```cli stripe subscriptions update {{SUBSCRIPTION_ID}} \ --cancel-at-period-end=false ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.update( '{{SUBSCRIPTION_ID}}', {cancel_at_period_end: false}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.update( "{{SUBSCRIPTION_ID}}", {"cancel_at_period_end": False}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->update( '{{SUBSCRIPTION_ID}}', ['cancel_at_period_end' => false] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionUpdateParams params = SubscriptionUpdateParams.builder().setCancelAtPeriodEnd(false).build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().update("{{SUBSCRIPTION_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.update( '{{SUBSCRIPTION_ID}}', { cancel_at_period_end: false, } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionUpdateParams{CancelAtPeriodEnd: stripe.Bool(false)} result, err := sc.V1Subscriptions.Update( context.TODO(), "{{SUBSCRIPTION_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionUpdateOptions { CancelAtPeriodEnd = false }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Update("{{SUBSCRIPTION_ID}}", options); ``` > Prior to version [2018-02-28](https://docs.stripe.com/upgrades.md#2018-02-28), *any* parameter sent to the [Update Subscription](https://docs.stripe.com/api/subscriptions/update.md) stops a pending cancellation. ## Set a custom cancel date Use the [cancel_at](https://docs.stripe.com/api/subscriptions/update.md#update_subscription-cancel_at) parameter to cancel a subscription at a future timestamp. ```curl curl https://api.stripe.com/v1/subscriptions/{{SUBSCRIPTION_ID}} \ -u "<>:" \ -d cancel_at=1723766400 ``` ```cli stripe subscriptions update {{SUBSCRIPTION_ID}} \ --cancel-at=1723766400 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.update( '{{SUBSCRIPTION_ID}}', {cancel_at: 1723766400}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.update( "{{SUBSCRIPTION_ID}}", {"cancel_at": 1723766400}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->update( '{{SUBSCRIPTION_ID}}', ['cancel_at' => 1723766400] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionUpdateParams params = SubscriptionUpdateParams.builder().setCancelAt(1723766400L).build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().update("{{SUBSCRIPTION_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.update( '{{SUBSCRIPTION_ID}}', { cancel_at: 1723766400, } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionUpdateParams{CancelAt: stripe.Int64(1723766400)} result, err := sc.V1Subscriptions.Update( context.TODO(), "{{SUBSCRIPTION_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionUpdateOptions { CancelAt = DateTimeOffset.FromUnixTimeSeconds(1723766400).UtcDateTime, }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Update("{{SUBSCRIPTION_ID}}", options); ``` When you schedule a cancel date that occurs before the billing period ends, the subscription’s items’ [current_period_end](https://docs.stripe.com/api/subscription_item/object.md#subscription_item_object-current_period_end) updates to match the `cancel_at` date. This creates prorations for the change in the current period, unless your update [disables](https://docs.stripe.com/billing/subscriptions/prorations.md#disable-prorations) prorations. For `billing_mode=flexible` subscriptions with `status=trialing`, adding, updating, or removing the `cancel_at` value doesn’t affect the [trial_end](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-trial_end) date. For subscriptions using [billing_mode](https://docs.stripe.com/api/subscriptions/create.md?api-version=2025-04-30.preview#create_subscription-billing_mode), you can use enum helpers with the `cancel_at` parameter to simplify canceling a subscription at the end of a billing period. The `min_period_end` and `max_period_end` helpers allow you to specify when to cancel a subscription based on the billing periods for all subscription items. | Event | Description | | ---------------- | ---------------------------------------------------------------- | | `min_period_end` | Selects the timestamp for the billing period that ends earliest. | | `max_period_end` | Selects the timestamp for the billing period that ends last. | These helpers resolve timestamps immediately, reducing the risk of later changes to an item’s `current_period_end` affecting the resolved cancellation timestamp. If you schedule a cancel date that occurs more than one period away, the subscription’s cycle remains unaffected until the subscription renews into the period that contains the `cancel_at` date. The `items.current_period_end` for the renewal then shortens to match the `cancel_at` date. For example, your customer subscribes to a 120 USD per year licensed subscription that renews on January 1, 2024. They set the subscription to cancel on July 1, 2024. The final invoice subtotal on January 1 calculates as 60 USD and the `items.current_period_end` is July 1. Changing, adding, or removing a scheduled cancel date within the current period updates the `items.current_period_end` and creates prorations. In the above example, on February 15 you update the cancel date to October 1. The current period end becomes October 1, and Stripe creates prorations for 30 USD for the additional quarter. To invoice the prorated items immediately instead of in a final invoice on October 1, pass a [proration_behavior](https://docs.stripe.com/api/subscriptions/update.md#update_subscription-proration_behavior) of `always_invoice` in the update, or separately [create a one-off invoice](https://docs.stripe.com/billing/invoices/subscription.md#generating-invoices). ## Cancellation with billing cycle anchor The subscription’s [billing cycle anchor](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-billing_cycle_anchor) property might change if it tracked the previous cancel date. During the first period, Stripe preserves any anchor you [originally set](https://docs.stripe.com/billing/subscriptions/billing-cycle.md#new-subscriptions) on the subscription. When the first period finishes, or if you didn’t provide a custom anchor when creating the subscription, the anchor resets to the [current period start](https://docs.stripe.com/api/subscription_items/object.md#subscription_item_object-current_period_start). This reset behavior for the billing cycle anchor is only guaranteed for subscriptions created after June 2024. Subscriptions created before this date might exhibit the legacy behavior where the [billing cycle anchor](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-billing_cycle_anchor) property remains unchanged after cancellation removal or extension. Adding a cancel date or moving an existing one closer to the current time shortens the [billing cycle anchor](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-billing_cycle_anchor) to match the new cancel date. In the above example, on February 15 you update the cancel date to April 1. The period end and billing anchor become April 1, and Stripe creates prorations for -30 USD to credit your customer for unused time for April 1 to July 1. ## See also - [Use trial periods](https://docs.stripe.com/billing/subscriptions/trials.md) - [Update subscription](https://docs.stripe.com/api.md#update_subscription) - [Cancel subscription](https://docs.stripe.com/api.md#cancel_subscription) --- # Source: https://docs.stripe.com/connect/supported-embedded-components/capital-financing-application.md # Capital application component Show an end-to-end application flow for Capital financing. The Capital application component allows your eligible connected accounts to complete a financing application in your platform’s website or application. They can select their offer amount and terms, view contractual details, and submit their application. Note: The following is a preview/demo component that behaves differently than live mode usage with real connected accounts. The actual component has more functionality than what might appear in this demo component. For example, for connected accounts without Stripe dashboard access (custom accounts), no user authentication is required in production. This component is similar to the [Capital promotion](https://docs.stripe.com/connect/supported-embedded-components/capital-financing-promotion.md) component, but it invokes the application directly and excludes educational or promotional content. Use this embedded component if you want to customize how to display the financing offer and program information to eligible connected accounts. ## Before you begin - Embedded components are only available to display to connected accounts in the US and UK. - Before you go live, you must [enable automatic offers](https://docs.stripe.com/capital/embedded-component-integration.md#enable-automatic-offers) and [submit your integration to Stripe for review](https://docs.stripe.com/connect/supported-embedded-components/capital-financing-application.md#submit-for-review). - When you [render the component](https://docs.stripe.com/connect/supported-embedded-components/capital-financing-application.md#render-the-component), it links out to Stripe content by default. You can replace the link for [Privacy policy](https://stripe.com/privacy) and [How Capital for platforms works](https://docs.stripe.com/capital/how-capital-for-platforms-works.md) with your equivalent documentation. ## Install Capital embedded components Install a beta version of the Stripe SDKs to create account sessions for private preview components: - [Ruby](https://github.com/stripe/stripe-ruby/#public-preview-sdks) `>=15.5.0-beta.1` - [Python](https://github.com/stripe/stripe-python/#public-preview-sdks) `>=12.5.0b1` - [PHP](https://github.com/stripe/stripe-php/#public-preview-sdks) `>=17.6.0-beta.1` - [Node](https://github.com/stripe/stripe-node/#public-preview-sdks) `>=18.5.0-beta.1` - [.NET](https://github.com/stripe/stripe-dotnet#public-preview-sdks) `>=48.5.0-beta.1` - [Java](https://github.com/stripe/stripe-java#public-preview-sdks) `>=29.5.0-beta.1` - [Go](https://github.com/stripe/stripe-go#public-preview-sdks) `>=82.5.0-beta.1` Use the beta version of the Stripe’s client-side libraries to render private preview components: #### npm Install the library: ```bash npm install --save @stripe/connect-js@preview ``` If you’re using React in your application: ```bash npm install --save @stripe/react-connect-js@preview ``` #### GitHub Download the [@stripe/connect-js](https://github.com/stripe/connect-js) and [@stripe/react-connect-js](https://github.com/stripe/react-connect-js) libraries source code directly from GitHub. ## Set up Connect.js If you don’t already use Stripe embedded components in your application, [initialize Connect.js](https://docs.stripe.com/connect/get-started-connect-embedded-components.md?platform=web#account-sessions) before you integrate the application component. ## Create an Account Session In your [create an Account Session](https://docs.stripe.com/api/account_sessions/create.md) request, specify `capital_financing_application` in the `components` parameter. ```curl curl https://api.stripe.com/v1/account_sessions \ -u "<>:" \ -H "Stripe-Version: 2026-01-28.preview; embedded_connect_beta=v2;" \ -d account="{{CONNECTEDACCOUNT_ID}}" \ -d "components[capital_financing_application][enabled]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new( "<>", stripe_version: '2026-01-28.preview; embedded_connect_beta=v2;', ) account_session = client.v1.account_sessions.create({ account: '{{CONNECTEDACCOUNT_ID}}', components: {capital_financing_application: {enabled: true}}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys # This example uses the beta SDK. See https://github.com/stripe/stripe-python#public-preview-sdks client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account_session = client.v1.account_sessions.create( { "account": "{{CONNECTEDACCOUNT_ID}}", "components": {"capital_financing_application": {"enabled": True}}, }, {"stripe_version": "2026-01-28.preview; embedded_connect_beta=v2;"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-php#public-preview-sdks $stripe = new \Stripe\StripeClient([ 'api_key' => '<>', 'stripe_version' => '2026-01-28.preview; embedded_connect_beta=v2;', ]); $accountSession = $stripe->accountSessions->create([ 'account' => '{{CONNECTEDACCOUNT_ID}}', 'components' => ['capital_financing_application' => ['enabled' => true]], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-java#public-preview-sdks StripeClient client = new StripeClient("<>"); AccountSessionCreateParams params = AccountSessionCreateParams.builder() .setAccount("{{CONNECTEDACCOUNT_ID}}") .setComponents( AccountSessionCreateParams.Components.builder() .setCapitalFinancingApplication( AccountSessionCreateParams.Components.CapitalFinancingApplication.builder() .setEnabled(true) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. AccountSession accountSession = client.v1().accountSessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-node#public-preview-sdks const stripe = require('stripe')( '<>', { // @ts-ignore overrides the pinned API version apiVersion: '2026-01-28.preview; embedded_connect_beta=v2;', } ); const accountSession = await stripe.accountSessions.create({ account: '{{CONNECTEDACCOUNT_ID}}', components: { capital_financing_application: { enabled: true, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-go#public-preview-sdks // Only public preview releases of stripe-go support setting the beta version. See https://github.com/stripe/stripe-go/blob/master/README.md#public-preview-sdks for more information. stripe.AddBetaVersion("embedded_connect_beta", "v2") sc := stripe.NewClient("<>") params := &stripe.AccountSessionCreateParams{ Account: stripe.String("{{CONNECTEDACCOUNT_ID}}"), Components: &stripe.AccountSessionCreateComponentsParams{ CapitalFinancingApplication: &stripe.AccountSessionCreateComponentsCapitalFinancingApplicationParams{ Enabled: stripe.Bool(true), }, }, } result, err := sc.V1AccountSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-dotnet#public-preview-sdks // Only public preview releases of stripe-dotnet support setting the beta version. See https://github.com/stripe/stripe-dotnet/blob/master/README.md#public-preview-sdks for more information. StripeConfiguration.AddBetaVersion("embedded_connect_beta", "v2"); var options = new AccountSessionCreateOptions { Account = "{{CONNECTEDACCOUNT_ID}}", Components = new AccountSessionComponentsOptions { CapitalFinancingApplication = new AccountSessionComponentsCapitalFinancingApplicationOptions { Enabled = true, }, }, }; var client = new StripeClient("<>"); var service = client.V1.AccountSessions; AccountSession accountSession = service.Create(options); ``` ## Render the application component Render the Capital application component in the front end: #### JavaScript ```js // Include this element in your HTML const capitalFinancingApplication = stripeConnectInstance.create('capital-financing-application'); container.appendChild(capitalFinancingApplication); ``` #### React ```jsx // Include this React component import { ConnectCapitalFinancingApplication, ConnectComponentsProvider, } from "@stripe/react-connect-js"; return ( ); ``` #### HTML + JS | Method | Type | Description | Default | | ---------------------------- | -------------------------- | --------------------------------------------------------------------------------- | ----------------------------------------------------------------- | | `setOnApplicationSubmitted` | `() => void` | The connected account has successfully submitted their application for financing. | | | `setOnApplicationStepChange` | `({step: string}) => void` | The connected account has navigated through the application. | | | `setPrivacyPolicyUrl` | `string` | Absolute URL of a page containing your privacy policy. | `https://stripe.com/privacy` | | `setHowCapitalWorksUrl` | `string` | Absolute URL of a page with information about the Capital program. | `https://docs.stripe.com/capital/how-capital-for-platforms-works` | #### React | React prop | Type | Description | Default | Required or Optional | | ------------------------- | -------------------------- | --------------------------------------------------------------------------------- | ----------------------------------------------------------------- | -------------------- | | `onApplicationSubmitted` | `() => void` | The connected account has successfully submitted their application for financing. | | required | | `onApplicationStepChange` | `({step: string}) => void` | The connected account has navigated through the application. | | optional | | `privacyPolicyUrl` | `string` | Absolute URL of a page containing your privacy policy. | `https://stripe.com/privacy` | optional | | `howCapitalWorksUrl` | `string` | Absolute URL of a page with information about the Capital program. | `https://docs.stripe.com/capital/how-capital-for-platforms-works` | optional | ## Set the display state Add the application component on a page your connected accounts use to view payments and payouts reporting information, or a dedicated **Financing** page in your platform’s UI. Make sure to use a different location than the [Connect promotion component](https://docs.stripe.com/connect/supported-embedded-components/capital-financing-promotion.md) (if applicable). To determine if a connected account is eligible for an offer, call the [List financing offers](https://docs.stripe.com/api/capital/financing_offers/list.md) endpoint and pass the connected account ID in the `connected_account` parameter. The application component displays content dynamically based on the connected account’s financing status: - **No active financing**: If an account doesn’t have an eligible financing offer, then the application component doesn’t render (returns null). - **With active offer**: If the connected account is eligible for an offer, the component shows full offer details with a **Start application** button. - **Offer in review**: After an eligible connected account accepts and applies for a financing offer, use this state to display an application status tracker. Listen to the `onApplicationStepChange` event to track their offer’s progress. This event is emitted when the connected account advances to the next step or navigates back to a previous step or page in the Capital application process. The name of the next step is provided to the handler you provide in the step field. These steps can appear in any order and repeat. You can modify, add, and remove the step names at any time. Only use the `onApplicationStepChange` object for analytics purposes, such as tracking the average page completion time or pages with the most drop off. Don’t use the `onApplicationStepChange` object to trigger operational or support workflows, such as sending emails to connected accounts who stopped application progress at a specific page. - **Submitted offer**: If a connected account has already submitted their financing application, the Capital financing application component renders an empty screen. Listen to the `onApplicationSubmitted` event to display a confirmation screen instead. - **Active financing in progress**: The component doesn’t render (returns null). ### The onApplicationStepChange type The `onApplicationStepChange` type is defined in connect.js. Every time the connected account navigates from one step to another in the Capital application process, the step change handler receives a onApplicationStepChange object with the following property: | Name | Type | Example value | | ------ | ------------------------------------ | --------------- | | `step` | `string` (must be a valid step name) | `business_type` | The unique reference to an onboarding step. | ### Step Names Each page in an onboarding flow has one of the following step names. | Step name | Description | | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `stripe_user_authentication` | Handles user authentication using a Stripe-hosted window to verify identity and secure the financing workflow. | | `offer_selector` | Introduces connected accounts to the financing application, providing an overview of the offer and the financing. | | `offer_summary` | Displays a detailed summary of the financing offer, including key terms and conditions. | | `business_details` | Collects detailed information about the connected account’s business, such as business address, industry, and operational specifics. | | `business_verification` | Gathers documentation and information that verifies the existence and legitimacy of the connected account’s business entity. | | `business_summary` | Provides a review of all business-related information submitted during onboarding, allowing the connected account to confirm or update details. | | `owners` | Collects information about the beneficial owners of the business applying for financing. | | `directors` | Gathers details about the directors of the business, if applicable. | | `executives` | Collects information about key executives associated with the business. | | `representative_details` | Collects information about the individual representing the business in the financing application. | | `representative_additional_document` | Allows the connected account to upload supplementary documents verifying the representative’s identity or authority. | | `representative_document` | Collects a government-issued ID or equivalent document that verifies the identity of the business representative. | | `person_summary` | Provides a review of all person-level information (owners, representatives, executives) submitted, allowing for updates or corrections. | | `offer_annual_revenue` | Collects information regarding the connected account’s annual revenue to assess financing eligibility and terms. | | `offer_financial_data` | Requests additional financial documents and data necessary for underwriting and approval of the financing offer. | | `offer_missing_contact_info` | Prompts the connected account to provide or update missing contact information relevant to the financing application. | | `offer_payout_details` | Collects payment and payout details to facilitate disbursement of financing funds to the connected account’s bank account. | | `lending_network_offer_review_agreements` | Provides connected accounts with agreements specific to financing offers sourced through Stripe’s Lending Network for review and acceptance. | | `offer_review_agreements` | Presents the legal agreements and terms related to the selected financing offer for review and acceptance by the connected account. | | `offer_complete` | Confirms that the financing offer has been submitted and the application process is complete. | #### Step Restrictions - The StepChange object is only for analytics. - Steps can appear in any order and can repeat. - The list of valid step names can change at any time, without notice. ## Submit the component for review To use any of the Capital components in live mode, Stripe and our financial partners must review and approve all customer-facing content that references Stripe Capital: 1. [Create a test offer in a sandbox](https://docs.stripe.com/capital/testing.md#create-offer), and set the offer status to `delivered`. Use this test offer to preview the application component in your platform’s website or dashboard. 1. Capture a preview of the sandbox offer and how the embedded component displays in your platform’s UI (such as screenshots or a recorded video). 1. [Submit the preview to Stripe](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835). After approval, Stripe enables you to use the component in live mode. ## Optional: Additional embedded components The application component is one of several [embedded components](https://docs.stripe.com/capital/embedded-component-integration.md#select-components) available for Capital for platforms. For example, you can embed the [Capital financing component](https://docs.stripe.com/connect/supported-embedded-components/capital-financing.md), which allows your connected accounts to manage their payments and view transaction history. ## See also - [Set up Capital embedded components](https://docs.stripe.com/capital/embedded-component-integration.md) --- # Source: https://docs.stripe.com/connect/supported-embedded-components/capital-financing-promotion.md # Capital promotion component Show promotional content about a connected account's Capital financing offer and launch a Capital application. The Capital promotion component allows your eligible connected accounts to complete a financing application in your platform’s website or application. Connected accounts can select their offer amount and terms, view contractual details, and submit their application. This component displays educational and promotional content about the Capital program as the starting point in the application process. Note: The following is a preview/demo component that behaves differently than live mode usage with real connected accounts. The actual component has more functionality than what might appear in this demo component. For example, for connected accounts without Stripe dashboard access (custom accounts), no user authentication is required in production. ### Alternate components - For a smaller version of this component, see the [Capital promo tile component](https://docs.stripe.com/capital/promotional-tile.md) - To exclude education and promotional information about the Capital program, see the [Capital application component](https://docs.stripe.com/connect/supported-embedded-components/capital-financing-application.md) ## Before you begin - Embedded components are only available to display to connected accounts in the US and UK. - Before you go live, you must [enable automatic offers](https://docs.stripe.com/capital/embedded-component-integration.md#enable-automatic-offers) and [submit your integration to Stripe for review](https://docs.stripe.com/connect/supported-embedded-components/capital-financing-promotion.md#submit-for-review). - When you [render the component](https://docs.stripe.com/connect/supported-embedded-components/capital-financing-promotion.md#render-the-component), it links out to Stripe content by default. You can replace the link for [Privacy policy](https://stripe.com/privacy) and [How Capital for platforms works](https://docs.stripe.com/capital/how-capital-for-platforms-works.md) with your equivalent documentation. ## Install Capital embedded components Install a beta version of the Stripe SDKs to create account sessions for private preview components: - [Ruby](https://github.com/stripe/stripe-ruby/#public-preview-sdks) `>=15.5.0-beta.1` - [Python](https://github.com/stripe/stripe-python/#public-preview-sdks) `>=12.5.0b1` - [PHP](https://github.com/stripe/stripe-php/#public-preview-sdks) `>=17.6.0-beta.1` - [Node](https://github.com/stripe/stripe-node/#public-preview-sdks) `>=18.5.0-beta.1` - [.NET](https://github.com/stripe/stripe-dotnet#public-preview-sdks) `>=48.5.0-beta.1` - [Java](https://github.com/stripe/stripe-java#public-preview-sdks) `>=29.5.0-beta.1` - [Go](https://github.com/stripe/stripe-go#public-preview-sdks) `>=82.5.0-beta.1` Use the beta version of the Stripe’s client-side libraries to render private preview components: #### npm Install the library: ```bash npm install --save @stripe/connect-js@preview ``` If you’re using React in your application: ```bash npm install --save @stripe/react-connect-js@preview ``` #### GitHub Download the [@stripe/connect-js](https://github.com/stripe/connect-js) and [@stripe/react-connect-js](https://github.com/stripe/react-connect-js) libraries source code directly from GitHub. ## Set up Connect.js If you don’t already use Stripe embedded components in your application, [initialize Connect.js](https://docs.stripe.com/connect/get-started-connect-embedded-components.md?platform=web#account-sessions) before you integrate the application component. ## Create an Account Session In your [create an Account Session](https://docs.stripe.com/api/account_sessions/create.md) request, specify  `capital_financing_promotion` in the `components` parameter. ```curl curl https://api.stripe.com/v1/account_sessions \ -u "<>:" \ -H "Stripe-Version: 2026-01-28.preview; embedded_connect_beta=v2;" \ -d account="{{CONNECTEDACCOUNT_ID}}" \ -d "components[capital_financing_promotion][enabled]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new( "<>", stripe_version: '2026-01-28.preview; embedded_connect_beta=v2;', ) account_session = client.v1.account_sessions.create({ account: '{{CONNECTEDACCOUNT_ID}}', components: {capital_financing_promotion: {enabled: true}}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys # This example uses the beta SDK. See https://github.com/stripe/stripe-python#public-preview-sdks client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account_session = client.v1.account_sessions.create( { "account": "{{CONNECTEDACCOUNT_ID}}", "components": {"capital_financing_promotion": {"enabled": True}}, }, {"stripe_version": "2026-01-28.preview; embedded_connect_beta=v2;"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-php#public-preview-sdks $stripe = new \Stripe\StripeClient([ 'api_key' => '<>', 'stripe_version' => '2026-01-28.preview; embedded_connect_beta=v2;', ]); $accountSession = $stripe->accountSessions->create([ 'account' => '{{CONNECTEDACCOUNT_ID}}', 'components' => ['capital_financing_promotion' => ['enabled' => true]], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-java#public-preview-sdks StripeClient client = new StripeClient("<>"); AccountSessionCreateParams params = AccountSessionCreateParams.builder() .setAccount("{{CONNECTEDACCOUNT_ID}}") .setComponents( AccountSessionCreateParams.Components.builder() .setCapitalFinancingPromotion( AccountSessionCreateParams.Components.CapitalFinancingPromotion.builder() .setEnabled(true) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. AccountSession accountSession = client.v1().accountSessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-node#public-preview-sdks const stripe = require('stripe')( '<>', { // @ts-ignore overrides the pinned API version apiVersion: '2026-01-28.preview; embedded_connect_beta=v2;', } ); const accountSession = await stripe.accountSessions.create({ account: '{{CONNECTEDACCOUNT_ID}}', components: { capital_financing_promotion: { enabled: true, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-go#public-preview-sdks // Only public preview releases of stripe-go support setting the beta version. See https://github.com/stripe/stripe-go/blob/master/README.md#public-preview-sdks for more information. stripe.AddBetaVersion("embedded_connect_beta", "v2") sc := stripe.NewClient("<>") params := &stripe.AccountSessionCreateParams{ Account: stripe.String("{{CONNECTEDACCOUNT_ID}}"), Components: &stripe.AccountSessionCreateComponentsParams{ CapitalFinancingPromotion: &stripe.AccountSessionCreateComponentsCapitalFinancingPromotionParams{ Enabled: stripe.Bool(true), }, }, } result, err := sc.V1AccountSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-dotnet#public-preview-sdks // Only public preview releases of stripe-dotnet support setting the beta version. See https://github.com/stripe/stripe-dotnet/blob/master/README.md#public-preview-sdks for more information. StripeConfiguration.AddBetaVersion("embedded_connect_beta", "v2"); var options = new AccountSessionCreateOptions { Account = "{{CONNECTEDACCOUNT_ID}}", Components = new AccountSessionComponentsOptions { CapitalFinancingPromotion = new AccountSessionComponentsCapitalFinancingPromotionOptions { Enabled = true, }, }, }; var client = new StripeClient("<>"); var service = client.V1.AccountSessions; AccountSession accountSession = service.Create(options); ``` ## Render the component Render the Capital promotion component in the front end: #### JavaScript ```js // Include this element in your HTML const capitalFinancingPromotion = stripeConnectInstance.create('capital-financing-promotion'); container.appendChild(capitalFinancingPromotion); ``` #### React ```jsx // Include this React component import { ConnectCapitalFinancingPromotion, ConnectComponentsProvider, } from "@stripe/react-connect-js"; return ( ); ``` #### HTML + JS | Method | Type | Description | Default | | ----------------------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | | `setOnApplicationSubmitted` | `() => void` | The connected account has successfully submitted their application for financing. | | | `setOnApplicationStepChange` | `({step: string}) => void` | The connected account has navigated through the application. | | | `setLayout` | `full | banner` | Controls the layout of the component. `banner` mode greatly reduces the vertical size of the component, which is useful when stacking the component with other content on the page. | `full` | | `setOnEligibleFinancingOfferLoaded` | `({productType: standard | refill | none}) => void` | The connected account’s financing offer has been loaded. The `productType` field corresponds to the `product_type` field on the [Financing Offer](https://docs.stripe.com/api/capital/connect_financing_object.md#financing_offer_object-product_type) object. | | | `setPrivacyPolicyUrl` | `string` | Absolute URL of a page containing your privacy policy. | `https://stripe.com/privacy` | | `setHowCapitalWorksUrl` | `string` | Absolute URL of a page with information about the Capital program. | `https://docs.stripe.com/capital/how-capital-for-platforms-works` | | `setEligibilityCriteriaUrl` | `string` | Absolute URL of a page with information about eligibility criteria for the Capital program. | `https://docs.stripe.com/capital/how-capital-for-platforms-works` | #### React | React prop | Type | Description | Default | Required or Optional | | -------------------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | -------------------- | | `onApplicationSubmitted` | `() => void` | The connected account has successfully submitted their application for financing. | | optional | | `onApplicationStepChange` | `({step: string}) => void` | The connected account navigated through the application. See [details](https://docs.stripe.com/connect/supported-embedded-components/capital-financing-promotion.md#display-states). | | optional | | `layout` | `full | banner` | Controls the layout of the component. `banner` mode greatly reduces the vertical size of the component, which is useful when stacking the component with other content on the page. | `"full"` | optional | | `onEligibleFinancingOfferLoaded` | `({productType: "standard" | "refill" | "none"}) => void` | The connected account’s financing offer has been loaded. The `productType` field corresponds to the `product_type` field on the [Financing Offer](https://docs.stripe.com/api/capital/connect_financing_object.md#financing_offer_object-product_type) object. | | optional | | `privacyPolicyUrl` | `string` | Absolute URL of a page containing your privacy policy. | `https://stripe.com/privacy` | optional | | `howCapitalWorksUrl` | `string` | Absolute URL of a page with information about the Capital program. | `https://docs.stripe.com/capital/how-stripe-capital-works` | optional | | `eligibilityCriteriaUrl` | `string` | Absolute URL of a page with information about eligibility criteria for the Capital program. | `https://docs.stripe.com/capital/how-stripe-capital-works` | optional | ## Set the display state Add the promotion component on your platform’s home page, or a dedicated **Financing** page in your platform’s website or app. The application component displays content dynamically based on the connected account’s financing status: - **No active financing**: If the connected account doesn’t have active financing, the component displays generic information about eligibility and the lending program. - **With active offer**: If the connected account is eligible for an offer, the component shows full offer details with a **Start application** button. - **Offer in review**: After an eligible connected account accepts and applies for a financing offer, use this state to display an application status tracker. Listen to the `onApplicationStepChange` event to track their offer’s progress. This event is emitted when the connected account advances to the next step or navigates back to a previous step or page in the Capital application process. The name of the next step is provided to the handler you provide in the step field. These steps can appear in any order and repeat. You can modify, add, and remove the step names at any time. Only use the `onApplicationStepChange` object for analytics purposes, such as tracking the average page completion time or pages with the most drop off. Don’t use the `onApplicationStepChange` object to trigger operational or support workflows, such as sending emails to connected accounts who stopped application progress at a specific page. - **Submitted offer**: After a connected account submits their financing application, the component renders an empty screen. Listen to the `onApplicationSubmitted` event to display a confirmation screen instead. - **Active financing in progress**: The component doesn’t render (returns null). ### The onApplicationStepChange type The `onApplicationStepChange` type is defined in connect.js. Every time the connected account navigates from one step to another in the Capital application process, the step change handler receives a onApplicationStepChange object with the following property: | Name | Type | Example value | | ------ | ------------------------------------ | --------------- | | `step` | `string` (must be a valid step name) | `business_type` | The unique reference to an onboarding step. | ### Step Names Each page in an onboarding flow has one of the following step names. | Step name | Description | | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `stripe_user_authentication` | Handles user authentication using a Stripe-hosted window to verify identity and secure the financing workflow. | | `offer_selector` | Introduces connected accounts to the financing application, providing an overview of the offer and the financing. | | `offer_summary` | Displays a detailed summary of the financing offer, including key terms and conditions. | | `business_details` | Collects detailed information about the connected account’s business, such as business address, industry, and operational specifics. | | `business_verification` | Gathers documentation and information that verifies the existence and legitimacy of the connected account’s business entity. | | `business_summary` | Provides a review of all business-related information submitted during onboarding, allowing the connected account to confirm or update details. | | `owners` | Collects information about the beneficial owners of the business applying for financing. | | `directors` | Gathers details about the directors of the business, if applicable. | | `executives` | Collects information about key executives associated with the business. | | `representative_details` | Collects information about the individual representing the business in the financing application. | | `representative_additional_document` | Allows the connected account to upload supplementary documents verifying the representative’s identity or authority. | | `representative_document` | Collects a government-issued ID or equivalent document that verifies the identity of the business representative. | | `person_summary` | Provides a review of all person-level information (owners, representatives, executives) submitted, allowing for updates or corrections. | | `offer_annual_revenue` | Collects information regarding the connected account’s annual revenue to assess financing eligibility and terms. | | `offer_financial_data` | Requests additional financial documents and data necessary for underwriting and approval of the financing offer. | | `offer_missing_contact_info` | Prompts the connected account to provide or update missing contact information relevant to the financing application. | | `offer_payout_details` | Collects payment and payout details to facilitate disbursement of financing funds to the connected account’s bank account. | | `lending_network_offer_review_agreements` | Provides connected accounts with agreements specific to financing offers sourced through Stripe’s Lending Network for review and acceptance. | | `offer_review_agreements` | Presents the legal agreements and terms related to the selected financing offer for review and acceptance by the connected account. | | `offer_complete` | Confirms that the financing offer has been submitted and the application process is complete. | #### Step Restrictions - The StepChange object is only for analytics. - Steps can appear in any order and can repeat. - The list of valid step names can change at any time, without notice. ## Submit the component for review To use any of the Capital components in live mode, Stripe and our financial partners must review and approve all customer-facing content that references Stripe Capital: 1. [Create a test offer in a sandbox](https://docs.stripe.com/capital/testing.md#create-offer), and set the offer status to `delivered`. Use this test offer to preview the application component in your platform’s website or dashboard. 1. Capture a preview of the sandbox offer and how the embedded component displays in your platform’s UI (such as screenshots or a recorded video). 1. [Submit the preview to Stripe](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835). After approval, Stripe enables you to use the component in live mode. ## Optional: Additional embedded components The promotion component is one of several [embedded components](https://docs.stripe.com/capital/embedded-component-integration.md#select-components) available for Capital for platforms. For example, you can embed the [Capital financing component](https://docs.stripe.com/connect/supported-embedded-components/capital-financing.md), which allows your connected accounts to manage their payments and view transaction history. ## See also - [Set up an embedded components integration](https://docs.stripe.com/capital/embedded-component-integration.md) --- # Source: https://docs.stripe.com/connect/supported-embedded-components/capital-financing.md # Capital financing component Allow a connected account to view and manage their active Capital financing. The Capital financing embedded component allows connected accounts to view and manage their financing status after they accept an offer. Connected accounts can: - View their payment progress - Monitor transaction history - Make payments, if applicable to their [type of financing](https://docs.stripe.com/capital/how-capital-for-platforms-works.md#types-of-financing-offers) Note: The following is a preview/demo component that behaves differently than live mode usage with real connected accounts. The actual component has more functionality than what might appear in this demo component. For example, for connected accounts without Stripe dashboard access (custom accounts), no user authentication is required in production. ## Before you begin - Embedded components are only available to display to connected accounts in the US and UK. - Before you go live, you must [enable automatic offers](https://docs.stripe.com/capital/embedded-component-integration.md#enable-automatic-offers) and [submit your integration to Stripe for review](https://docs.stripe.com/connect/supported-embedded-components/capital-financing.md#submit-for-review). - When you [render the component](https://docs.stripe.com/connect/supported-embedded-components/capital-financing.md#render-the-component), it links out to Stripe content by default. You can replace the link for [Privacy policy](https://stripe.com/privacy) and [How Capital for platforms works](https://docs.stripe.com/capital/how-capital-for-platforms-works.md) with your equivalent documentation. ## Install Capital embedded components Install a beta version of the Stripe SDKs to create account sessions for private preview components: - [Ruby](https://github.com/stripe/stripe-ruby/#public-preview-sdks) `>=15.5.0-beta.1` - [Python](https://github.com/stripe/stripe-python/#public-preview-sdks) `>=12.5.0b1` - [PHP](https://github.com/stripe/stripe-php/#public-preview-sdks) `>=17.6.0-beta.1` - [Node](https://github.com/stripe/stripe-node/#public-preview-sdks) `>=18.5.0-beta.1` - [.NET](https://github.com/stripe/stripe-dotnet#public-preview-sdks) `>=48.5.0-beta.1` - [Java](https://github.com/stripe/stripe-java#public-preview-sdks) `>=29.5.0-beta.1` - [Go](https://github.com/stripe/stripe-go#public-preview-sdks) `>=82.5.0-beta.1` Use the beta version of the Stripe’s client-side libraries to render private preview components: #### npm Install the library: ```bash npm install --save @stripe/connect-js@preview ``` If you’re using React in your application: ```bash npm install --save @stripe/react-connect-js@preview ``` #### GitHub Download the [@stripe/connect-js](https://github.com/stripe/connect-js) and [@stripe/react-connect-js](https://github.com/stripe/react-connect-js) libraries source code directly from GitHub. ## Set up Connect.js If you don’t already use Stripe embedded components in your application, [initialize Connect.js](https://docs.stripe.com/connect/get-started-connect-embedded-components.md?platform=web#account-sessions) before you integrate the financing component. ## Create an Account Session In your [create an Account Session](https://docs.stripe.com/api/account_sessions/create.md) request, specify `capital_financing` in the `components` parameter to enable the financing component. ```curl curl https://api.stripe.com/v1/account_sessions \ -u "<>:" \ -H "Stripe-Version: 2026-01-28.preview; embedded_connect_beta=v2;" \ -d account="{{CONNECTEDACCOUNT_ID}}" \ -d "components[capital_financing][enabled]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new( "<>", stripe_version: '2026-01-28.preview; embedded_connect_beta=v2;', ) account_session = client.v1.account_sessions.create({ account: '{{CONNECTEDACCOUNT_ID}}', components: {capital_financing: {enabled: true}}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys # This example uses the beta SDK. See https://github.com/stripe/stripe-python#public-preview-sdks client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account_session = client.v1.account_sessions.create( { "account": "{{CONNECTEDACCOUNT_ID}}", "components": {"capital_financing": {"enabled": True}}, }, {"stripe_version": "2026-01-28.preview; embedded_connect_beta=v2;"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-php#public-preview-sdks $stripe = new \Stripe\StripeClient([ 'api_key' => '<>', 'stripe_version' => '2026-01-28.preview; embedded_connect_beta=v2;', ]); $accountSession = $stripe->accountSessions->create([ 'account' => '{{CONNECTEDACCOUNT_ID}}', 'components' => ['capital_financing' => ['enabled' => true]], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-java#public-preview-sdks StripeClient client = new StripeClient("<>"); AccountSessionCreateParams params = AccountSessionCreateParams.builder() .setAccount("{{CONNECTEDACCOUNT_ID}}") .setComponents( AccountSessionCreateParams.Components.builder() .setCapitalFinancing( AccountSessionCreateParams.Components.CapitalFinancing.builder() .setEnabled(true) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. AccountSession accountSession = client.v1().accountSessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-node#public-preview-sdks const stripe = require('stripe')( '<>', { // @ts-ignore overrides the pinned API version apiVersion: '2026-01-28.preview; embedded_connect_beta=v2;', } ); const accountSession = await stripe.accountSessions.create({ account: '{{CONNECTEDACCOUNT_ID}}', components: { capital_financing: { enabled: true, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-go#public-preview-sdks // Only public preview releases of stripe-go support setting the beta version. See https://github.com/stripe/stripe-go/blob/master/README.md#public-preview-sdks for more information. stripe.AddBetaVersion("embedded_connect_beta", "v2") sc := stripe.NewClient("<>") params := &stripe.AccountSessionCreateParams{ Account: stripe.String("{{CONNECTEDACCOUNT_ID}}"), Components: &stripe.AccountSessionCreateComponentsParams{ CapitalFinancing: &stripe.AccountSessionCreateComponentsCapitalFinancingParams{ Enabled: stripe.Bool(true), }, }, } result, err := sc.V1AccountSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-dotnet#public-preview-sdks // Only public preview releases of stripe-dotnet support setting the beta version. See https://github.com/stripe/stripe-dotnet/blob/master/README.md#public-preview-sdks for more information. StripeConfiguration.AddBetaVersion("embedded_connect_beta", "v2"); var options = new AccountSessionCreateOptions { Account = "{{CONNECTEDACCOUNT_ID}}", Components = new AccountSessionComponentsOptions { CapitalFinancing = new AccountSessionComponentsCapitalFinancingOptions { Enabled = true, }, }, }; var client = new StripeClient("<>"); var service = client.V1.AccountSessions; AccountSession accountSession = service.Create(options); ``` ## Render the component Render the Capital financing component in the front end: #### JavaScript ```js // Include this element in your HTML const capitalFinancing = stripeConnectInstance.create('capital-financing'); container.appendChild(capitalFinancing); ``` #### React ```jsx // Include this React component import { ConnectCapitalFinancing, ConnectComponentsProvider, } from "@stripe/react-connect-js"; return ( ); ``` #### HTML + JS | Method | Type | Description | Default | | -------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | | `setDefaultFinancingOffer` | `string` | [Financing Offer](https://docs.stripe.com/api/capital/financing_offers.md) ID to render on initial load of the component. If omitted, the component displays the active or most recent financing. | | | `setShowFinancingSelector` | `boolean` | If true, render the financing dropdown selector to allow the connected account to change the displayed financing. | `true` | | `setOnFinancingsLoaded` | `({total: number}) => void` | The component loaded the connected account’s financing history. | | | `setSupportUrl` | `string` | Absolute URL of your support site. | `https://support.stripe.com/` | | `setHowCapitalWorksUrl` | `string` | Absolute URL of a page with information about the Capital program. | `https://docs.stripe.com/capital/how-stripe-capital-works` | #### React | React property | Type | Description | Default | Required or Optional | | ----------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | -------------------- | | `defaultFinancingOffer` | `string` | [Financing Offer](https://docs.stripe.com/api/capital/financing_offers.md) ID to render on initial load of the component. If omitted, the component displays the active or most recent financing. | `null` | optional | | `showFinancingSelector` | `boolean` | If true, render the financing dropdown selector to allow the connected account to change the displayed financing. | `true` | optional | | `onFinancingsLoaded` | `({total: number}) => void` | The component loaded the connected account’s financing history. | | optional | | `supportUrl` | `string` | Absolute URL of your support site. | `https://support.stripe.com/` | optional | | `howCapitalWorksUrl` | `string` | Absolute URL of a page with information about the Capital program. | `https://docs.stripe.com/capital/how-stripe-capital-works` | optional | ## Set the display state Place the financing component on a page your connected accounts currently use to view payments and payouts reporting information, or a dedicated **Financing** page. The financing component displays content dynamically based on the connected account’s financing status: - **No financing history**: If a connected account has an offer, but hasn’t accepted or applied for it yet, the financing component displays nothing. Listen to the `onFinancingsLoaded` event to display a custom message in the financing component for this state or hide the financing component until financing data becomes available. - **Offer in review**: After an eligible connected account accepts and applies for a financing offer, use this state to render the component to display an application status tracker while they wait for offer approval. ## Submit the component for review To use any of the Capital components in live mode, Stripe and our financial partners must review and approve all customer-facing content that references Stripe Capital: 1. [Create a test offer in a sandbox](https://docs.stripe.com/capital/testing.md#create-offer), and set the offer status to `delivered`. Use this test offer to preview the application component in your platform’s website or dashboard. 1. Capture a preview of the sandbox offer and how the embedded component displays in your platform’s UI (such as screenshots or a recorded video). 1. [Submit the preview to Stripe](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835). After approval, Stripe enables you to use the component in live mode. ## Optional: Additional embedded components The financing component is one of several embedded components available for Capital. Learn more about embedded components in the [Set up Capital embedded components](https://docs.stripe.com/capital/embedded-component-integration.md) guide. ## See also - [Set up Capital embedded components](https://docs.stripe.com/capital/embedded-component-integration.md) --- # Source: https://docs.stripe.com/climate/orders/carbon-removal-inventory.md # Carbon removal inventory Learn about available carbon removal inventory. ## Available products *Products* (Products represent the different types of carbon removal units that are available for purchase) represent the carbon removal inventory available for purchase. All products come from *offtake agreements* (A contractual agreement to purchase carbon removal at a certain price if and when tons of carbon removal are delivered and verified) with carbon removal suppliers in [Frontier’s portfolio](https://frontierclimate.com/portfolio?track=offtake). ### Buy the portfolio Avoiding the worst impacts of climate change requires a portfolio of technologies. By purchasing the Frontier offtake portfolio, you accelerate the development of a range of carbon removal technologies while simultaneously maximizing the likelihood that your tons are delivered by the expected delivery year. Frontier conducts diligence on carbon removal technologies to grow this portfolio as the industry evolves. To provide users with price certainty, we take on the underlying pricing risk. If the actual price per ton delivered is less than price per ton sold, we’ll use all excess funds to buy more carbon removal. If the actual price per ton delivered is greater than the price per ton sold—for example, if only the more expensive suppliers can deliver—the price doesn’t change for you and the losses are borne by us. We aim to fulfill orders from a diverse set of suppliers within Frontier’s offtake portfolio. However, we won’t fractionalize deliveries in quantities less than 1 ton (for example, an order for 4 tons might include deliveries from up to 4 suppliers). ### Buy from individual suppliers If you’re excited about a particular technology or want to align purchases with company-specific attributes (for example, geography), you can also purchase from individual suppliers. ## Pricing Our goal is to bring new buyers into the market, not to make money. We price the products as close to cost as possible. Fees help cover our underlying costs of administering the carbon removal portfolio. Frontier receives these fees for services including, but not limited to, sourcing, performing diligence, negotiating offtake agreements with, monitoring the progress of, and reallocating demand between carbon removal suppliers. --- # Source: https://docs.stripe.com/payments/checkout/customization/card-brands.md # Customize card brands Customize the card brands that Checkout displays. When you use a Stripe-hosted payment page or embedded payment form, you can customize the card brands you want to display to your customers. To block specific card brands, include the `brands_blocked` parameter when you create a Checkout Session. Pass an array with any of the following card brand values: - `visa` - `mastercard` - `american_express` - `discover_global_network` The `discover_global_network` value encompasses all of the cards that are part of the Discover Global Network, including Discover, Diners, JCB, UnionPay, and Elo. The following code example initializes the Checkout Session with the `brands_blocked` parameter set to `['american_express']`, which prevents customers from using American Express cards. #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" \ -d "payment_method_options[card][restrictions][brands_blocked][0]"=american_express ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --success-url="https://example.com/success" \ -d "payment_method_options[card][restrictions][brands_blocked][0]"=american_express ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success', payment_method_options: {card: {restrictions: {brands_blocked: ['american_express']}}}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "payment", "success_url": "https://example.com/success", "payment_method_options": { "card": {"restrictions": {"brands_blocked": ["american_express"]}}, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'payment', 'success_url' => 'https://example.com/success', 'payment_method_options' => [ 'card' => ['restrictions' => ['brands_blocked' => ['american_express']]], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .setPaymentMethodOptions( SessionCreateParams.PaymentMethodOptions.builder() .setCard( SessionCreateParams.PaymentMethodOptions.Card.builder() .setRestrictions( SessionCreateParams.PaymentMethodOptions.Card.Restrictions.builder() .addBrandsBlocked( SessionCreateParams.PaymentMethodOptions.Card.Restrictions.BrandsBlocked.AMERICAN_EXPRESS ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success', payment_method_options: { card: { restrictions: { brands_blocked: ['american_express'], }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), PaymentMethodOptions: &stripe.CheckoutSessionCreatePaymentMethodOptionsParams{ Card: &stripe.CheckoutSessionCreatePaymentMethodOptionsCardParams{ Restrictions: &stripe.CheckoutSessionCreatePaymentMethodOptionsCardRestrictionsParams{ BrandsBlocked: []*string{ stripe.String(stripe.CheckoutSessionPaymentMethodOptionsCardRestrictionsBrandsBlockedAmericanExpress), }, }, }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "payment", SuccessUrl = "https://example.com/success", PaymentMethodOptions = new Stripe.Checkout.SessionPaymentMethodOptionsOptions { Card = new Stripe.Checkout.SessionPaymentMethodOptionsCardOptions { Restrictions = new Stripe.Checkout.SessionPaymentMethodOptionsCardRestrictionsOptions { BrandsBlocked = new List { "american_express" }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode return_url="https://example.com/return" \ -d ui_mode=embedded \ -d "payment_method_options[card][restrictions][brands_blocked][0]"=american_express ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --return-url="https://example.com/return" \ --ui-mode=embedded \ -d "payment_method_options[card][restrictions][brands_blocked][0]"=american_express ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', return_url: 'https://example.com/return', ui_mode: 'embedded', payment_method_options: {card: {restrictions: {brands_blocked: ['american_express']}}}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "payment", "return_url": "https://example.com/return", "ui_mode": "embedded", "payment_method_options": { "card": {"restrictions": {"brands_blocked": ["american_express"]}}, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'payment', 'return_url' => 'https://example.com/return', 'ui_mode' => 'embedded', 'payment_method_options' => [ 'card' => ['restrictions' => ['brands_blocked' => ['american_express']]], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setReturnUrl("https://example.com/return") .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setPaymentMethodOptions( SessionCreateParams.PaymentMethodOptions.builder() .setCard( SessionCreateParams.PaymentMethodOptions.Card.builder() .setRestrictions( SessionCreateParams.PaymentMethodOptions.Card.Restrictions.builder() .addBrandsBlocked( SessionCreateParams.PaymentMethodOptions.Card.Restrictions.BrandsBlocked.AMERICAN_EXPRESS ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', return_url: 'https://example.com/return', ui_mode: 'embedded', payment_method_options: { card: { restrictions: { brands_blocked: ['american_express'], }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), ReturnURL: stripe.String("https://example.com/return"), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), PaymentMethodOptions: &stripe.CheckoutSessionCreatePaymentMethodOptionsParams{ Card: &stripe.CheckoutSessionCreatePaymentMethodOptionsCardParams{ Restrictions: &stripe.CheckoutSessionCreatePaymentMethodOptionsCardRestrictionsParams{ BrandsBlocked: []*string{ stripe.String(stripe.CheckoutSessionPaymentMethodOptionsCardRestrictionsBrandsBlockedAmericanExpress), }, }, }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "payment", ReturnUrl = "https://example.com/return", UiMode = "embedded", PaymentMethodOptions = new Stripe.Checkout.SessionPaymentMethodOptionsOptions { Card = new Stripe.Checkout.SessionPaymentMethodOptionsCardOptions { Restrictions = new Stripe.Checkout.SessionPaymentMethodOptionsCardRestrictionsOptions { BrandsBlocked = new List { "american_express" }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` If a customer enters an unsupported card number in Checkout, an error message notifies them that their card brand isn’t accepted. ![Card brand filtering on Checkout](https://b.stripecdn.com/docs-statics-srv/assets/card-brand-filtering-on-form.e3a1bab1800020eefd977e093863d208.png) An error surfaces informing the customer that you don’t accept Visa (or whatever card brand you have blocked). Additionally, [Link](https://docs.stripe.com/payments/link/checkout-link.md) also disables saved cards for returning customers if the saved card is blocked. ![Card brand filtering on Checkout with Link](https://b.stripecdn.com/docs-statics-srv/assets/card-brand-filtering-link.eb5ed48829c0b18a59dadf2a77cd6a66.png) If a Link user’s saved card is blocked, it is disabled. Checkout also filters cards in Apple and Google Pay wallets, customer’s [saved payment methods](https://docs.stripe.com/payments/checkout/save-during-payment.md), and [networks from co-badged cards](https://docs.stripe.com/co-badged-cards-compliance.md). --- # Source: https://docs.stripe.com/issuing/cards/physical/card-bundle-selections.md # Customize card bundle Make your card bundle selections. During the design phase, Stripe provides a design form where you can choose from the following standard options. Additionally, there are many innovative products in the physical cards market, such as LED-powered cards that light up in point-of-sale terminals, wooden cards, and recycled ocean plastic cards. These options are outside our standard offerings, but we can arrange expert-driven sessions to help you learn more about them. ## Choose card body The following table displays the available card body options. We can also ship you generic samples of these materials. “Core color options” refers to the color on the edge of the card. | **Card material** | **Description** | **Core color options** | **Weight (grams)** | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------ | | Plastic (PVC) | - Industry standard plastic card. - Edge of the card is the color of the plastic. | - White - Black - Red - Blue - Translucent - Custom PMS color | 6 g | | Recycled PVC | - Plastic card made up of 85.5% recycled PVC. You can include this statement on the card. - Edge of the card is the color of the plastic. | - White (the whiteness of the card might vary slightly due to the recycled plastic) | 6 g | | Embedded Metal | - Stainless steel core encapsulated in a PVC shell. - Edge of the card is the color of the plastic. | - White - Black | 11 g – 13 g | | Standard Metal | - Stainless steel core encapsulated in a PVC shell. - Edge of the card is metal. | - Metal | 12 g – 14 g | | Heavy Metal | - Heavyweight tungsten core encapsulated in a PVC shell. - Edge of the card is metal. | - Metal | 18 g – 22 g | ## Choose carrier type The following table captures the available custom carrier and compatible envelope options. If you don’t want a custom carrier, you can also combine your custom card with the standard carrier and set it up when the bundle is available in the Issuing Dashboard. | **Carrier type** | **Description** | **Envelope compatibility** | | ---------------- | ------------------------------------------------------------- | -------------------------- | | Standard trifold | White trifold with black text added in the Issuing Dashboard. | Window #10 | | Custom trifold | Customization on the carrier with your brand colors or logos. | Window #10 | | Custom bifold | Customization on the carrier with your brand colors or logos. | 6 x 91/4 | The following tables lists the carrier specs: | **Carrier** | **Trifold** | **Bifold** | | ---------------- | ------------------------ | ----------------- | | Paper size | 8.5" x 11" | 8.5" x 11" | | Fold | 2 horizontal folds | 1 horizontal fold | | Card location | Middle-right panel | Bottom-left panel | | Card orientation | Horizontal | Horizontal | | Color | 80# offset white | 100# offset white | | Finish | Matte/uncoated | Matte/uncoated | | Envelope size | 41/8 x 91/2 (Window #10) | 6 x 91/4 | ## Choose envelope type Stripe offers various custom envelope options in addition to the standard white envelopes. Let us know which packaging option interests you and we’ll provide more details to assist you throughout the process. Options with customized exteriors are reviewed for PCI compliance. The envelope can’t have any visual or implied indication there’s a card inside. | **Envelope type** | **Description** | **Carrier compatibility** | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | | Standard Window #10 | White industry standard envelope. | Trifold | | Standard 6 x 91/4 | White industry standard envelope. | Bifold | | Custom Window #10 | Customization on the envelope’s exterior with your brand colors or logos for a personalized look. | Trifold | | Custom 6 x 91/4 | Customization on the envelope’s exterior with your brand colors or logos for a personalized look. | Bifold | | Enhanced packaging | For a more unique unboxing experience, we partner with [Burgopak](https://burgopak.com/). You can choose from five options, including solutions with sliding mechanisms and book-like formats. If you’re interested, we can walk you through more details during a design session. These might require additional time for testing and added costs. | No carrier included | ## Optional: Add specialty treatments The following additional effects and features are available for custom card designs. Stripe can arrange to ship various samples to see the treatments firsthand, and aid in the decision-making process. | **Treatments** | **Description** | **PVC** | **Metal** | **Front of card** | **Back of card** | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | --------------- | ----------------- | ---------------- | | Knockout | Adds distinction in areas where you can expose the core color of the card. For example, if you have a metal card, you can showcase the metal material on your brand logo by choosing to expose it in that specific area. | ✓ Supported | ✓ Supported | ✓ Supported | - Not supported | | Post laminate finish (PLF) | Highlights certain areas or logos on the card by adding a different texture on top. For example, you can choose to have a glossy finish on the card and then apply a matte PLF on your logo, or vice versa. This creates an elevated texture on the logo compared to the rest of the card, providing a visual and tactile distinction. | ✓ Supported | ✓ Supported | ✓ Supported | - Not supported | | Metallic foil | Applies a thin layer of metallic foil onto the surface of the card, creating a reflective and shiny appearance. You can use this technique to partially highlight or mask the metalized effect on the face of the card by using translucent or opaque inks. The combination of the foil and the inks creates a striking visual effect on the card design. | ✓ Supported | ✓ Supported | ✓ Supported | - Not supported | | Metallic ink | Prints silver or gold ink over the card and then your design is printed on top to create a metallic appearance. Metallic ink is also commonly used for logos or product identifiers, adding a touch of elegance and shine to the card design. | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | | Pearlescent ink | Provides a metallic sheen with “sparkles” to either specific parts or the entire card. It can give a shiny quality to almost any image or design element when overprinted. Pearlescent ink adds a subtle shimmer and depth, enhancing the overall visual appeal of the card design. | ✓ Supported | ✓ Supported | ✓ Supported | ✓ Supported | | Accessibility notch | Assists individuals with visual impairments. This notch is designed to provide tactile feedback and aid in the identification and orientation of the card. | ✓ Supported | - Not supported | - Not supported | - Not supported | ## Optional: Activation labels Stripe offers activation labels that you can add to your cards with additional instructions tailored to your activation flow. We work with you to customize the printed text on the activation label. - Activation labels are pre-printed stock, and Stripe manages the procurement process for your custom activation label inventory. - Activation labels are available in matte or glossy stock and text are printed in CMYK colors. - This option is only available for cards with standard horizontal orientation with left-oriented chip. ![An example of an activation label](https://b.stripecdn.com/docs-statics-srv/assets/physical-card-activation-label.71bd719990a62c90a05dd9e8feeeb56b.png) An example of an activation label --- # Source: https://docs.stripe.com/payments/link/card-element-link.md # Link in the Card Element Enable checkout using Link with the Card Element. > Stripe no longer recommends using the Card Element as part of your Web Elements integration. To integrate Link, use one of our preferred Elements: the [Link Authentication Element](https://docs.stripe.com/payments/link/link-authentication-element.md), [Express Checkout Element](https://docs.stripe.com/payments/link/express-checkout-element-link.md), or [Payment Element](https://docs.stripe.com/payments/link/payment-element-link.md). Use [Link](https://docs.stripe.com/payments/link.md) in the Card Element to save and autofill payment information for your customers, so they don’t need to enter their payment details manually. The Card Element can take on two forms: a single line [Card Element](https://docs.stripe.com/js/element/other_element?type=card) or split Elements (like [Card Number](https://docs.stripe.com/js/element/other_element?type=cardNumber), [Expiry](https://docs.stripe.com/js/element/other_element?type=cardExpiry), and [CVC](https://docs.stripe.com/js/element/other_element?type=cardCvc)). When referring to the Card Element, the following information applies to both forms. ## The Link flow #### Single line Card Element When Link is enabled, the card input form displays a **Link** button, which an authenticated customer can click to autofill their payment details. They only need to authenticate their account once every 90 days on any Link-enabled business. ![Link autofilling customer payment details](https://b.stripecdn.com/docs-statics-srv/assets/link-single-ce-returning-user.e50d94e96551810ac4f95c2fabfd33b9.png) Link autofilling customer payment details If a customer hasn’t signed up for Link and they click the **Link** button, they’re asked to add their email address, phone number, and payment method. A customer can also enter their card details into the Card Element first, and save that card in a Link account. ![A customer signing up for Link](https://b.stripecdn.com/docs-statics-srv/assets/link-single-ce-new-user.b8495f2e5258b8cf04b5d43e3a290ec0.png) A customer signing up for Link If a returning Link customer clicks the **Link** button and needs to authenticate, Link asks them to do it with an SMS or email code. After the customer authenticates, Link loads their previously saved payment details, allowing them to check out faster. ![Link authenticating a customer](https://b.stripecdn.com/docs-statics-srv/assets/link-in-ce-dialog.ec3340f0aaa847f610249e7dcc3fb7ad.png) Link authenticating a customer We’re continuously optimizing Link to improve checkout conversion, and may selectively show Link when it’s most beneficial to customers at checkout. You can expect to see changes over time, including how and when Link appears. #### Split Elements When Link is enabled, the card input form displays a **Link** button, which an authenticated customer can click to autofill their payment details. They only need to authenticate their account once every 90 days on any Link-enabled business. If a customer hasn’t signed up for Link and they click the **Link** button, they’re asked to add their email address, phone number, and payment method. A customer can also enter their card details into the Card Element first, and save that card in a Link account. If a returning Link customer clicks the **Link** button and needs to authenticate, Link asks them to do it with an SMS or email code. After the customer authenticates, Link loads their previously saved payment details, allowing them to check out faster. We’re continuously optimizing Link to improve checkout conversion, and might selectively show Link when it’s most beneficial to customers at checkout. You can expect to see changes over time, including how and when Link appears. ## Link enablement The [Card Element](https://docs.stripe.com/js/element/other_element?type=card) supports Link globally for all businesses with granted access and doesn’t require additional fees or code changes (see note below for details). Link is fully compatible with the other features you receive from card payments. Stripe automatically enables Link in the Card Element. You can disable Link for all instances of the Card Element in your [Payment Method settings](https://dashboard.stripe.com/settings/payment_methods). In the Link section, click the overflow menu (⋯) next to the Link row, and disable **Link in Card Element**. This setting applies to both forms of the Card Element. You can also set the [disableLink](https://docs.stripe.com/js/elements_object/create_element?type=card#elements_create-options-disableLink) parameter to `true` to disable Link in the Card Element. You only need to use one of these controls to hide Link in the Card Element. Link *isn’t* visible in the Card Element if: - The parent container that the Card Element is mounted in is too short in height or narrow in width to display the Link button. Typically, we require a minimum width of 350px and height of 28px. However, other factors such as font size, locale, placeholder text, and card icon visibility can also affect these requirements. - The Card Element is displayed on a browser that doesn’t support pop-ups, including in-app browsers. View information about [supported browsers](https://docs.stripe.com/payments/link/card-element-link.md#test-link-in-the-card-element). - The [Cross-Origin-Opener-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy) is set to `same-origin`. The Link pop-up must communicate with the page that opened it, so Link in the Card Element isn’t compatible with configurations that block this communication. > We’re releasing Link in the Card Element in phases. Link for the [single line Card Element](https://docs.stripe.com/js/element/other_element?type=card) was released in 2023, followed by Link in [split Elements](https://docs.stripe.com/js/element/other_element?type=cardNumber) in late 2023 and early 2024. Only accounts with granted access can see Link in the Card Element in their [Payment Method settings](https://dashboard.stripe.com/settings/link) or use Link in production or in a sandbox. Link isn’t currently supported for Stripe accounts based in India. ## Use the Card Element and Payment Request Button You can also use Link with the [Payment Request Button](https://docs.stripe.com/payments/link/payment-request-button-link.md). Link in the Card Element operates independently from Link in the Payment Request button. If you use both the Payment Request Button and the Card Element, Link might appear in both during checkout. For more information on when Link appears in the Payment Request Button, see [Link in the Payment Request Button](https://docs.stripe.com/payments/link/payment-request-button-link.md). ## Link and Connect platforms Link is automatically available to any connected accounts that access the Card Element through a Connect integration. Depending on the integration, some platforms can allow connected accounts to customize their own Link settings in the Dashboard. ### Eligibility requirements for connected platforms If the following conditions are all met by your platform, then your connected accounts can manage their Link settings directly in their own Dashboard. - You use [direct charges](https://docs.stripe.com/connect/direct-charges.md). - You create and charge payment methods on your connected accounts. - Your connected accounts have access to the full Stripe Dashboard. To set the default state for all connected accounts on your platform: 1. Click **Edit settings** under **Your connected accounts** in [Payment Method settings](https://dashboard.stripe.com/settings/connect/payment_methods). 1. Navigate to **Link in the Card Element** in the Link section. ### Ineligible connected platforms In the following cases, Link is controlled by your platform account settings, and your connected accounts can’t customize their Link settings for payments processed through your platform: - You create payment methods on your platform and then [clone payment methods](https://docs.stripe.com/connect/direct-charges-multiple-accounts.md#clone-and-create-direct-charges) to your connected accounts. - You use [destination charges](https://docs.stripe.com/connect/destination-charges.md) or [separate charges and transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md). - Your connected accounts don’t have access to the full Stripe Dashboard. To manage your platform account settings: 1. Click **Edit settings** under **Your Account** in [Payment Method settings](https://dashboard.stripe.com/settings/connect/payment_methods). 1. Navigate to **Link in the Card Element** in the Link section. If you want to turn Link off for only specific connected accounts, you can use the [disableLink](https://docs.stripe.com/js/elements_object/create_element?type=card#elements_create-options-disableLink) parameter. ### Payment processing for connected accounts - If your platform lets you customize your Link settings for platform payments, then you can manage your Link in Card Element settings within [Payment Method settings](https://dashboard.stripe.com/settings/payment_methods) by selecting your platform from the dropdown menu at the top of the page. - If your platform can’t offer you settings customization, then the platform determines Link’s availability for all payments processed through the platform, and you won’t have settings control for platform payments in your Dashboard. - For payments you process without a platform, you can manage Link in your [Payment Method settings](https://dashboard.stripe.com/settings/payment_methods) by selecting “no platform” from the dropdown menu at the top of the page. ## Test Link in the Card Element > Don’t store real user data in *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) Link accounts. Treat them as if they’re publicly available, because these test accounts are associated with your publishable key. Link works with the following browsers: - Chrome, Chrome Mobile, and Microsoft Edge. - Safari on desktop and iOS (last 3 major versions). Link is available in both production and in a sandbox. You can create sandbox Link accounts using any valid email address. The following table shows the fixed one-time passcode values that Stripe accepts for authenticating Link sandbox accounts: | Value | Outcome | | ----------------------------------- | ---------------------------- | | Any other 6 digits not listed below | Success | | 000001 | Error, code invalid | | 000002 | Error, code expired | | 000003 | Error, max attempts exceeded | Enabling Link in a sandbox presents Link on all Card Element sandbox sessions that meet the [enablement requirements](https://docs.stripe.com/payments/link/card-element-link.md#enable-link). In production, Link’s visibility might vary to maximize Link’s conversion benefits in each checkout session. ## See also - [Stripe Web Elements](https://docs.stripe.com/payments/elements.md) - [Link Authentication Element](https://docs.stripe.com/payments/elements/link-authentication-element.md) - [Payment Element](https://docs.stripe.com/payments/payment-element.md) --- # Source: https://docs.stripe.com/disputes/prevention/card-testing.md # Protect yourself from card testing Learn about this fraudulent activity and how to protect yourself against it. Card testing is a type of fraudulent activity where someone tries to determine whether stolen card information is valid so that they can use it to make purchases. A fraudster might do this by purchasing stolen credit card information, and then attempting to validate or make purchases with those cards to determine which cards are still valid. Other common terms for card testing are “carding”, “account testing”, “enumeration”, and “card checking.” Fraudulent activity such as card testing is an unavoidable part of online commerce. Card testing, however, has consequences for the entire payments ecosystem, so merchants, card networks, and Stripe share responsibility to prevent it. At Stripe, we’re constantly improving our tools and systems to detect and reduce fraud, but you must remain vigilant with respect to fraud. ## How card testing works Card testers use both card setup and payments to determine whether the stolen or enumerated card information they have is valid or not. To quickly validate many card numbers, fraudsters use scripts to test a large amount of card information at once, and collect 3DS or issuer responses to validate which card information is valid. After they have identified the valid cards, they can cash them with merchants or resell confirmed cards on the dark web. - **Card Setup**—This is a method preferred by fraudsters, as card validation and authorizations during card setup don’t typically show up on cardholder statements. This reduces the likelihood of card holders noticing and reporting the fraudulent activity. - **Payments**—Card testers create small amount payments, which cardholders are less likely to notice and report as fraudulent. ## Card testing consequences Card testing has many negative outcomes, some of which get worse over time as card testing continues: - **Disputes**— Many types of card testing involve payments, some of which succeed. Customers notice successful payments and report them as fraud, which result in [Early Fraud Warnings](https://docs.stripe.com/disputes/measuring.md#early-fraud-warnings) or even [fraudulent disputes](https://docs.stripe.com/disputes.md) that cost you time and money. - **Higher decline rates**—Card testing associates a large number of declines with your business. A high decline rate might damages the reputation of your business with card issuers and card networks, which makes all of your transactions appear riskier. This can result in an increased decline rate for legitimate payments, even after card testing ceases. - **Additional fees**—Card testing activity can result in additional fees, such as authorization fees for custom pricing plans, and dispute fees. - **Infrastructure strain**—Card testing usually results in numerous network requests and operations. This additional traffic can overburden your infrastructure and disrupt legitimate activity. - **Damages ecosystem health**—Card testing has negative impacts on the financial system as a whole, so both Stripe and our financial partners want to help you stop it. A large amount of card testing resulting in Early Fraud Warnings or Disputes might, for example, enlist you into [Card Monitoring Programs](https://docs.stripe.com/disputes/monitoring-programs.md). - **Reduce quality of data for your business to operate**-Revenue from card testing might look like good, new customers in your data, so it becomes hard for you to have a clear line of sight on your real business growth. ## Active card testing checklist If your integration is being exploited by card testers, we recommend that you take the following actions immediately: - [Identify](https://docs.stripe.com/disputes/prevention/card-testing.md#identify-card-testing) the card testing activity. - [Refund](https://docs.stripe.com/refunds.md) fraudulent payments to avoid disputes. - [Use a Stripe-recommended integration](https://docs.stripe.com/disputes/prevention/card-testing.md#optimize-integration) or add [mitigations](https://docs.stripe.com/disputes/prevention/card-testing.md#control-implementation) to suppress card testing. - Monitor your integration to make sure your mitigations are effective. ## Identify card testing You can identify most card testing activity by a significant increase in failed authorization and payments. Most attacks are obvious in your Stripe Dashboard. The common symptoms to look out for are: - **A spike in failed or blocked payments.** You can see the trends on [the Dashboard home page](https://dashboard.stripe.com/dashboard), the [transactions](https://dashboard.stripe.com/payments) list view, and you can examine the block reasons on the payment details page. - **A spike in requests with 402 errors**. You can see the volume spike on the [Developers](https://dashboard.stripe.com/developers) page, examine 402 failures on the [failed Logs](https://dashboard.stripe.com/logs?error_type=card_error) page or listen to webhooks and API responses, in particular with an [outcome of “generic_decline”](https://docs.stripe.com/declines/codes.md). - **A spike in suspicious payments** with low transaction amounts, often with nonsensical customer names and emails. To avoid disputes, we recommend refunding these suspicious transactions if they get through the existing defenses. ## Prevent card testing Card testers employ a wide variety of techniques to make their fraudulent activity difficult to block. As a result, simple firewall rules or filters based on a single heuristic such as IP addresses are usually not sufficient to prevent card testing on their own. Card testers can use your publishable key and use it to retry a large number of payments on your website. You have two main mitigation strategies for such attacks: - **Use a recommended Stripe integration–** Choose a Stripe-recommended integration to take advantage of card testing protection that we know works. - **Control implementation–** Invest in a suite of controls that stops card testers from attacking vulnerable endpoints. In addition to implementing mitigation strategies, you want to make sure that you’re keeping your keys safe and don’t publish your secret key publicly. When your credentials are leaked or stolen, card testers can create payments and set up cards using your secret key. > Not a developer? Using a plugin or platform? Preventing and mitigating card testing typically requires code-level changes, so you’ll need to show this documentation to the developer or vendor who wrote the code and work with them to prevent card testing. ### Use a Stripe-recommended integration If you use Stripe’s latest Payment Element or Checkout, we have many automated and manual controls in place to mitigate card testing, including rate limiters, AI models, CAPTCHA triggers, ongoing reviews, and so on. When we detect that you’re under a card testing attack, we dynamically choose interventions to suppress the attack as much as possible, while still allowing legitimate users to transact on your account with minimal impact. You see these payments marked as `Blocked by Stripe`. *However, the success of Stripe’s controls depends on your integration and what signals you send to us*. We use many signals to distinguish between card testing and legitimate payments. While we compute some of these signals automatically, many of them depend on the information that your integration provides. In general, the more data your integration provides, the more successful card testing prevention can be. We recommend using one of Stripe’s [recommended integrations](https://docs.stripe.com/payments/online-payments.md#compare-features-and-availability) to take advantage of the automated [CAPTCHA](https://www.hcaptcha.com/) based protection. Modern CAPTCHA solutions apply multiple signals to increase friction for high-risk behavior, while appearing mostly invisible to legitimate users of your service. To opt out of our CAPTCHA integration, reach out to [Stripe Support](https://support.stripe.com/contact/login). Using one of our recommended payment integrations allows you to get the most out of Stripe’s card testing prevention. If you can’t use a recommended integration, include as much data as possible or implement your own controls. While card testing controls are separate from Radar’s protection against fraudulent disputes, they benefit [from the same signals used by Radar](https://docs.stripe.com/radar/optimize-fraud-signals.md). Including the following information with your payments can have a significant impact on the performance of Stripe’s card testing models. Our recommended integrations enable you to collect this information, while direct integrations might need to explicitly include this data. - [Advanced fraud detection](https://docs.stripe.com/disputes/prevention/advanced-fraud-detection.md) (Highest impact) - IP address - Customer email - Customer name - Billing address ### Control implementation Adding restrictions to targeted endpoints help you suppress and prevent card testing. The restrictions you implement can make card testing impractical while having little to no impact on your legitimate traffic. Endpoints targeted by card testers typically allow them to do one of the following: - Save card. - Make a payment. The specific security measures you add to your integration vary depending on your situation and the needs of your business. We describe several common approaches below. ### Implement CAPTCHA Card testers often use automated scripts that CAPTCHA can block. The scripts are especially effective if you’re not using one of the recommended integrations that supports CAPTCHA. Modern CAPTCHA solutions provide options for both visible and invisible CAPTCHAS, depending on your needs. If you’ve added a CAPTCHA to your integration but card testing hasn’t stopped, check the following: - Make sure the CAPTCHA requires validation on all requests that enable card validations or payments with Stripe. - Review the CAPTCHA documentation to make sure that you’ve implemented it on the server side. - If you’re using a CAPTCHA solution that provides a score, adjust the threshold at which you prevent requests from succeeding. - Try a different CAPTCHA solution, such as switching from an invisible CAPTCHA to a visible one, or using a different CAPTCHA solution entirely. ### Limit access to your payment form The easier it is for fraudulent actors to reach your payment form (for example, using guest checkout), the easier it is for them to execute card testing attacks. You can reduce your exposure to card testers by requiring login or session validation before they can make a payment. Some of [the safeguards that protect against cross-site request forgery (CSRF) attacks](https://owasp.org/www-project-cheat-sheets/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html) are also effective against some types of card testing, such as CSRF tokens. ### Add rate limits In some cases, you can reduce card testing by adding networking rate limits (for example, in your web shop front end). Tailor these rate limits to stop the specific kind of card testing you’re experiencing. For example, if card testers use your integration to validate cards by attaching them to new customers, an effective deterrent might be to limit the number of new customers that can be created by a single IP address in 1 day. In addition to network rate limits, you can add rate limits to your payments and cart checkout flow to [detect and prevent unusual behavior](https://docs.stripe.com/disputes/prevention/card-testing.md#prevent-unusual-behavior) even after login or signup. ### Detect and prevent unusual behavior Use the Dashboard, [webhooks](https://docs.stripe.com/webhooks.md), or continuous monitoring with [Stripe Sigma or Data Pipelines](https://stripe.com/guides/improve-fraud-management-with-radar-for-fraud-teams-and-stripe-data) to track anomalies in your traffic. You can compare card testing activity to typical legitimate traffic, and then build filters that limit or prevent only the card testing activity. For example, you might make changes to your system that: - Limit the number of cards that can be added to an account - Limit the number of customers that can be created with a single IP address - Limit the number of purchases that can be made with same product - Limit the number of customers of the same type that can be created - Filter out requests with certain user agents or other parameters To do so, you can use [custom rules](https://docs.stripe.com/radar/rules/reference.md#velocity-rules) in Radar for Fraud Teams. We cover that in the next section. ### Use a combination of mitigations It might make sense to combine multiple approaches to reduce card testing to maximize the impact on fraudulent activity without having an adverse effect on legitimate traffic. For example, you might combine CAPTCHAS and rate limits so the first payment attempt from an IP address succeeds without restriction, but subsequent requests made by that same IP address for the next several hours require a captcha verification to succeed. ### Retry carefully Excessive retries (dunning) of payments can look like card testing if they come in extreme spikes with low success rate. Dunning and real card testing attacks might have similar effects on your business, including issuers hardening their risk stance. Make sure that you don’t keep retrying cards set up on fraudulent customers after a card testing attack, because this repeats the original attack. Stripe’s [Smart Retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries.md#non-retryable-decline-codes) already take this into consideration. ### Customize protection based on your risk appetite Beyond the implementing mitigations, you might want to further fine tune your protection using Radar. It comes with built-in rules to block based on [bank checks](https://docs.stripe.com/radar/rules.md#traditional-bank-checks), such as *CVC* (The card verification code (CVC) or card verification value (CVV) is a three- or four-digit number printed directly on a card used to verify the entered card number) checks. If you understand your customer behavior and want to customize the velocity of payments in detail, you can build [custom rules](https://docs.stripe.com/radar/rules/reference.md#velocity-rules) in Radar for Fraud Teams. You can find examples in the [Radar 101 guide](https://stripe.com/guides/radar-rules-101#rules-that-help-prevent-card-testing-or-card-cashing). ## See also - [Advanced fraud detection](https://docs.stripe.com/disputes/prevention/advanced-fraud-detection.md) - [Optimizing your Radar integration](https://docs.stripe.com/radar/optimize-fraud-signals.md) - [Keeping your keys safe](https://docs.stripe.com/keys-best-practices.md) - [Radar 101 guide](https://stripe.com/guides/radar-rules-101) --- # Source: https://docs.stripe.com/payments/cartes-bancaires.md # Cartes Bancaires (CB) Learn about Cartes Bancaires, a common payment method in France. Cartes Bancaires is France’s local card network. More than 95% of these cards are co-badged with either Visa or Mastercard, meaning you can process these cards over either Cartes Bancaires or the Visa or Mastercard networks. Businesses processing co-badged cards in the EEA must provide customers a choice of which network they prefer at checkout. Learn more in our [guide for co-badged cards compliance](https://docs.stripe.com/co-badged-cards-compliance.md). Cartes Bancaires can have a positive effect on your acceptance rate in France. If a charge is declined on the Cartes Bancaires network for a technical reason, Stripe [automatically retries the charge](https://stripe.com/payments/features#authorization) on Visa or Mastercard’s networks. #### Payment method properties - **Customer locations** Europe - **Presentment currency** EUR - **Payment confirmation** Customer-initiated - **Payment method family** Cards - **Recurring payments** Yes - **Payout timing** Standard payout timing applies - **Connect support** Yes - **Dispute support** [Yes](https://docs.stripe.com/payments/cartes-bancaires.md#disputes) - **Manual capture support** Yes - **Multicapture support** Yes - **Refunds / Partial refunds** Yes / Yes #### Business locations Stripe accounts in the following countries can accept Cartes Bancaires payments with local currency settlement. - AT - AU - BE - BG - CA - CH - CY - CZ - DE - DK - EE - ES - FI - FR - GB - GI - GR - HK - HR - HU - IE - IS - IT - JP - LI - LT - LU - LV - MT - MX - NL - NO - NZ - PL - PT - RO - SE - SG - SI - SK - US #### Product support - Connect - Checkout - Payment Links - Subscriptions - Invoicing - Elements1 - Terminal2 1Express Checkout Element doesn’t support Cartes Bancaires. 2Terminal integrations have [specific regional requirements](https://docs.stripe.com/terminal/payments/regional.md?integration-country=FR) to process Cartes Bancaires cards in France. ## Availability If your business isn’t based in France, you must first process one payment from a Cartes Bancaires eligible card to fully enable this payment method. ## Disputes As with Visa and Mastercard, cardholders can dispute Cartes Bancaires charges. Because Cartes Bancaires dispute rules are more stringent, there are fewer reasons that a cardholder can dispute a charge, which on average leads to a lower dispute rate compared to Visa and Mastercard. Businesses can’t contest Cartes Bancaires disputes. The dispute fee is 0 EUR on Cartes Bancaires. ## Integration If you can already [accept card payments](https://docs.stripe.com/payments/accept-a-payment.md), you can accept Cartes Bancaires. See the [co-badged cards compliance guide](https://docs.stripe.com/co-badged-cards-compliance.md) to learn how to best handle customer priority selection, and to find multiple test cards that you can use to test your integration as soon as it’s active. If you require that Cartes Bancaires is never the default network for any payments, contact [Stripe Support](https://support.stripe.com/contact). --- # Source: https://docs.stripe.com/issuing/categories.md # Issuing merchant categories Learn about the available categories that businesses are grouped in. Every business that processes card payments is categorized using [Merchant Category Codes](https://en.wikipedia.org/wiki/Merchant_category_code) (MCC). The category name is provided as a value for `merchant_data.category` on [Authorization](https://docs.stripe.com/api.md#issuing_authorization_object) objects. If a business doesn’t fit into a specific category, it’s categorized as `miscellaneous`. You can use these categories when creating [spending controls](https://docs.stripe.com/issuing/controls/spending-controls.md) to restrict issued cards from being used with certain business types. You can also use [enriched merchant data](https://docs.stripe.com/issuing/purchases/enriched-merchant-data.md) to set more granular controls. --- # Source: https://docs.stripe.com/billing/subscriptions/change-price.md # Change the price of existing subscriptions Learn how to upgrade and downgrade subscriptions by changing the price. This guide focuses on using the Subscriptions API to manage customer subscriptions. You can also implement the [customer portal](https://docs.stripe.com/customer-management.md) to provide a Stripe-hosted Dashboard where customers can manage their subscriptions and billing details. When a customer changes their subscription, you must change the subscription item to reflect the new selection. For example, a customer might upgrade to a premium tier or downgrade to a basic tier, prompting you to replace the underlying price of that subscription item. You can do this using a few different methods. > #### Compare Customers v1 and Accounts v2 references > > If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. ## Retrieve the identifiers Regardless of the method you choose, you need to provide identifiers for the objects you’re updating. Use the [list subscriptions](https://docs.stripe.com/api/subscriptions/list.md) method with a relevant filter (such as the customer ID) to find the subscription and item to update. ```curl curl -G https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d customer={{CUSTOMER_ID}} ``` ```cli stripe subscriptions list \ --customer={{CUSTOMER_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscriptions = client.v1.subscriptions.list({customer: '{{CUSTOMER_ID}}'}) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscriptions = client.v1.subscriptions.list({"customer": "{{CUSTOMER_ID}}"}) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscriptions = $stripe->subscriptions->all(['customer' => '{{CUSTOMER_ID}}']); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionListParams params = SubscriptionListParams.builder().setCustomer("{{CUSTOMER_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. StripeCollection stripeCollection = client.v1().subscriptions().list(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscriptions = await stripe.subscriptions.list({ customer: '{{CUSTOMER_ID}}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionListParams{Customer: stripe.String("{{CUSTOMER_ID}}")} result := sc.V1Subscriptions.List(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionListOptions { Customer = "{{CUSTOMER_ID}}" }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; StripeList subscriptions = service.List(options); ``` The returns the set of subscriptions for the specified customer, from which you can retrieve the subscription ID (`id`), any subscription item IDs (`items.data.id`) and the subscription items price ID (`items.data.price.id`). ```json { "object": "list", "url": "/v1/subscriptions", "has_more": false, "data": [ {"id": "su_1NXPiE2eZvKYlo2COk9fohqA", "object": "subscription", "application": null, "application_fee_percent": null, "automatic_tax": { "enabled": false },"items": { "object": "list", "data": [ { "id": "si_OK3pbS1dvdQYJP", "object": "subscription_item", "billing_thresholds": null, "created": 1690208774, "metadata": {},"price": { "id": "price_1NOhvg2eZvKYlo2CqkpQDVRT", "object": "price" } } ] } } ] } ``` ## Update the subscription [Update a subscription](https://docs.stripe.com/api.md#update_subscription) including the following parameters: - `item ID`: You must specify the subscription item to replace the current price with the new price. Otherwise, updating the subscription with a new price *adds* a new subscription item so both prices are active for the subscription. - `item price`: Provide the identifier for the replacement price. - `item quantity`: Updating a subscription price automatically reverts the quantity to the default value of `1`. If the existing subscription quantity is anything other than `1` and you want to preserve that value, you must include it in the update. ```curl curl https://api.stripe.com/v1/subscriptions/sub_xxxxxxxxx \ -u "<>:" \ -d "items[0][id]"={{SUB_ITEM_ID}} \ -d "items[0][price]"={{NEW_PRICE_ID}} ``` ```cli stripe subscriptions update sub_xxxxxxxxx \ -d "items[0][id]"={{SUB_ITEM_ID}} \ -d "items[0][price]"={{NEW_PRICE_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.update( 'sub_xxxxxxxxx', { items: [ { id: '{{SUB_ITEM_ID}}', price: '{{NEW_PRICE_ID}}', }, ], }, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.update( "sub_xxxxxxxxx", {"items": [{"id": "{{SUB_ITEM_ID}}", "price": "{{NEW_PRICE_ID}}"}]}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->update( 'sub_xxxxxxxxx', [ 'items' => [ [ 'id' => '{{SUB_ITEM_ID}}', 'price' => '{{NEW_PRICE_ID}}', ], ], ] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionUpdateParams params = SubscriptionUpdateParams.builder() .addItem( SubscriptionUpdateParams.Item.builder() .setId("{{SUB_ITEM_ID}}") .setPrice("{{NEW_PRICE_ID}}") .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().update("sub_xxxxxxxxx", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.update( 'sub_xxxxxxxxx', { items: [ { id: '{{SUB_ITEM_ID}}', price: '{{NEW_PRICE_ID}}', }, ], } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionUpdateParams{ Items: []*stripe.SubscriptionUpdateItemParams{ &stripe.SubscriptionUpdateItemParams{ ID: stripe.String("{{SUB_ITEM_ID}}"), Price: stripe.String("{{NEW_PRICE_ID}}"), }, }, } result, err := sc.V1Subscriptions.Update(context.TODO(), "sub_xxxxxxxxx", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionUpdateOptions { Items = new List { new SubscriptionItemOptions { Id = "{{SUB_ITEM_ID}}", Price = "{{NEW_PRICE_ID}}", }, }, }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Update("sub_xxxxxxxxx", options); ``` > You must specify the subscription item to replace the current price with the new price. Failing to do so results in *adding* the new price so both prices are active for the subscription. Alternatively, you can delete the current subscription item and create a new subscription item with the updated price. ```curl curl https://api.stripe.com/v1/subscriptions/sub_xxxxxxxxx \ -u "<>:" \ -d "items[0][id]"={{SUB_ITEM_ID}} \ -d "items[0][deleted]"=true \ -d "items[1][price]"={{NEW_PRICE_ID}} ``` ```cli stripe subscriptions update sub_xxxxxxxxx \ -d "items[0][id]"={{SUB_ITEM_ID}} \ -d "items[0][deleted]"=true \ -d "items[1][price]"={{NEW_PRICE_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.update( 'sub_xxxxxxxxx', { items: [ { id: '{{SUB_ITEM_ID}}', deleted: 'true', }, {price: '{{NEW_PRICE_ID}}'}, ], }, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.update( "sub_xxxxxxxxx", {"items": [{"id": "{{SUB_ITEM_ID}}", "deleted": True}, {"price": "{{NEW_PRICE_ID}}"}]}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->update( 'sub_xxxxxxxxx', [ 'items' => [ [ 'id' => '{{SUB_ITEM_ID}}', 'deleted' => true, ], ['price' => '{{NEW_PRICE_ID}}'], ], ] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionUpdateParams params = SubscriptionUpdateParams.builder() .addItem( SubscriptionUpdateParams.Item.builder() .setId("{{SUB_ITEM_ID}}") .setDeleted(true) .build() ) .addItem(SubscriptionUpdateParams.Item.builder().setPrice("{{NEW_PRICE_ID}}").build()) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().update("sub_xxxxxxxxx", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.update( 'sub_xxxxxxxxx', { items: [ { id: '{{SUB_ITEM_ID}}', deleted: true, }, { price: '{{NEW_PRICE_ID}}', }, ], } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionUpdateParams{ Items: []*stripe.SubscriptionUpdateItemParams{ &stripe.SubscriptionUpdateItemParams{ ID: stripe.String("{{SUB_ITEM_ID}}"), Deleted: stripe.Bool(true), }, &stripe.SubscriptionUpdateItemParams{Price: stripe.String("{{NEW_PRICE_ID}}")}, }, } result, err := sc.V1Subscriptions.Update(context.TODO(), "sub_xxxxxxxxx", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionUpdateOptions { Items = new List { new SubscriptionItemOptions { Id = "{{SUB_ITEM_ID}}", Deleted = true }, new SubscriptionItemOptions { Price = "{{NEW_PRICE_ID}}" }, }, }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Update("sub_xxxxxxxxx", options); ``` ## Update the subscription item [Update a subscription item](https://docs.stripe.com/api/subscription_items/update.md) using the following parameters: - [price](https://docs.stripe.com/api/subscription_items/update.md#update_subscription_item-price): Provide the identifier for the replacement price. - [quantity](https://docs.stripe.com/api/subscription_items/update.md#update_subscription_item-quantity): Updating a subscription price automatically reverts the quantity to the default value of `1`. If the existing subscription quantity is anything other than `1` and you want to preserve that value, you must include it in the update. Use this option if you don’t need to make any other changes at the subscription level. ```curl curl https://api.stripe.com/v1/subscription_items/si_xxxxxxxxx \ -u "<>:" \ -d price={{NEW_PRICE_ID}} ``` ```cli stripe subscription_items update si_xxxxxxxxx \ --price={{NEW_PRICE_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription_item = client.v1.subscription_items.update( 'si_xxxxxxxxx', {price: '{{NEW_PRICE_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription_item = client.v1.subscription_items.update( "si_xxxxxxxxx", {"price": "{{NEW_PRICE_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscriptionItem = $stripe->subscriptionItems->update( 'si_xxxxxxxxx', ['price' => '{{NEW_PRICE_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionItemUpdateParams params = SubscriptionItemUpdateParams.builder().setPrice("{{NEW_PRICE_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. SubscriptionItem subscriptionItem = client.v1().subscriptionItems().update("si_xxxxxxxxx", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscriptionItem = await stripe.subscriptionItems.update( 'si_xxxxxxxxx', { price: '{{NEW_PRICE_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionItemUpdateParams{Price: stripe.String("{{NEW_PRICE_ID}}")} result, err := sc.V1SubscriptionItems.Update(context.TODO(), "si_xxxxxxxxx", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionItemUpdateOptions { Price = "{{NEW_PRICE_ID}}" }; var client = new StripeClient("<>"); var service = client.V1.SubscriptionItems; SubscriptionItem subscriptionItem = service.Update("si_xxxxxxxxx", options); ``` ## Billing periods If both prices have the same billing periods (combination of `interval` and `interval_count`), the subscription retains the same billing dates. If the prices have different billing periods, the new price is billed at the new interval, starting on the day of the change. For example, switching a customer from one monthly subscription to another doesn’t change the billing dates. However, switching a customer from a monthly subscription to a yearly subscription moves the billing date to the date of the switch. Switching a customer from one monthly subscription to another monthly subscription while introducing a trial period also moves the billing date (to the conclusion of the trial). ### Subscription schedules If you’re changing a subscription at the end of its billing period, consider using a [subscription schedule](https://docs.stripe.com/billing/subscriptions/subscription-schedules.md#changing-subscriptions) to manage the transition. When using subscription schedules, follow [best practices](https://docs.stripe.com/billing/subscriptions/subscription-schedules.md#subscription-schedule-sub-updates) to prevent unexpected subscription overwrites. ## Usage-based billing with Billing Meters Details on mid-cycle updates for prices attached to a Billing Meter are described in the [pricing models](https://docs.stripe.com/billing/subscriptions/usage-based/manage-billing-setup.md#mid-cycle-updates) section. Passing `clear_usage` when updating a price with a Billing Meter has no effect. ## Usage-based billing with Usage Records (Legacy) If you have a metered price backed by legacy usage records and update to a new usage records price, the usage is transferred to the new price. ```curl curl https://api.stripe.com/v1/subscriptions/sub_xxxxxxxxx \ -u "<>:" \ -d "items[0][id]"={{SUB_ITEM_ID}} \ -d "items[0][price]"={{NEW_PRICE_ID}} \ -d "items[0][clear_usage]"=true ``` ```cli stripe subscriptions update sub_xxxxxxxxx \ -d "items[0][id]"={{SUB_ITEM_ID}} \ -d "items[0][price]"={{NEW_PRICE_ID}} \ -d "items[0][clear_usage]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.update( 'sub_xxxxxxxxx', { items: [ { id: '{{SUB_ITEM_ID}}', price: '{{NEW_PRICE_ID}}', clear_usage: 'true', }, ], }, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.update( "sub_xxxxxxxxx", { "items": [ {"id": "{{SUB_ITEM_ID}}", "price": "{{NEW_PRICE_ID}}", "clear_usage": True}, ], }, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->update( 'sub_xxxxxxxxx', [ 'items' => [ [ 'id' => '{{SUB_ITEM_ID}}', 'price' => '{{NEW_PRICE_ID}}', 'clear_usage' => true, ], ], ] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionUpdateParams params = SubscriptionUpdateParams.builder() .addItem( SubscriptionUpdateParams.Item.builder() .setId("{{SUB_ITEM_ID}}") .setPrice("{{NEW_PRICE_ID}}") .setClearUsage(true) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().update("sub_xxxxxxxxx", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.update( 'sub_xxxxxxxxx', { items: [ { id: '{{SUB_ITEM_ID}}', price: '{{NEW_PRICE_ID}}', clear_usage: true, }, ], } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionUpdateParams{ Items: []*stripe.SubscriptionUpdateItemParams{ &stripe.SubscriptionUpdateItemParams{ ID: stripe.String("{{SUB_ITEM_ID}}"), Price: stripe.String("{{NEW_PRICE_ID}}"), ClearUsage: stripe.Bool(true), }, }, } result, err := sc.V1Subscriptions.Update(context.TODO(), "sub_xxxxxxxxx", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionUpdateOptions { Items = new List { new SubscriptionItemOptions { Id = "{{SUB_ITEM_ID}}", Price = "{{NEW_PRICE_ID}}", ClearUsage = true, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Update("sub_xxxxxxxxx", options); ``` ## Proration Changing a subscription often results in a [proration](https://docs.stripe.com/billing/subscriptions/prorations.md) to apply the new price to the remaining days in the billing period. You can prepare your customer for any additional expense resulting from a price change by [previewing a proration](https://docs.stripe.com/billing/subscriptions/prorations.md#preview-proration). Alternatively, you can [disable prorations](https://docs.stripe.com/billing/subscriptions/prorations.md#disable-prorations). ### Immediate payment Stripe immediately attempts payment when a subscription’s billing cycle anchor is reset. Learn more about [resetting a subscription’s billing cycle anchor](https://docs.stripe.com/billing/subscriptions/billing-cycle.md#changing). When billing is performed immediately, but the required payment fails, the subscription change request succeeds and the subscription transitions to `past_due`. To bill a customer immediately for a change to a subscription on the same billing period, set `proration_behavior` to `always_invoice`. This calculates the proration, then immediately generates an *invoice* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) after making the switch. Combine this setting with [pending updates](https://docs.stripe.com/billing/subscriptions/pending-updates.md) so the subscription doesn’t update unless payment succeeds on the new invoice. ### Credit prorations Credit prorations are issued when customers downgrade their subscriptions or cancel subscription items before the end of their billing period. Stripe offers two approaches for calculating credit prorations, depending on your subscription’s [billing_mode](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-billing_mode) setting. See [Credit prorations](https://docs.stripe.com/billing/subscriptions/prorations.md#credit-prorations) for more details. ### Handle zero-amount prices and quantities If you’ve subscribed a customer to a zero-amount price (for example, as a trial), changing the price to a non-zero amount generates an invoice and resets the [billing period](https://docs.stripe.com/billing/subscriptions/change-price.md#billing-periods) to the date of the change. If you’ve subscribed a customer to a price with a non-zero amount and a zero-amount quantity, changing the quantity to a non-zero amount doesn’t generate an invoice or reset the billing period. ## See also - [Billing period (cycle)](https://docs.stripe.com/billing/subscriptions/billing-cycle.md) - [Canceling and pausing](https://docs.stripe.com/billing/subscriptions/cancel.md) - [Update Subscription API](https://docs.stripe.com/api.md#update_subscription) --- # Source: https://docs.stripe.com/billing/subscriptions/change.md # Modify subscriptions Change existing subscriptions to cancel, pause, apply prorated charges and credits, and more. You can change existing subscriptions without having to cancel and recreate them. Set up the [customer portal](https://docs.stripe.com/customer-management.md) to let your customers manage their own subscriptions and billing details through a Stripe-hosted page. For changes that automatically create a new [subscription invoice](https://docs.stripe.com/billing/invoices/subscription.md), use [pending updates](https://docs.stripe.com/billing/subscriptions/pending-updates.md) so that the updates are only applied if the new invoice is successfully paid. ## Billing impacts Not all subscription changes affect billing or generate prorations: - *Billing-related updates* create prorations and can generate invoices. These include changing prices, quantities, billing periods, or adding or removing subscription items. - *Non-billing updates* apply immediately without prorations. These include updating metadata, payment methods, tax settings, or applying discounts. To see billing impacts before making changes, [preview prorations](https://docs.stripe.com/billing/subscriptions/prorations.md#preview-proration). > Configuration updates, like metadata and payment methods, don’t generate invoices with `proration_behavior=always_invoice` because they don’t change the amount owed for the current billing period. For a complete list, see [What doesn’t trigger prorations](https://docs.stripe.com/billing/subscriptions/prorations.md#no-prorations). ## Use cases [Change billing period](https://docs.stripe.com/billing/subscriptions/billing-cycle.md): Adjust the billing date for subscriptions. [Change prices](https://docs.stripe.com/billing/subscriptions/change-price.md): Upgrade and downgrade subscriptions by changing the price. [Cancel active subscriptions](https://docs.stripe.com/billing/subscriptions/cancel.md): Manually cancel your customers’ subscriptions. [Pause payment collection](https://docs.stripe.com/billing/subscriptions/pause-payment.md): Temporarily stop collecting payments from your customers. [Apply discounts](https://docs.stripe.com/billing/subscriptions/coupons.md): Add discounts to subscriptions using coupons and promotion codes. [Use trial periods](https://docs.stripe.com/billing/subscriptions/trials.md): Delay payments on active subscriptions using trial periods. [Set quantities](https://docs.stripe.com/billing/subscriptions/quantities.md): Subscribe a customer to multiple quantities of a product. [Collect taxes](https://docs.stripe.com/billing/taxes.md): Collect and report taxes with Stripe Billing and Stripe Tax. [Set payment methods](https://docs.stripe.com/billing/subscriptions/payment-methods-setting.md): Specify which payment methods to allow for a subscription. [Manage prorations](https://docs.stripe.com/billing/subscriptions/prorations.md): Handle prorations for modified subscriptions. --- # Source: https://docs.stripe.com/changelog.md # Source: https://docs.stripe.com/checkout/elements-with-checkout-sessions-api/changelog.md # Elements with Checkout Sessions API beta changelog Keep track of changes to the Elements with Checkout Sessions API beta integration. > This doc contains changelogs related to beta versions of Elements with Checkout Sessions API. > > If you’re already on the [Clover release](https://docs.stripe.com/changelog/clover.md) of Elements with Checkout Sessions API, this changelog doesn’t apply to you. ## Migrating to Clover ### Clover changes - (Breaking) The [stripe.initCheckout](https://docs.stripe.com/js/custom_checkout/init) method is now synchronous instead of asynchronous. This reduces render latency and enables Elements to show skeleton loaders earlier. See [Updates initCheckout to be synchronous](https://docs.stripe.com/changelog/clover/2025-09-30/update-init-checkout-synchronous.md) for migration details. - (Breaking) Saved payment methods are now automatically enabled in the Payment Element when configured on the Checkout Session, without requiring additional client-side configuration. See [Updates default behavior for saved payment methods](https://docs.stripe.com/changelog/clover/2025-09-30/custom-checkout-saved-payment-method-defaults.md) for details. - (Breaking) Postal codes are no longer automatically collected for card payments in Canada, UK, and Puerto Rico. See [Removes postal code for card payments](https://docs.stripe.com/changelog/clover/2025-09-30/postal_code_in_card_form_for_non_us_countries.md) if you rely on this data. - (Breaking) For React integrations: - Import paths have changed from `@stripe/react-stripe-js` to `@stripe/react-stripe-js/checkout`. - [useCheckout](https://docs.stripe.com/js/react_stripe_js/checkout/use_checkout) now returns a disjoint union describing the asynchronous state (`{type: 'loading'}`, `{type: 'success', checkout: ...}`, or `{type: 'error', error: ...}`) instead of throwing an error. - [CheckoutProvider](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider) now renders children unconditionally instead of rendering `null` when [initCheckout](https://docs.stripe.com/js/custom_checkout/init) hasn’t succeeded. ### Clover upgrade Before migrating to Clover, first [update your integration](https://docs.stripe.com/checkout/elements-with-checkout-sessions-api/changelog.md#migrating-to-basil) to Basil. - If you’re using any Stripe NPM packages, you must upgrade `@stripe/stripe-js` to at least `8.0.0` and `@stripe/react-stripe-js` to at least `5.0.0`. - If you’re loading Stripe.js through the script tag, update the tag to reference `clover` using the [versioned Stripe.js nomenclature](https://docs.stripe.com/sdks/stripejs-versioning.md) as follows: ```html Checkout ``` - Update the API version to be at least `2025-09-30.clover` on your back-end integration. #### HTML + JS Update your integration as follows: 1. Remove any `await` or `.then()` calls associated with `initCheckout`. 1. Replace your `fetchClientSecret` function with a client secret string or Promise that resolves to a client secret string. 1. Call the new asynchronous function `checkout.loadActions()` to access actions such as `getSession()`, which replaces `session()`, or `confirm()`. You only need to call `loadActions()` once. 1. If you previously wrapped `initCheckout` in a `try...catch` block, examine the resolved `type` value of `loadActions()` instead to check for errors. ```javascript const clientSecret = fetch("/create-checkout-session", { method: "POST", headers: { "Content-Type": "application/json" }, }) .then((r) => r.json()) .then((r) => r.clientSecret); const checkout = stripe.initCheckout({ clientSecret }); const paymentElement = checkout.createPaymentElement(); paymentElement.mount("#payment-element"); const loadActionsResult = await checkout.loadActions(); if (loadActionsResult.type === 'success') { const session = loadActionsResult.actions.getSession(); } ``` #### React Upgrade your `@stripe/react-stripe-js` dependency to at least version `5.0.0`. If you upgrade from a version earlier than `4.0.0`, make sure you read the [v4.0.0 release notes](https://github.com/stripe/react-stripe-js/releases/tag/v4.0.0) for additional migration steps. #### Import changes Update your imports to use the new checkout-specific entrypoint: ```jsx import {useCheckout, PaymentElement} from '@stripe/react-stripe-js/checkout'; ``` #### CheckoutProvider and useCheckout changes Replace `fetchClientSecret` with `clientSecret`. You can now render Elements without first checking if `useCheckout` returned `type: 'success'`, which reduces latency and enables Elements to show skeleton loaders earlier. ```jsx const App = () => { const promise = useMemo(() => { return fetch('/create-checkout-session', { method: 'POST', headers: { "Content-Type": "application/json" }, }) .then((res) => res.json()) .then((data) => data.clientSecret); }, []); return ( ); } const CheckoutPage = () => { const {type, ...rest} = useCheckout(); return (
); } ``` For more details, see the [Updates initCheckout to be synchronous](https://docs.stripe.com/changelog/clover/2025-09-30/update-init-checkout-synchronous.md) changelog entry. ## Migrating to Basil ### Basil changes - (Breaking) Asynchronous methods, such as [confirm](https://docs.stripe.com/js/custom_checkout/confirm) or [applyPromotionCode](https://docs.stripe.com/js/custom_checkout/apply_promotion_code), resolve with a different schema: - If successful, the updated session state is populated under the `session` key. Previously, this was under the `success` key. - (Breaking) An error is now thrown when passing in [returnUrl](https://docs.stripe.com/js/custom_checkout/confirm#custom_checkout_session_confirm-options-returnUrl) on [confirm](https://docs.stripe.com/js/custom_checkout/confirm) when [return_url](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-return_url) has been already set on the Checkout Session. - (Breaking) The return URL redirected to after a successful confirmation previously had inconsistent query parameters. Extra parameters are now removed and the URL only contains what’s provided in [returnUrl](https://docs.stripe.com/js/custom_checkout/confirm#custom_checkout_session_confirm-options-returnUrl) on [confirm](https://docs.stripe.com/js/custom_checkout/confirm) or [return_url](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-return_url) on the Checkout Session. - (Breaking) Improves latency on Checkout Session API for subscription-mode Sessions and fixes a bug that prevented your customers from updating a Session after the first payment attempt - The change creates the subscription after the user has completed the payment, so `checkout_session.invoice` and `checkout_session.subscription` are null until the Checkout Session completes. - If you currently rely on the deprecated `payment_intent.invoice` field, we recommend using the `checkout_session.completed` webhook, which ensures an invoice is present, and `checkout_session.invoice` or [Invoice Payment list](https://docs.stripe.com/api/invoice-payment/list.md) to find the associated invoice. - To learn more, read the [2025-03-31.basil API changelog](https://docs.stripe.com/changelog/basil/2025-03-31/checkout-legacy-subscription-upgrade.md). - Added [percentOff](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-discountAmounts-percentOff) to [discountAmounts](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-discountAmounts) as an option to display discounts. ### Basil upgrade Before migrating to Basil, first [update your integration](https://docs.stripe.com/checkout/elements-with-checkout-sessions-api/changelog.md#beta-changelog) to `custom_checkout_beta_6`. - If you’re using any Stripe NPM packages, you must first upgrade `@stripe/stripe-js` to at least `7.0.0` and `@stripe/react-stripe-js` to at least `3.6.0`. - If you’re loading Stripe.js through the script tag, and you’re still using `v3` or `acacia`, update the tag to reference `basil` using the [versioned Stripe.js nomenclature](https://docs.stripe.com/sdks/stripejs-versioning.md) as follows: ```html Checkout ``` - Remove the Stripe.js beta header when initializing Stripe.js. #### HTML + JS ```js const stripe = Stripe( '<>', { } ); ``` #### React ```javascript import {loadStripe} from '@stripe/stripe-js'; const stripe = loadStripe("<>", { }); ``` - Remove the API version beta header and specify the API version to be at least `2025-03-31.basil` on your back-end integration. ### Before #### TypeScript ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys import Stripe from 'stripe'; const stripe = new Stripe('<>', { apiVersion: '2026-01-28.clover; custom_checkout_beta=v1' as any, }); ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>', { apiVersion: '2026-01-28.clover; custom_checkout_beta=v1;', }); ``` #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' Stripe.api_version = '2026-01-28.clover; custom_checkout_beta=v1;' ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient([ "api_key" => "<>", "stripe_version" => "2026-01-28.clover; custom_checkout_beta=v1;" ]); ``` #### Python ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' stripe.api_version = '2026-01-28.clover; custom_checkout_beta=v1;' ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" stripe.APIVersion += "2026-01-28.clover; custom_checkout_beta=v1;" ``` #### .NET ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" stripe.APIVersion += "2026-01-28.clover; custom_checkout_beta=v1;" ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; Stripe.apiVersion = "2026-01-28.clover; custom_checkout_beta=v1;" ``` ### After #### TypeScript ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys import Stripe from 'stripe'; const stripe = new Stripe('<>', { apiVersion: '2025-03-31.basil' as any, }); ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>', { apiVersion: '2025-03-31.basil', }); ``` #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' Stripe.api_version = '2025-03-31.basil' ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient([ "api_key" => "<>", "stripe_version" => "2025-03-31.basil" ]); ``` #### Python ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' stripe.api_version = '2025-03-31.basil' ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" stripe.APIVersion += "2025-03-31.basil" ``` #### .NET ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" stripe.APIVersion += "2025-03-31.basil" ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; Stripe.apiVersion = "2025-03-31.basil" ``` ## Beta changelog Elements with Checkout Sessions API beta uses two kinds of beta versions: - A Stripe.js beta header (for example, `custom_checkout_beta_6`), which is set on your front-end integration. - An API version beta header (for example, `custom_checkout_beta=v1`), which is set on your back-end integration. ### Front-end beta versions Specify the front-end beta version when [initializing Stripe.js](https://docs.stripe.com/payments/quickstart-checkout-sessions.md). #### custom_checkout_beta_6 If you’re using any Stripe NPM packages, you must first upgrade `@stripe/stripe-js` to at least `6.1.0` and `@stripe/react-stripe-js` to at least `3.5.0`. - (Breaking) The sign of [total.appliedBalance](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-total-appliedBalance) has been flipped. A positive number now increases the amount to be paid, and a negative number decreases the amount to be paid. - (Breaking) Replaced `clientSecret` with [fetchClientSecret](https://docs.stripe.com/js/custom_checkout/init#custom_checkout_init-options-clientSecret). Update your integration to pass an async function resolving to the client secret instead of passing a static value. - (Breaking) Elements methods has been renamed. - If you’re using React Stripe.js, you don’t need to do anything except upgrade `@stripe/react-stripe-js`. - If you’re using HTML/JS: - Use `createPaymentElement()` instead of `createElement('payment')`. - Use `createBillingAddressElement()` instead of `createElement('address', {mode: 'billing'})`. - Use `createShippingAddressElement()` instead of `createElement('address', {mode: 'shipping'})`. - Use `createExpressCheckoutElement()` instead of `createElement('expressCheckout')`. - Use `getPaymentElement()` instead of `getElement('payment')`. - Use `getBillingAddressElement()` instead of `getElement('address', {mode: 'billing'})`. - Use `getShippingAddressElement()` instead of `getElement('address', {mode: 'shipping'})`. - Use `getExpressCheckoutElement()` instead of `getElement('expressCheckout')`. - (Breaking) Updated fields related to confirmation to more accurately reflect session state. - [canConfirm](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-canConfirm) now responds to any mounted Billing Address Element or Shipping Address Element. - [canConfirm](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-canConfirm) now becomes `false` if there is an in-flight confirmation. - Removed `confirmationRequirements`. - (Breaking) [updateEmail](https://docs.stripe.com/js/custom_checkout/update_email) now throws an error if [customer_email](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_email) was provided when creating the Checkout Session. If you intend to prefill an email that your customer can update, call `updateEmail` as soon as the page loads instead of passing `customer_email`. - (Breaking) [returnUrl](https://docs.stripe.com/js/custom_checkout/confirm#custom_checkout_session_confirm-options-returnUrl) must be an absolute URL (for example, starts with `https://` rather than a relative URL, like `/success`). - (Breaking) Updated pricing fields to a nested object for ease of rendering. - Replaced numeric values with an object containing `amount` (a formatted currency string, such as `$10.00`) and `minorUnitsAmount`, an integer representing the value in the currency’s smallest unit. If you’re already reading the amount, read instead from `minorUnitsAmount`. - For example, replace `total.total` with [`total.total.minorUnitsAmount`](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-total-total-minorUnitsAmount). - You must either read `total.total.amount` or each of `total.total.minorUnitsAmount` and `currency` and `minorUnitsAmountDivisor` from the `checkout` object and display in your UI, otherwise an error will be thrown. This helps keep your checkout page in sync as the CheckoutSession updates, including adding future Stripe features, with minimal UI code changes. - Customer tax IDs can now be collected. Learn how to [collect tax IDs](https://docs.stripe.com/tax/checkout/tax-ids.md?payment-ui=embedded-components). - A test mode-only assistant is now available at the bottom of your checkout page, offering guidance for your integration and shortcuts for common test scenarios. #### custom_checkout_beta_5 - (Breaking) The `initCustomCheckout` function has been renamed to [initCheckout](https://docs.stripe.com/js/custom_checkout/init) - Within React Stripe.js, `CustomCheckoutProvider` has been renamed to `CheckoutProvider` and `useCustomCheckout` has been renamed to `useCheckout`. - (Breaking) To confirm the Express Checkout Element, call [confirm](https://docs.stripe.com/js/custom_checkout/confirm), passing the [confirm event](https://docs.stripe.com/js/elements_object/express_checkout_element_confirm_event) as `expressCheckoutConfirmEvent`. - Previously, Express Checkout Element was confirmed by calling `event.confirm()`. - (Breaking) When [confirm](https://docs.stripe.com/js/custom_checkout/confirm) is called, Payment Element and Address Element will validate form inputs and render any errors. - (Breaking) Error messages have been standardized and improved. - Errors returned/resolved by a function represent known scenarios like invalid payment details or insufficient funds. These are predictable issues that can be communicated to your customer by displaying the `message` on the checkout page. - Errors thrown/rejected by a function represent errors in the integration itself, such as invalid parameters or configuration. These errors are not meant to be displayed to your customers. - (Breaking) Asynchronous methods, such as [confirm](https://docs.stripe.com/js/custom_checkout/confirm) or [applyPromotionCode](https://docs.stripe.com/js/custom_checkout/apply_promotion_code), resolve with a different schema: - A `type="success"|"error"` discriminator field has been added. - If successful, the updated session state is populated under the `success` key. Previously, this was under the `session` key. - Otherwise, the error continues to be populated under the `error` key. - Added the `email`, `phoneNumber`, `billingAddress`, and `shippingAddress` options to [confirm](https://docs.stripe.com/js/custom_checkout/confirm). - (Breaking) Address Element no longer automatically updates the [billingAddress](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-billingAddress) or [shippingAddress](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-shippingAddress) fields on the Session. - So long as Address Element is mounted, form values will automatically be used when calling [confirm](https://docs.stripe.com/js/custom_checkout/confirm). - Listen to the [change event](https://docs.stripe.com/js/element/events/on_change?type=addressElement) to use the Address Element value before confirmation. #### custom_checkout_beta_4 - Added [images](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-lineItems-images) to the [Session object](https://docs.stripe.com/js/custom_checkout/session_object). - Added [fields](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options-fields) as an option when creating the Payment Element. - Added [paymentMethods](https://docs.stripe.com/js/custom_checkout/create_express_checkout_element#custom_checkout_create_express_checkout_element-options-paymentMethods) as an option when creating the Express Checkout Element. - (Breaking) Passing invalid options to [createElement](https://docs.stripe.com/js/custom_checkout/create_payment_element) now throws an error. Previously, unrecognized options would be silently ignored. - (Breaking) [updateEmail](https://docs.stripe.com/js/custom_checkout/update_email) and [updatePhoneNumber](https://docs.stripe.com/js/custom_checkout/update_phone_number) apply changes asynchronously. Calling these methods before the customer finishes entering complete values might cause poor performance. - Instead of calling `updateEmail` or `updatePhoneNumber` on each input’s change event, wait until your customer finishes the input, such as on input blur or when they submit the form for payment. - `updateEmail` now validates that the input is a properly formed email address and returns an error if an invalid input is used. - `updatePhoneNumber` still performs no validation on the input string. #### custom_checkout_beta_3 - The following fields have been added to the [Session object](https://docs.stripe.com/js/custom_checkout/session_object): - [id](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-id) - [livemode](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-livemode) - [businessName](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-businessName) - Saved cards can now be reused. Learn how to [save and reuse](https://docs.stripe.com/payments/checkout/save-during-payment.md) payment methods. - (Breaking) The default [layout](https://docs.stripe.com/js/elements_object/create_payment_element#payment_element_create-options-layout) of the Payment Element has been changed to `accordion`. - To continue using the previous default layout, you must explicitly specify `layout='tabs'`. - (Breaking) The default behavior of [confirm](https://docs.stripe.com/js/custom_checkout/confirm) has been changed to always redirect to your `return_url` after a successful confirmation. - Previously, `confirm` redirected only if the customer chooses a redirect-based payment method. To continue using the old behavior, you must pass [redirect=‘if_required’](https://docs.stripe.com/js/custom_checkout/confirm#custom_checkout_session_confirm-options-redirect) to `confirm`. #### custom_checkout_beta_2 - (Breaking) The `lineItem.recurring.interval_count` field has been removed and replaced with [lineItem.recurring.intervalCount](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-lineItems-recurring-intervalCount). - (Breaking) The `lineItem.amount` field has been removed and replaced with the following: - [lineItem.amountSubtotal](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-lineItems-amountSubtotal) - [lineItem.amountDiscount](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-lineItems-amountDiscount) - [lineItem.amountTaxInclusive](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-lineItems-amountTaxInclusive) - [lineItem.amountTaxExclusive](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-lineItems-amountTaxExclusive) #### custom_checkout_beta_1 *This is the initial front-end beta version.* ### Back-end versions Specify the back-end beta version when [setting up your server library](https://docs.stripe.com/payments/quickstart-checkout-sessions.md#init-stripe). *There are no changes to the back-end beta version.* --- # Source: https://docs.stripe.com/payments/no-code/charge-shipping.md # Source: https://docs.stripe.com/payments/mobile/charge-shipping.md # Source: https://docs.stripe.com/payments/during-payment/charge-shipping.md # Charge for shipping Create different shipping rates for your customers. Shipping rates let you display various shipping options—like standard, express, and overnight—with more accurate delivery estimates. Charge your customer for shipping using different Stripe products. Before you create a shipping rate, learn how to [collect billing and shipping addresses](https://docs.stripe.com/payments/collect-addresses.md). ## Create a shipping rate [Dashboard] [Server-side] Shipping rates only support fixed amount values for the entire order. You can’t adjust the shipping rate based on the number of items in the order. #### Dashboard To add a [shipping rate](https://dashboard.stripe.com/test/shipping-rates) using the Dashboard: 1. Click **Create shipping rate**. 1. Enter an amount, a description, and an optional delivery estimate. 1. Click **Save**, and copy the shipping rate ID (`shr_123456`). ![](https://b.stripecdn.com/docs-statics-srv/assets/create-shipping-rate-dashboard.ddd79821d5edee523d7da9d22682be59.png) Enter your shipping rate details ### Update a shipping rate You can’t update an amount of a currency that’s already been set on a shipping rate. After you set a currency and amount on a shipping rate, it can only be updated to include new currencies. To update a shipping rate in the Dashboard, you must archive the shipping rate and then create a new one. ### Archive a shipping rate To archive a shipping rate: 1. On the [Shipping rates](https://dashboard.stripe.com/test/shipping-rates) tab, select the applicable shipping rate. 1. Click the overflow menu ⋯, and select **Archive**. To unarchive the shipping rate, click the overflow menu ⋯, and select **Unarchive shipping rate**. #### API > #### Interested in dynamic shipping rate updates? > > Checkout supports letting you dynamically update shipping rates based on the address your customer provides or the value of the order. See [Dynamically customize shipping options](https://docs.stripe.com/payments/checkout/custom-shipping-options.md) about this preview feature. [Create a shipping rate](https://docs.stripe.com/api/shipping_rates.md), which at a minimum, requires the `type` and `display_name` parameters. The following code sample uses both of these parameters along with `fixed_amount` and `delivery_estimate` to create a shipping rate: ```curl curl https://api.stripe.com/v1/shipping_rates \ -u "<>:" \ -d display_name="Ground shipping" \ -d type=fixed_amount \ -d "fixed_amount[amount]"=500 \ -d "fixed_amount[currency]"=usd \ -d "delivery_estimate[minimum][unit]"=business_day \ -d "delivery_estimate[minimum][value]"=5 \ -d "delivery_estimate[maximum][unit]"=business_day \ -d "delivery_estimate[maximum][value]"=7 ``` ```cli stripe shipping_rates create \ --display-name="Ground shipping" \ --type=fixed_amount \ -d "fixed_amount[amount]"=500 \ -d "fixed_amount[currency]"=usd \ -d "delivery_estimate[minimum][unit]"=business_day \ -d "delivery_estimate[minimum][value]"=5 \ -d "delivery_estimate[maximum][unit]"=business_day \ -d "delivery_estimate[maximum][value]"=7 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") shipping_rate = client.v1.shipping_rates.create({ display_name: 'Ground shipping', type: 'fixed_amount', fixed_amount: { amount: 500, currency: 'usd', }, delivery_estimate: { minimum: { unit: 'business_day', value: 5, }, maximum: { unit: 'business_day', value: 7, }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. shipping_rate = client.v1.shipping_rates.create({ "display_name": "Ground shipping", "type": "fixed_amount", "fixed_amount": {"amount": 500, "currency": "usd"}, "delivery_estimate": { "minimum": {"unit": "business_day", "value": 5}, "maximum": {"unit": "business_day", "value": 7}, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $shippingRate = $stripe->shippingRates->create([ 'display_name' => 'Ground shipping', 'type' => 'fixed_amount', 'fixed_amount' => [ 'amount' => 500, 'currency' => 'usd', ], 'delivery_estimate' => [ 'minimum' => [ 'unit' => 'business_day', 'value' => 5, ], 'maximum' => [ 'unit' => 'business_day', 'value' => 7, ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); ShippingRateCreateParams params = ShippingRateCreateParams.builder() .setDisplayName("Ground shipping") .setType(ShippingRateCreateParams.Type.FIXED_AMOUNT) .setFixedAmount( ShippingRateCreateParams.FixedAmount.builder() .setAmount(500L) .setCurrency("usd") .build() ) .setDeliveryEstimate( ShippingRateCreateParams.DeliveryEstimate.builder() .setMinimum( ShippingRateCreateParams.DeliveryEstimate.Minimum.builder() .setUnit(ShippingRateCreateParams.DeliveryEstimate.Minimum.Unit.BUSINESS_DAY) .setValue(5L) .build() ) .setMaximum( ShippingRateCreateParams.DeliveryEstimate.Maximum.builder() .setUnit(ShippingRateCreateParams.DeliveryEstimate.Maximum.Unit.BUSINESS_DAY) .setValue(7L) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. ShippingRate shippingRate = client.v1().shippingRates().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const shippingRate = await stripe.shippingRates.create({ display_name: 'Ground shipping', type: 'fixed_amount', fixed_amount: { amount: 500, currency: 'usd', }, delivery_estimate: { minimum: { unit: 'business_day', value: 5, }, maximum: { unit: 'business_day', value: 7, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.ShippingRateCreateParams{ DisplayName: stripe.String("Ground shipping"), Type: stripe.String("fixed_amount"), FixedAmount: &stripe.ShippingRateCreateFixedAmountParams{ Amount: stripe.Int64(500), Currency: stripe.String(stripe.CurrencyUSD), }, DeliveryEstimate: &stripe.ShippingRateCreateDeliveryEstimateParams{ Minimum: &stripe.ShippingRateCreateDeliveryEstimateMinimumParams{ Unit: stripe.String(stripe.ShippingRateDeliveryEstimateMinimumUnitBusinessDay), Value: stripe.Int64(5), }, Maximum: &stripe.ShippingRateCreateDeliveryEstimateMaximumParams{ Unit: stripe.String(stripe.ShippingRateDeliveryEstimateMaximumUnitBusinessDay), Value: stripe.Int64(7), }, }, } result, err := sc.V1ShippingRates.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new ShippingRateCreateOptions { DisplayName = "Ground shipping", Type = "fixed_amount", FixedAmount = new ShippingRateFixedAmountOptions { Amount = 500, Currency = "usd" }, DeliveryEstimate = new ShippingRateDeliveryEstimateOptions { Minimum = new ShippingRateDeliveryEstimateMinimumOptions { Unit = "business_day", Value = 5, }, Maximum = new ShippingRateDeliveryEstimateMaximumOptions { Unit = "business_day", Value = 7, }, }, }; var client = new StripeClient("<>"); var service = client.V1.ShippingRates; ShippingRate shippingRate = service.Create(options); ``` ### Update a shipping rate To [update a shipping rate](https://docs.stripe.com/api/shipping_rates/update.md), call `Stripe::ShippingRate.update`, and update the parameters as needed. ## Create a Checkout Session [Server-side] To create a Checkout Session that includes your shipping rate, pass in the generated shipping rate ID to the [shipping_options](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-shipping_options) parameter. If you want to create the shipping rate at the same time as a Checkout Session, use the `shipping_rate_data` parameter with `shipping_options`. Only Checkout Sessions in [payment mode](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-mode) support shipping options. The following code sample adds two shipping options to the Checkout Session: - Free shipping, with an estimated delivery of 5-7 business days. - Next day air, at a cost of 15.00 USD, with an estimated delivery of exactly 1 business day. In this example, the first option in the `shipping_options` array is pre-selected for the customer on the checkout page. However, customers can choose either option. #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_address_collection[allowed_countries][1]"=CA \ -d "shipping_options[0][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[0][shipping_rate_data][fixed_amount][amount]"=0 \ -d "shipping_options[0][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[0][shipping_rate_data][display_name]"="Free shipping" \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][value]"=5 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][value]"=7 \ -d "shipping_options[1][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[1][shipping_rate_data][fixed_amount][amount]"=1500 \ -d "shipping_options[1][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[1][shipping_rate_data][display_name]"="Next day air" \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][minimum][value]"=1 \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][maximum][value]"=1 \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" ``` ```cli stripe checkout sessions create \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_address_collection[allowed_countries][1]"=CA \ -d "shipping_options[0][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[0][shipping_rate_data][fixed_amount][amount]"=0 \ -d "shipping_options[0][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[0][shipping_rate_data][display_name]"="Free shipping" \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][value]"=5 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][value]"=7 \ -d "shipping_options[1][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[1][shipping_rate_data][fixed_amount][amount]"=1500 \ -d "shipping_options[1][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[1][shipping_rate_data][display_name]"="Next day air" \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][minimum][value]"=1 \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][maximum][value]"=1 \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --success-url="https://example.com/success" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ shipping_address_collection: {allowed_countries: ['US', 'CA']}, shipping_options: [ { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 0, currency: 'usd', }, display_name: 'Free shipping', delivery_estimate: { minimum: { unit: 'business_day', value: 5, }, maximum: { unit: 'business_day', value: 7, }, }, }, }, { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 1500, currency: 'usd', }, display_name: 'Next day air', delivery_estimate: { minimum: { unit: 'business_day', value: 1, }, maximum: { unit: 'business_day', value: 1, }, }, }, }, ], line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "shipping_address_collection": {"allowed_countries": ["US", "CA"]}, "shipping_options": [ { "shipping_rate_data": { "type": "fixed_amount", "fixed_amount": {"amount": 0, "currency": "usd"}, "display_name": "Free shipping", "delivery_estimate": { "minimum": {"unit": "business_day", "value": 5}, "maximum": {"unit": "business_day", "value": 7}, }, }, }, { "shipping_rate_data": { "type": "fixed_amount", "fixed_amount": {"amount": 1500, "currency": "usd"}, "display_name": "Next day air", "delivery_estimate": { "minimum": {"unit": "business_day", "value": 1}, "maximum": {"unit": "business_day", "value": 1}, }, }, }, ], "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, }, "quantity": 1, }, ], "mode": "payment", "success_url": "https://example.com/success", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'shipping_address_collection' => ['allowed_countries' => ['US', 'CA']], 'shipping_options' => [ [ 'shipping_rate_data' => [ 'type' => 'fixed_amount', 'fixed_amount' => [ 'amount' => 0, 'currency' => 'usd', ], 'display_name' => 'Free shipping', 'delivery_estimate' => [ 'minimum' => [ 'unit' => 'business_day', 'value' => 5, ], 'maximum' => [ 'unit' => 'business_day', 'value' => 7, ], ], ], ], [ 'shipping_rate_data' => [ 'type' => 'fixed_amount', 'fixed_amount' => [ 'amount' => 1500, 'currency' => 'usd', ], 'display_name' => 'Next day air', 'delivery_estimate' => [ 'minimum' => [ 'unit' => 'business_day', 'value' => 1, ], 'maximum' => [ 'unit' => 'business_day', 'value' => 1, ], ], ], ], ], 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, ], 'quantity' => 1, ], ], 'mode' => 'payment', 'success_url' => 'https://example.com/success', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setShippingAddressCollection( SessionCreateParams.ShippingAddressCollection.builder() .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.US ) .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.CA ) .build() ) .addShippingOption( SessionCreateParams.ShippingOption.builder() .setShippingRateData( SessionCreateParams.ShippingOption.ShippingRateData.builder() .setType( SessionCreateParams.ShippingOption.ShippingRateData.Type.FIXED_AMOUNT ) .setFixedAmount( SessionCreateParams.ShippingOption.ShippingRateData.FixedAmount.builder() .setAmount(0L) .setCurrency("usd") .build() ) .setDisplayName("Free shipping") .setDeliveryEstimate( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.builder() .setMinimum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.Unit.BUSINESS_DAY ) .setValue(5L) .build() ) .setMaximum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.Unit.BUSINESS_DAY ) .setValue(7L) .build() ) .build() ) .build() ) .build() ) .addShippingOption( SessionCreateParams.ShippingOption.builder() .setShippingRateData( SessionCreateParams.ShippingOption.ShippingRateData.builder() .setType( SessionCreateParams.ShippingOption.ShippingRateData.Type.FIXED_AMOUNT ) .setFixedAmount( SessionCreateParams.ShippingOption.ShippingRateData.FixedAmount.builder() .setAmount(1500L) .setCurrency("usd") .build() ) .setDisplayName("Next day air") .setDeliveryEstimate( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.builder() .setMinimum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.Unit.BUSINESS_DAY ) .setValue(1L) .build() ) .setMaximum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.Unit.BUSINESS_DAY ) .setValue(1L) .build() ) .build() ) .build() ) .build() ) .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ shipping_address_collection: { allowed_countries: ['US', 'CA'], }, shipping_options: [ { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 0, currency: 'usd', }, display_name: 'Free shipping', delivery_estimate: { minimum: { unit: 'business_day', value: 5, }, maximum: { unit: 'business_day', value: 7, }, }, }, }, { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 1500, currency: 'usd', }, display_name: 'Next day air', delivery_estimate: { minimum: { unit: 'business_day', value: 1, }, maximum: { unit: 'business_day', value: 1, }, }, }, }, ], line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ ShippingAddressCollection: &stripe.CheckoutSessionCreateShippingAddressCollectionParams{ AllowedCountries: []*string{stripe.String("US"), stripe.String("CA")}, }, ShippingOptions: []*stripe.CheckoutSessionCreateShippingOptionParams{ &stripe.CheckoutSessionCreateShippingOptionParams{ ShippingRateData: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataParams{ Type: stripe.String("fixed_amount"), FixedAmount: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataFixedAmountParams{ Amount: stripe.Int64(0), Currency: stripe.String(stripe.CurrencyUSD), }, DisplayName: stripe.String("Free shipping"), DeliveryEstimate: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateParams{ Minimum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMinimumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(5), }, Maximum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMaximumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(7), }, }, }, }, &stripe.CheckoutSessionCreateShippingOptionParams{ ShippingRateData: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataParams{ Type: stripe.String("fixed_amount"), FixedAmount: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataFixedAmountParams{ Amount: stripe.Int64(1500), Currency: stripe.String(stripe.CurrencyUSD), }, DisplayName: stripe.String("Next day air"), DeliveryEstimate: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateParams{ Minimum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMinimumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(1), }, Maximum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMaximumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(1), }, }, }, }, }, LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { ShippingAddressCollection = new Stripe.Checkout.SessionShippingAddressCollectionOptions { AllowedCountries = new List { "US", "CA" }, }, ShippingOptions = new List { new Stripe.Checkout.SessionShippingOptionOptions { ShippingRateData = new Stripe.Checkout.SessionShippingOptionShippingRateDataOptions { Type = "fixed_amount", FixedAmount = new Stripe.Checkout.SessionShippingOptionShippingRateDataFixedAmountOptions { Amount = 0, Currency = "usd", }, DisplayName = "Free shipping", DeliveryEstimate = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateOptions { Minimum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMinimumOptions { Unit = "business_day", Value = 5, }, Maximum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMaximumOptions { Unit = "business_day", Value = 7, }, }, }, }, new Stripe.Checkout.SessionShippingOptionOptions { ShippingRateData = new Stripe.Checkout.SessionShippingOptionShippingRateDataOptions { Type = "fixed_amount", FixedAmount = new Stripe.Checkout.SessionShippingOptionShippingRateDataFixedAmountOptions { Amount = 1500, Currency = "usd", }, DisplayName = "Next day air", DeliveryEstimate = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateOptions { Minimum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMinimumOptions { Unit = "business_day", Value = 1, }, Maximum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMaximumOptions { Unit = "business_day", Value = 1, }, }, }, }, }, LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, }, Quantity = 1, }, }, Mode = "payment", SuccessUrl = "https://example.com/success", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d billing_address_collection=required \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_address_collection[allowed_countries][1]"=CA \ -d "shipping_options[0][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[0][shipping_rate_data][fixed_amount][amount]"=0 \ -d "shipping_options[0][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[0][shipping_rate_data][display_name]"="Free shipping" \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][value]"=5 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][value]"=7 \ -d "shipping_options[1][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[1][shipping_rate_data][fixed_amount][amount]"=1500 \ -d "shipping_options[1][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[1][shipping_rate_data][display_name]"="Next day air" \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][minimum][value]"=1 \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][maximum][value]"=1 \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" ``` ```cli stripe checkout sessions create \ --billing-address-collection=required \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_address_collection[allowed_countries][1]"=CA \ -d "shipping_options[0][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[0][shipping_rate_data][fixed_amount][amount]"=0 \ -d "shipping_options[0][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[0][shipping_rate_data][display_name]"="Free shipping" \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][value]"=5 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][value]"=7 \ -d "shipping_options[1][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[1][shipping_rate_data][fixed_amount][amount]"=1500 \ -d "shipping_options[1][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[1][shipping_rate_data][display_name]"="Next day air" \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][minimum][value]"=1 \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[1][shipping_rate_data][delivery_estimate][maximum][value]"=1 \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ billing_address_collection: 'required', shipping_address_collection: {allowed_countries: ['US', 'CA']}, shipping_options: [ { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 0, currency: 'usd', }, display_name: 'Free shipping', delivery_estimate: { minimum: { unit: 'business_day', value: 5, }, maximum: { unit: 'business_day', value: 7, }, }, }, }, { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 1500, currency: 'usd', }, display_name: 'Next day air', delivery_estimate: { minimum: { unit: 'business_day', value: 1, }, maximum: { unit: 'business_day', value: 1, }, }, }, }, ], line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "billing_address_collection": "required", "shipping_address_collection": {"allowed_countries": ["US", "CA"]}, "shipping_options": [ { "shipping_rate_data": { "type": "fixed_amount", "fixed_amount": {"amount": 0, "currency": "usd"}, "display_name": "Free shipping", "delivery_estimate": { "minimum": {"unit": "business_day", "value": 5}, "maximum": {"unit": "business_day", "value": 7}, }, }, }, { "shipping_rate_data": { "type": "fixed_amount", "fixed_amount": {"amount": 1500, "currency": "usd"}, "display_name": "Next day air", "delivery_estimate": { "minimum": {"unit": "business_day", "value": 1}, "maximum": {"unit": "business_day", "value": 1}, }, }, }, ], "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, }, "quantity": 1, }, ], "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'billing_address_collection' => 'required', 'shipping_address_collection' => ['allowed_countries' => ['US', 'CA']], 'shipping_options' => [ [ 'shipping_rate_data' => [ 'type' => 'fixed_amount', 'fixed_amount' => [ 'amount' => 0, 'currency' => 'usd', ], 'display_name' => 'Free shipping', 'delivery_estimate' => [ 'minimum' => [ 'unit' => 'business_day', 'value' => 5, ], 'maximum' => [ 'unit' => 'business_day', 'value' => 7, ], ], ], ], [ 'shipping_rate_data' => [ 'type' => 'fixed_amount', 'fixed_amount' => [ 'amount' => 1500, 'currency' => 'usd', ], 'display_name' => 'Next day air', 'delivery_estimate' => [ 'minimum' => [ 'unit' => 'business_day', 'value' => 1, ], 'maximum' => [ 'unit' => 'business_day', 'value' => 1, ], ], ], ], ], 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, ], 'quantity' => 1, ], ], 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setBillingAddressCollection(SessionCreateParams.BillingAddressCollection.REQUIRED) .setShippingAddressCollection( SessionCreateParams.ShippingAddressCollection.builder() .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.US ) .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.CA ) .build() ) .addShippingOption( SessionCreateParams.ShippingOption.builder() .setShippingRateData( SessionCreateParams.ShippingOption.ShippingRateData.builder() .setType( SessionCreateParams.ShippingOption.ShippingRateData.Type.FIXED_AMOUNT ) .setFixedAmount( SessionCreateParams.ShippingOption.ShippingRateData.FixedAmount.builder() .setAmount(0L) .setCurrency("usd") .build() ) .setDisplayName("Free shipping") .setDeliveryEstimate( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.builder() .setMinimum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.Unit.BUSINESS_DAY ) .setValue(5L) .build() ) .setMaximum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.Unit.BUSINESS_DAY ) .setValue(7L) .build() ) .build() ) .build() ) .build() ) .addShippingOption( SessionCreateParams.ShippingOption.builder() .setShippingRateData( SessionCreateParams.ShippingOption.ShippingRateData.builder() .setType( SessionCreateParams.ShippingOption.ShippingRateData.Type.FIXED_AMOUNT ) .setFixedAmount( SessionCreateParams.ShippingOption.ShippingRateData.FixedAmount.builder() .setAmount(1500L) .setCurrency("usd") .build() ) .setDisplayName("Next day air") .setDeliveryEstimate( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.builder() .setMinimum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.Unit.BUSINESS_DAY ) .setValue(1L) .build() ) .setMaximum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.Unit.BUSINESS_DAY ) .setValue(1L) .build() ) .build() ) .build() ) .build() ) .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ billing_address_collection: 'required', shipping_address_collection: { allowed_countries: ['US', 'CA'], }, shipping_options: [ { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 0, currency: 'usd', }, display_name: 'Free shipping', delivery_estimate: { minimum: { unit: 'business_day', value: 5, }, maximum: { unit: 'business_day', value: 7, }, }, }, }, { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 1500, currency: 'usd', }, display_name: 'Next day air', delivery_estimate: { minimum: { unit: 'business_day', value: 1, }, maximum: { unit: 'business_day', value: 1, }, }, }, }, ], line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ BillingAddressCollection: stripe.String(stripe.CheckoutSessionBillingAddressCollectionRequired), ShippingAddressCollection: &stripe.CheckoutSessionCreateShippingAddressCollectionParams{ AllowedCountries: []*string{stripe.String("US"), stripe.String("CA")}, }, ShippingOptions: []*stripe.CheckoutSessionCreateShippingOptionParams{ &stripe.CheckoutSessionCreateShippingOptionParams{ ShippingRateData: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataParams{ Type: stripe.String("fixed_amount"), FixedAmount: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataFixedAmountParams{ Amount: stripe.Int64(0), Currency: stripe.String(stripe.CurrencyUSD), }, DisplayName: stripe.String("Free shipping"), DeliveryEstimate: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateParams{ Minimum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMinimumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(5), }, Maximum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMaximumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(7), }, }, }, }, &stripe.CheckoutSessionCreateShippingOptionParams{ ShippingRateData: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataParams{ Type: stripe.String("fixed_amount"), FixedAmount: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataFixedAmountParams{ Amount: stripe.Int64(1500), Currency: stripe.String(stripe.CurrencyUSD), }, DisplayName: stripe.String("Next day air"), DeliveryEstimate: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateParams{ Minimum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMinimumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(1), }, Maximum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMaximumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(1), }, }, }, }, }, LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { BillingAddressCollection = "required", ShippingAddressCollection = new Stripe.Checkout.SessionShippingAddressCollectionOptions { AllowedCountries = new List { "US", "CA" }, }, ShippingOptions = new List { new Stripe.Checkout.SessionShippingOptionOptions { ShippingRateData = new Stripe.Checkout.SessionShippingOptionShippingRateDataOptions { Type = "fixed_amount", FixedAmount = new Stripe.Checkout.SessionShippingOptionShippingRateDataFixedAmountOptions { Amount = 0, Currency = "usd", }, DisplayName = "Free shipping", DeliveryEstimate = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateOptions { Minimum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMinimumOptions { Unit = "business_day", Value = 5, }, Maximum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMaximumOptions { Unit = "business_day", Value = 7, }, }, }, }, new Stripe.Checkout.SessionShippingOptionOptions { ShippingRateData = new Stripe.Checkout.SessionShippingOptionShippingRateDataOptions { Type = "fixed_amount", FixedAmount = new Stripe.Checkout.SessionShippingOptionShippingRateDataFixedAmountOptions { Amount = 1500, Currency = "usd", }, DisplayName = "Next day air", DeliveryEstimate = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateOptions { Minimum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMinimumOptions { Unit = "business_day", Value = 1, }, Maximum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMaximumOptions { Unit = "business_day", Value = 1, }, }, }, }, }, LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, }, Quantity = 1, }, }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` If successful, the shipping selector appears in your checkout flow: ![The shipping selector in the checkout flow](https://b.stripecdn.com/docs-statics-srv/assets/example-checkout-session.5807984bdc0a25ddb53aab00768dd079.jpg) The shipping selector in the checkout flow ## Optional: Handle completed transactions After the payment succeeds, you can retrieve the shipping amount in the [amount_total](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-amount_total) attribute of the [shipping_cost](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-shipping_cost). You can also retrieve the selected shipping rate using the `shipping_rate` attribute in `shipping_cost`. To access the `shipping_cost` property, you must [create an event handler](https://docs.stripe.com/checkout/fulfillment.md#create-payment-event-handler) to handle completed Checkout Sessions. You can test a handler by [installing the Stripe CLI](https://docs.stripe.com/stripe-cli.md) and using `stripe listen --forward-to localhost:4242/webhook` to [forward events to your local server](https://docs.stripe.com/webhooks.md#test-webhook). In the following code sample, the handler allows for the user to access the `shipping_property`: #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = "<>" require 'sinatra' # You can find your endpoint's secret in your webhook settings endpoint_secret = 'whsec_...' post '/webhook' do event = nil # Verify webhook signature and extract the event # See https://stripe.com/docs/webhooks#verify-events for more information. begin sig_header = request.env['HTTP_STRIPE_SIGNATURE'] payload = request.body.read event = Stripe::Webhook.construct_event(payload, sig_header, endpoint_secret) rescue JSON::ParserError => e # Invalid payload return status 400 rescue Stripe::SignatureVerificationError => e # Invalid signature return status 400 end if event['type'] == 'checkout.session.completed' checkout_session = event['data']['object'] fulfill_order(checkout_session) end status 200 end def fulfill_order(checkout_session)selected_shipping_rate = Stripe::ShippingRate.retrieve(checkout_session.shipping_cost.shipping_rate) shipping_total = checkout_session.shipping_cost.amount_total # TODO: Remove error and implement... raise NotImplementedError.new(<<~MSG) Given the Checkout Session "#{checkout_session.id}" load your internal order from the database then implement your own fulfillment logic. MSG end ``` #### Python ```python import stripe # Using Django from django.http import HttpResponse # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' # You can find your endpoint's secret in your webhook settings endpoint_secret = 'whsec_...' @csrf_exempt def my_webhook_view(request): payload = request.body sig_header = request.META['HTTP_STRIPE_SIGNATURE'] event = None try: event = stripe.Webhook.construct_event( payload, sig_header, endpoint_secret ) except ValueError as e: # Invalid payload return HttpResponse(status=400) except stripe.error.SignatureVerificationError as e: # Invalid signature return HttpResponse(status=400) # Handle the checkout.session.completed event if event['type'] == 'checkout.session.completed': session = event['data']['object'] # Fulfill the purchase... fulfill_order(session) # Passed signature verification return HttpResponse(status=200) def fulfill_order(session):selected_shipping_rate = stripe.ShippingRate.retrieve(checkout_session.shipping_cost.shipping_rate) shipping_total = session.shipping_cost.amount_total # TODO: Remove error and implement... raise NotImplementedError("Given the Checkout Session \"" + session['id'] + "\", load your internal order from the database then implement your own fulfillment logic.") ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('<>'); $stripe = new \Stripe\StripeClient('{$ key type="secret" %}'); // You can find your endpoint's secret in your webhook settings $endpoint_secret = 'whsec_...'; $payload = @file_get_contents('php://input'); $sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE']; $event = null; try { $event = \Stripe\Webhook::constructEvent( $payload, $sig_header, $endpoint_secret ); } catch(\UnexpectedValueException $e) { // Invalid payload http_response_code(400); exit(); } catch(\Stripe\Exception\SignatureVerificationException $e) { // Invalid signature http_response_code(400); exit(); } function fulfill_order($session) {$selected_shipping_rate = $stripe->shippingRates->retrieve( $session->shipping_cost->shipping_rate, [] ); $shipping_total = $session->shipping_cost->amount_total; // TODO: Remove error and implement... throw new Exception("Given the Checkout Session $session->id, load your internal order from the database then implement your own fulfillment logic.") } // Handle the checkout.session.completed event if ($event->type == 'checkout.session.completed') { $session = $event->data->object; // Fulfill the purchase... fulfill_order($session); } http_response_code(200); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; // You can find your endpoint's secret in your webhook settings String endpointSecret = "whsec_..."; public void fulfillOrder(Session session) {Long shippingTotal = checkoutSession .getRawJsonObject() .getAsJsonObject("shipping_cost") .getAsJsonPrimitive("amount_total") .getAsLong(); String error = String.format("Given the Checkout Session \"%s\" load your internal order from the database then implement your own fulfillment logic.", session.getId()); throw new UnsupportedOperationException(error); } // Using the Spark framework public Object handle(Request request, Response response) { String payload = request.body(); String sigHeader = request.headers("Stripe-Signature"); Event event = null; try { event = Webhook.constructEvent(payload, sigHeader, endpointSecret); } catch (JsonSyntaxException e) { // Invalid payload response.status(400); return ""; } catch (SignatureVerificationException e) { // Invalid signature response.status(400); return ""; } // Handle the checkout.session.completed event if ("checkout.session.completed".equals(event.getType())) { Session session = (Session) event.getDataObjectDeserializer().getObject(); Long shippingTotal = session.getShippingCost().getAmountTotal(); ShippingRate selectedShippingRate = session.getShippingCost().getShippingRateObject(); // Fulfill the purchase... fulfillOrder(session); } response.status(200); return ""; } ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); // Find your endpoint's secret in your Dashboard's webhook settings const endpointSecret = 'whsec_...'; // Using Express const app = require('express')(); // Use body-parser to retrieve the raw body as a buffer const bodyParser = require('body-parser'); const fulfillOrder = (session) => { const selectedShippingRate = await stripe.shippingRates.retrieve(session.shipping_cost.shipping_rate); const shippingTotal = session.shipping_cost.amount_total; // TODO: Remove error and implement... throw new Error(` Given the Checkout Session ${session.id}, load your internal order from the database then implement your own fulfillment logic.` ); } app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => { const payload = request.body; const sig = request.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(payload, sig, endpointSecret); } catch (err) { return response.status(400).send(`Webhook Error: ${err.message}`); } // Handle the checkout.session.completed event if (event.type === 'checkout.session.completed') { const session = event.data.object; // Fulfill the purchase... fulfillOrder(session); } response.status(200).end(); }); app.listen(4242, () => console.log('Running on port 4242')); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" func FulfillOrder(session stripe.CheckoutSession) {var rawData map[string]interface{} _ = json.Unmarshal(session.LastResponse.RawJSON, &rawData) shippingCost, ok := rawData["shipping_cost"].(map[string]interface{}) if ok { shippingTotal := shippingCost["amount_total"].(float64) // TODO: Remove error and implement... return fmt.Errorf("given the Checkout Session %q, load your internal order from the database then implement your own fulfillment logic.", session.Id) } } http.HandleFunc("/webhook", func(w http.ResponseWriter, req *http.Request) { const MaxBodyBytes = int64(65536) req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes) body, err := ioutil.ReadAll(req.Body) if err != nil { fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err) w.WriteHeader(http.StatusServiceUnavailable) return } // Pass the request body and Stripe-Signature header to ConstructEvent, along with the webhook signing key // You can find your endpoint's secret in your webhook settings endpointSecret := "whsec_..."; event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), endpointSecret) if err != nil { fmt.Fprintf(os.Stderr, "Error verifying webhook signature: %v\n", err) w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature return } // Handle the checkout.session.completed event if event.Type == "checkout.session.completed" { var session stripe.CheckoutSession err := json.Unmarshal(event.Data.Raw, &session) if err != nil { fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err) w.WriteHeader(http.StatusBadRequest) return } // Fulfill the purchase... FulfillOrder(session) } w.WriteHeader(http.StatusOK) }) ``` #### .NET ```dotnet using System; using System.IO; using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using Stripe; using Stripe.Checkout; // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; namespace workspace.Controllers { [Route("api/[controller]")] public class StripeWebHook : Controller { // You can find your endpoint's secret in your webhook settings const string secret = "whsec_..."; [HttpPost] public async Task Index() { var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync(); try { var stripeEvent = EventUtility.ConstructEvent( json, Request.Headers["Stripe-Signature"], secret ); // Handle the checkout.session.completed event // If on SDK version < 46, use class Events instead of EventTypes if (stripeEvent.Type == EventTypes.CheckoutSessionCompleted) { var session = stripeEvent.Data.Object as Checkout.Session; // Fulfill the purchase... this.FulfillOrder(session); } return Ok(); } catch (StripeException e) { return BadRequest(); } } private void FulfillOrder(Checkout.Session session) {var shippingAmount = session.ShippingCost.AmountTotal; // TODO: Remove error and implement... throw new NotImplementedException($"Given the Checkout Session \"{session.Id}\" load your internal order from the database then implement your own fulfillment logic."); } } } ``` ## Optional: Define a delivery estimate You can configure shipping rates using a number of delivery estimate combinations. The following table contains some examples of plain English delivery estimates, and their corresponding `delivery_estimate.minimum` and `delivery_estimate.maximum` values: | Delivery Estimate | Minimum | Maximum | | -------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | 1 day | ```es6 { unit: 'day', value: 1, } ``` | ```es6 { unit: 'day', value: 1, } ``` | | 1 business day | ```es6 { unit: 'business_day', value: 1, } ``` | ```es6 { unit: 'business_day', value: 1, } ``` | | At least 2 business days | ```es6 { unit: 'business_day', value: 2, } ``` | ```es6 null ``` | | 3 to 7 days | ```es6 { unit: 'day', value: 3, } ``` | ```es6 { unit: 'day', value: 7, } ``` | | 4 to 8 hours | ```es6 { unit: 'hour', value: 4, } ``` | ```es6 { unit: 'hour', value: 8, } ``` | | 4 hours to 2 business days | ```es6 { unit: 'hour', value: 4, } ``` | ```es6 { unit: 'business_day', value: 2, } ``` | ## Optional: Charge tax for shipping You can use [Stripe Tax](https://docs.stripe.com/tax/checkout.md) to automatically calculate tax on shipping fees by setting a `tax_code` and `tax_behavior` on your shipping rate. Stripe Tax automatically determines whether shipping is taxable ([as taxability varies by state and country](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#shipping-tax-code)) and applies the correct tax rate if so. When creating a shipping rate with `shipping_rate_data` or through [Create a Shipping Rate](https://docs.stripe.com/api/shipping_rates/create.md), you can add a `tax_behavior` and `tax_code` parameter to the shipping rate. We recommend setting the `tax_code` to `Shipping` (`txcd_92010001`) to make sure that you always charge the correct tax. You can also set the shipping rate `tax_code` to `Nontaxable` (`txcd_00000000`) if you don’t want to charge tax. For this example, we set the `tax_behavior` to `exclusive`, which is common in the US. Learn more about [tax behavior](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-behavior). #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d billing_address_collection=required \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_address_collection[allowed_countries][1]"=CA \ -d "shipping_options[0][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[0][shipping_rate_data][fixed_amount][amount]"=0 \ -d "shipping_options[0][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[0][shipping_rate_data][display_name]"="Free shipping" \ -d "shipping_options[0][shipping_rate_data][tax_behavior]"=exclusive \ -d "shipping_options[0][shipping_rate_data][tax_code]"=txcd_92010001 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][value]"=5 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][value]"=7 \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][tax_behavior]"=exclusive \ -d "line_items[0][quantity]"=1 \ -d "automatic_tax[enabled]"=true \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" ``` ```cli stripe checkout sessions create \ --billing-address-collection=required \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_address_collection[allowed_countries][1]"=CA \ -d "shipping_options[0][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[0][shipping_rate_data][fixed_amount][amount]"=0 \ -d "shipping_options[0][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[0][shipping_rate_data][display_name]"="Free shipping" \ -d "shipping_options[0][shipping_rate_data][tax_behavior]"=exclusive \ -d "shipping_options[0][shipping_rate_data][tax_code]"=txcd_92010001 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][value]"=5 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][value]"=7 \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][tax_behavior]"=exclusive \ -d "line_items[0][quantity]"=1 \ -d "automatic_tax[enabled]"=true \ --mode=payment \ --success-url="https://example.com/success" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ billing_address_collection: 'required', shipping_address_collection: {allowed_countries: ['US', 'CA']}, shipping_options: [ { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 0, currency: 'usd', }, display_name: 'Free shipping', tax_behavior: 'exclusive', tax_code: 'txcd_92010001', delivery_estimate: { minimum: { unit: 'business_day', value: 5, }, maximum: { unit: 'business_day', value: 7, }, }, }, }, ], line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, tax_behavior: 'exclusive', }, quantity: 1, }, ], automatic_tax: {enabled: true}, mode: 'payment', success_url: 'https://example.com/success', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "billing_address_collection": "required", "shipping_address_collection": {"allowed_countries": ["US", "CA"]}, "shipping_options": [ { "shipping_rate_data": { "type": "fixed_amount", "fixed_amount": {"amount": 0, "currency": "usd"}, "display_name": "Free shipping", "tax_behavior": "exclusive", "tax_code": "txcd_92010001", "delivery_estimate": { "minimum": {"unit": "business_day", "value": 5}, "maximum": {"unit": "business_day", "value": 7}, }, }, }, ], "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, "tax_behavior": "exclusive", }, "quantity": 1, }, ], "automatic_tax": {"enabled": True}, "mode": "payment", "success_url": "https://example.com/success", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'billing_address_collection' => 'required', 'shipping_address_collection' => ['allowed_countries' => ['US', 'CA']], 'shipping_options' => [ [ 'shipping_rate_data' => [ 'type' => 'fixed_amount', 'fixed_amount' => [ 'amount' => 0, 'currency' => 'usd', ], 'display_name' => 'Free shipping', 'tax_behavior' => 'exclusive', 'tax_code' => 'txcd_92010001', 'delivery_estimate' => [ 'minimum' => [ 'unit' => 'business_day', 'value' => 5, ], 'maximum' => [ 'unit' => 'business_day', 'value' => 7, ], ], ], ], ], 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, 'tax_behavior' => 'exclusive', ], 'quantity' => 1, ], ], 'automatic_tax' => ['enabled' => true], 'mode' => 'payment', 'success_url' => 'https://example.com/success', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setBillingAddressCollection(SessionCreateParams.BillingAddressCollection.REQUIRED) .setShippingAddressCollection( SessionCreateParams.ShippingAddressCollection.builder() .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.US ) .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.CA ) .build() ) .addShippingOption( SessionCreateParams.ShippingOption.builder() .setShippingRateData( SessionCreateParams.ShippingOption.ShippingRateData.builder() .setType( SessionCreateParams.ShippingOption.ShippingRateData.Type.FIXED_AMOUNT ) .setFixedAmount( SessionCreateParams.ShippingOption.ShippingRateData.FixedAmount.builder() .setAmount(0L) .setCurrency("usd") .build() ) .setDisplayName("Free shipping") .setTaxBehavior( SessionCreateParams.ShippingOption.ShippingRateData.TaxBehavior.EXCLUSIVE ) .setTaxCode("txcd_92010001") .setDeliveryEstimate( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.builder() .setMinimum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.Unit.BUSINESS_DAY ) .setValue(5L) .build() ) .setMaximum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.Unit.BUSINESS_DAY ) .setValue(7L) .build() ) .build() ) .build() ) .build() ) .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .setTaxBehavior(SessionCreateParams.LineItem.PriceData.TaxBehavior.EXCLUSIVE) .build() ) .setQuantity(1L) .build() ) .setAutomaticTax(SessionCreateParams.AutomaticTax.builder().setEnabled(true).build()) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ billing_address_collection: 'required', shipping_address_collection: { allowed_countries: ['US', 'CA'], }, shipping_options: [ { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 0, currency: 'usd', }, display_name: 'Free shipping', tax_behavior: 'exclusive', tax_code: 'txcd_92010001', delivery_estimate: { minimum: { unit: 'business_day', value: 5, }, maximum: { unit: 'business_day', value: 7, }, }, }, }, ], line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, tax_behavior: 'exclusive', }, quantity: 1, }, ], automatic_tax: { enabled: true, }, mode: 'payment', success_url: 'https://example.com/success', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ BillingAddressCollection: stripe.String(stripe.CheckoutSessionBillingAddressCollectionRequired), ShippingAddressCollection: &stripe.CheckoutSessionCreateShippingAddressCollectionParams{ AllowedCountries: []*string{stripe.String("US"), stripe.String("CA")}, }, ShippingOptions: []*stripe.CheckoutSessionCreateShippingOptionParams{ &stripe.CheckoutSessionCreateShippingOptionParams{ ShippingRateData: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataParams{ Type: stripe.String("fixed_amount"), FixedAmount: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataFixedAmountParams{ Amount: stripe.Int64(0), Currency: stripe.String(stripe.CurrencyUSD), }, DisplayName: stripe.String("Free shipping"), TaxBehavior: stripe.String("exclusive"), TaxCode: stripe.String("txcd_92010001"), DeliveryEstimate: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateParams{ Minimum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMinimumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(5), }, Maximum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMaximumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(7), }, }, }, }, }, LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), TaxBehavior: stripe.String("exclusive"), }, Quantity: stripe.Int64(1), }, }, AutomaticTax: &stripe.CheckoutSessionCreateAutomaticTaxParams{ Enabled: stripe.Bool(true), }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { BillingAddressCollection = "required", ShippingAddressCollection = new Stripe.Checkout.SessionShippingAddressCollectionOptions { AllowedCountries = new List { "US", "CA" }, }, ShippingOptions = new List { new Stripe.Checkout.SessionShippingOptionOptions { ShippingRateData = new Stripe.Checkout.SessionShippingOptionShippingRateDataOptions { Type = "fixed_amount", FixedAmount = new Stripe.Checkout.SessionShippingOptionShippingRateDataFixedAmountOptions { Amount = 0, Currency = "usd", }, DisplayName = "Free shipping", TaxBehavior = "exclusive", TaxCode = "txcd_92010001", DeliveryEstimate = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateOptions { Minimum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMinimumOptions { Unit = "business_day", Value = 5, }, Maximum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMaximumOptions { Unit = "business_day", Value = 7, }, }, }, }, }, LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, TaxBehavior = "exclusive", }, Quantity = 1, }, }, AutomaticTax = new Stripe.Checkout.SessionAutomaticTaxOptions { Enabled = true }, Mode = "payment", SuccessUrl = "https://example.com/success", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d billing_address_collection=required \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_address_collection[allowed_countries][1]"=CA \ -d "shipping_options[0][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[0][shipping_rate_data][fixed_amount][amount]"=0 \ -d "shipping_options[0][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[0][shipping_rate_data][display_name]"="Free shipping" \ -d "shipping_options[0][shipping_rate_data][tax_behavior]"=exclusive \ -d "shipping_options[0][shipping_rate_data][tax_code]"=txcd_92010001 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][value]"=5 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][value]"=7 \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][tax_behavior]"=exclusive \ -d "line_items[0][quantity]"=1 \ -d "automatic_tax[enabled]"=true \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" ``` ```cli stripe checkout sessions create \ --billing-address-collection=required \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_address_collection[allowed_countries][1]"=CA \ -d "shipping_options[0][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[0][shipping_rate_data][fixed_amount][amount]"=0 \ -d "shipping_options[0][shipping_rate_data][fixed_amount][currency]"=usd \ -d "shipping_options[0][shipping_rate_data][display_name]"="Free shipping" \ -d "shipping_options[0][shipping_rate_data][tax_behavior]"=exclusive \ -d "shipping_options[0][shipping_rate_data][tax_code]"=txcd_92010001 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][minimum][value]"=5 \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][unit]"=business_day \ -d "shipping_options[0][shipping_rate_data][delivery_estimate][maximum][value]"=7 \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][tax_behavior]"=exclusive \ -d "line_items[0][quantity]"=1 \ -d "automatic_tax[enabled]"=true \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ billing_address_collection: 'required', shipping_address_collection: {allowed_countries: ['US', 'CA']}, shipping_options: [ { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 0, currency: 'usd', }, display_name: 'Free shipping', tax_behavior: 'exclusive', tax_code: 'txcd_92010001', delivery_estimate: { minimum: { unit: 'business_day', value: 5, }, maximum: { unit: 'business_day', value: 7, }, }, }, }, ], line_items: [ { price_data: { currency: 'usd', product_data: {name: 'T-shirt'}, unit_amount: 2000, tax_behavior: 'exclusive', }, quantity: 1, }, ], automatic_tax: {enabled: true}, mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "billing_address_collection": "required", "shipping_address_collection": {"allowed_countries": ["US", "CA"]}, "shipping_options": [ { "shipping_rate_data": { "type": "fixed_amount", "fixed_amount": {"amount": 0, "currency": "usd"}, "display_name": "Free shipping", "tax_behavior": "exclusive", "tax_code": "txcd_92010001", "delivery_estimate": { "minimum": {"unit": "business_day", "value": 5}, "maximum": {"unit": "business_day", "value": 7}, }, }, }, ], "line_items": [ { "price_data": { "currency": "usd", "product_data": {"name": "T-shirt"}, "unit_amount": 2000, "tax_behavior": "exclusive", }, "quantity": 1, }, ], "automatic_tax": {"enabled": True}, "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'billing_address_collection' => 'required', 'shipping_address_collection' => ['allowed_countries' => ['US', 'CA']], 'shipping_options' => [ [ 'shipping_rate_data' => [ 'type' => 'fixed_amount', 'fixed_amount' => [ 'amount' => 0, 'currency' => 'usd', ], 'display_name' => 'Free shipping', 'tax_behavior' => 'exclusive', 'tax_code' => 'txcd_92010001', 'delivery_estimate' => [ 'minimum' => [ 'unit' => 'business_day', 'value' => 5, ], 'maximum' => [ 'unit' => 'business_day', 'value' => 7, ], ], ], ], ], 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => ['name' => 'T-shirt'], 'unit_amount' => 2000, 'tax_behavior' => 'exclusive', ], 'quantity' => 1, ], ], 'automatic_tax' => ['enabled' => true], 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setBillingAddressCollection(SessionCreateParams.BillingAddressCollection.REQUIRED) .setShippingAddressCollection( SessionCreateParams.ShippingAddressCollection.builder() .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.US ) .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.CA ) .build() ) .addShippingOption( SessionCreateParams.ShippingOption.builder() .setShippingRateData( SessionCreateParams.ShippingOption.ShippingRateData.builder() .setType( SessionCreateParams.ShippingOption.ShippingRateData.Type.FIXED_AMOUNT ) .setFixedAmount( SessionCreateParams.ShippingOption.ShippingRateData.FixedAmount.builder() .setAmount(0L) .setCurrency("usd") .build() ) .setDisplayName("Free shipping") .setTaxBehavior( SessionCreateParams.ShippingOption.ShippingRateData.TaxBehavior.EXCLUSIVE ) .setTaxCode("txcd_92010001") .setDeliveryEstimate( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.builder() .setMinimum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Minimum.Unit.BUSINESS_DAY ) .setValue(5L) .build() ) .setMaximum( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.builder() .setUnit( SessionCreateParams.ShippingOption.ShippingRateData.DeliveryEstimate.Maximum.Unit.BUSINESS_DAY ) .setValue(7L) .build() ) .build() ) .build() ) .build() ) .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setUnitAmount(2000L) .setTaxBehavior(SessionCreateParams.LineItem.PriceData.TaxBehavior.EXCLUSIVE) .build() ) .setQuantity(1L) .build() ) .setAutomaticTax(SessionCreateParams.AutomaticTax.builder().setEnabled(true).build()) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ billing_address_collection: 'required', shipping_address_collection: { allowed_countries: ['US', 'CA'], }, shipping_options: [ { shipping_rate_data: { type: 'fixed_amount', fixed_amount: { amount: 0, currency: 'usd', }, display_name: 'Free shipping', tax_behavior: 'exclusive', tax_code: 'txcd_92010001', delivery_estimate: { minimum: { unit: 'business_day', value: 5, }, maximum: { unit: 'business_day', value: 7, }, }, }, }, ], line_items: [ { price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, tax_behavior: 'exclusive', }, quantity: 1, }, ], automatic_tax: { enabled: true, }, mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ BillingAddressCollection: stripe.String(stripe.CheckoutSessionBillingAddressCollectionRequired), ShippingAddressCollection: &stripe.CheckoutSessionCreateShippingAddressCollectionParams{ AllowedCountries: []*string{stripe.String("US"), stripe.String("CA")}, }, ShippingOptions: []*stripe.CheckoutSessionCreateShippingOptionParams{ &stripe.CheckoutSessionCreateShippingOptionParams{ ShippingRateData: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataParams{ Type: stripe.String("fixed_amount"), FixedAmount: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataFixedAmountParams{ Amount: stripe.Int64(0), Currency: stripe.String(stripe.CurrencyUSD), }, DisplayName: stripe.String("Free shipping"), TaxBehavior: stripe.String("exclusive"), TaxCode: stripe.String("txcd_92010001"), DeliveryEstimate: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateParams{ Minimum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMinimumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(5), }, Maximum: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataDeliveryEstimateMaximumParams{ Unit: stripe.String("business_day"), Value: stripe.Int64(7), }, }, }, }, }, LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ Currency: stripe.String(stripe.CurrencyUSD), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), TaxBehavior: stripe.String("exclusive"), }, Quantity: stripe.Int64(1), }, }, AutomaticTax: &stripe.CheckoutSessionCreateAutomaticTaxParams{ Enabled: stripe.Bool(true), }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { BillingAddressCollection = "required", ShippingAddressCollection = new Stripe.Checkout.SessionShippingAddressCollectionOptions { AllowedCountries = new List { "US", "CA" }, }, ShippingOptions = new List { new Stripe.Checkout.SessionShippingOptionOptions { ShippingRateData = new Stripe.Checkout.SessionShippingOptionShippingRateDataOptions { Type = "fixed_amount", FixedAmount = new Stripe.Checkout.SessionShippingOptionShippingRateDataFixedAmountOptions { Amount = 0, Currency = "usd", }, DisplayName = "Free shipping", TaxBehavior = "exclusive", TaxCode = "txcd_92010001", DeliveryEstimate = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateOptions { Minimum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMinimumOptions { Unit = "business_day", Value = 5, }, Maximum = new Stripe.Checkout.SessionShippingOptionShippingRateDataDeliveryEstimateMaximumOptions { Unit = "business_day", Value = 7, }, }, }, }, }, LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { Currency = "usd", ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, UnitAmount = 2000, TaxBehavior = "exclusive", }, Quantity = 1, }, }, AutomaticTax = new Stripe.Checkout.SessionAutomaticTaxOptions { Enabled = true }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` Your customer can see the calculated tax amount for the shipping rate factored into the total sales tax in your checkout flow: ![Calculated tax amount for the shipping rate on the checkout page](https://b.stripecdn.com/docs-statics-srv/assets/taxed-shipping.14e1bb580c37e035fcf2f0016680db5a.jpg) Calculated tax amount for the shipping rate in the checkout flow --- # Source: https://docs.stripe.com/revenue-recognition/connect/charges-transfers.md # Revenue Recognition for separate charges and transfers Learn how revenue recognition works with separate charges and transfers. With Connect, you can make charges on your platform account on behalf of connected accounts, perform transfers separately, and retain funds in the process. Stripe Revenue Recognition manages separate charges on the platform account in the same manner we handle charges and invoices. Stripe books separate transfers as contra revenue, and transfer reversals cancel out the contra revenue. Revenue recognition doesn’t automatically link [separate charges and transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md) because they might not always have a direct connection. In this example, `amount="1000"` is set on the separate transfer. - On January 1, you create a charge of 15 USD. - On January 2, you create a transfer of 10 USD. - On February 1, you create a refund of 15 USD. - On February 2, you create a transfer reversal of 10 USD. If you view the summary after February ends, your data might resemble the following: | Account | Jan | Feb | | -------- | ------ | ------ | | Revenue | +15.00 | | | Refund | | +15.00 | | Transfer | +10.00 | -10.00 | | Cash | +5.00 | -5.00 | --- # Source: https://docs.stripe.com/connect/charges.md # Understand how charges work in a Connect integration Learn about the types of charges used in Connect integrations and how funds move between the platform and connected accounts. In a *Connect* (Connect is Stripe's solution for multi-party businesses, such as marketplace or software platforms, to route payments between sellers, customers, and other recipients) integration, for your platform or a connected account to accept a payment from a customer, you must first create a charge. The type of charge you create determines how the funds are distributed between your platform, the connected account, and Stripe. It also determines whether your platform’s or the connected account’s information appears on the customer’s bank or billing statement and which account Stripe debits for refunds and chargebacks. ## Charge types Connect uses three types of charges in two general categories: - [Direct charges](https://docs.stripe.com/connect/charges.md#direct): payments made directly to a connected account. Funds then transfer from the connected account to Stripe or the platform account as fees. - Indirect charges: Payments made to your platform. Funds then transfer from your platform to Stripe as fees and to the connected account as its portion of the payment. Indirect charges include [destination charges](https://docs.stripe.com/connect/charges.md#destination) and [separate charges and transfers](https://docs.stripe.com/connect/charges.md#separate-charges-transfers), which differ in the way they transfer funds from your platform to connected accounts. The following table describes many factors to consider when choosing which charge type to use. Your platform’s business model is particularly important because it can affect how funds flow through Stripe. To review Stripe’s recommendations for your business, refer to your [platform profile](https://dashboard.stripe.com/connect/settings/profile). | Charge type | Use cases | Examples | | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Direct charges](https://docs.stripe.com/connect/charges.md#direct-charges) | - Your connected accounts transact directly with their customers, who are often unaware of your platform’s existence. - Each transaction involves a single connected account and a single customer. - You want to choose whether Stripe debits fees from your connected accounts or from your platform. | - An e-commerce platform for independent sellers. - A Software as a Service (SaaS) platform, such as an accounting platform that enables invoice payments. | | [Destination charges](https://docs.stripe.com/connect/charges.md#destination-charges) | - Customers transact with your platform for products or services provided by your connected accounts. - Each transaction involves a single connected account and a single customer. - Stripe debits fees from your platform account. | - A branded service that uses independent contractors, such as a rideshare app. - A business services marketplace, such as a website that matches contractors with homeowners. | | [Separate charges and transfers](https://docs.stripe.com/connect/charges.md#separate-charges-and-transfers) | - Individual transactions can involve multiple connected accounts. - You can create a charge before knowing the connected account. - You can create a charge before being able to transfer the funds. - Stripe debits fees from your platform account. | - An e-commerce marketplace that allows a single shopping cart for goods sold by multiple businesses | You can use multiple charge types, if that’s appropriate for your business. ### Direct charges Create a charge directly on a connected account. The account’s customers are often unaware of your platform’s existence. You can specify an application fee, which transfers to your platform’s account balance when the connected account collects the payment. > Your connected accounts must have the [card_payments capability](https://docs.stripe.com/connect/account-capabilities.md) active in order to use direct charges. This charge type is best suited for platforms providing Software as a Service (SaaS). For example, Shopify provides tools for building online storefronts, and Thinkific enables educators to sell online courses. With this charge type: - You create a charge on your connected account, so the payment appears in the connected account’s balance, not in your platform’s balance. - The connected account’s balance increases with every charge. - Funds always settle in the country of the connected account. - Your platform’s balance increases with any application fees you collect for a charge. - Refunds and chargebacks reduce the connected account’s balance. - You can choose whether to have Stripe debit fees directly from connected accounts or from your platform account. - You can use Stripe Managed Risk if you meet these [additional requirements](https://docs.stripe.com/connect/risk-management/managed-risk.md#requirements-to-use-stripe-managed-risk). ![Direct charges funds flow diagram](https://b.stripecdn.com/docs-statics-srv/assets/direct_charges.a2a8b68037ac95fe22140d6dde9740d3.svg) Funds flow for direct charges For more information about direct charges, see [Direct charges](https://docs.stripe.com/connect/direct-charges.md). ### Destination charges Create a charge on the platform and immediately transfer funds to the connected account. You decide whether some or all of those funds are transferred, and whether to deduct an application fee. This charge type is best suited for marketplaces, such as a home rental marketplace or a ridesharing app. With this charge type: - You create a charge on your platform, so the payment appears in your platform’s balance. A portion of the funds immediately transfers to the connected account’s balance (see the funds flow diagrams below). - The portion of the funds that remains in your platform balance represents the fee you charge your connected account. - Refunds and chargebacks reduce your platform’s balance. - Stripe debits fees from your platform’s balance. ![Destination charges with fee deducted funds flow diagram](https://b.stripecdn.com/docs-statics-srv/assets/platform_charges.6a14fd660d7433ba617e816ff09f10b5.svg) Funds flow for destination charges with the platform fee deducted from the transferred amount ![Destination charges with post-paid fee funds flow diagram](https://b.stripecdn.com/docs-statics-srv/assets/application_fee_amount.837aa2339469b3c1a4319672971c1367.svg) Funds flow for destination charges with the platform fee paid after transferring the full amount > Destination charges support cross-region funds flows between platforms and connected accounts only in certain regions. For other regions, the platform and connected account must be in the same region unless using `on_behalf_of`. For more information about cross-region support, see [Cross-border transfers](https://docs.stripe.com/connect/cross-border-payouts.md). For more information about destination charges, see [Destination charges](https://docs.stripe.com/connect/destination-charges.md). ### Separate charges and transfers Create charges on your platform and split funds between multiple connected accounts, or hold them when you don’t know the specific user at the time of the charge. The charge on your platform account is decoupled from the transfers to your connected accounts. This charge type is best suited for marketplaces that need to split payments between multiple parties, such as DoorDash, a restaurant delivery platform. For [Express](https://docs.stripe.com/connect/express-accounts.md) and [Custom](https://docs.stripe.com/connect/custom-accounts.md) accounts, Stripe recommends that you create [separate charges and transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md) if destination charges don’t meet your business needs. With this charge type: - You create a charge on your platform’s account first. Create a separate transfer to move funds to your connected account. The payment appears as a charge on your account and there’s also a transfer to a connected account (amount determined by you), which is withdrawn from your [account balance](https://docs.stripe.com/connect/account-balances.md). - You can transfer funds to multiple connected accounts. - Your account balance is debited for the cost of the Stripe fees, refunds, and chargebacks. Separate charges and transfers require a more complex Connect integration. Use them only if your business use case requires them: - A one-to-many relationship. For example, a payment made to a delivery service needs to be split between the store (the source of the items being delivered) and the delivery person. - A many-to-one relationship. For example, a carpool trip with a ride-hailing service. - Charges created before the destination account is known. For example, a janitorial service could process a payment before deciding which janitor to assign to the job. - Need to transfer funds before receiving a payment, or while the charge is pending. For example, an ad network needs to purchase ad space before they can sell ad time or before receiving any payment from customers. - Transfer amounts greater than the associated payments. For example, a platform provides a discount to its customer but pays its user the full amount. In some cases, the transfer amount can be greater than the charge amount, or the transfer is made before the payment is processed. You must monitor your account balance carefully to make sure it has enough available funds to cover the transfer amount. You can also associate a transfer with a charge so the transfer doesn’t occur until the funds from that charge are available. ![Separate charges and transfers with multiple connected accounts funds flow diagram](https://b.stripecdn.com/docs-statics-srv/assets/charges_transfers.a95f5bf398651fba0fb303e32a742546.svg) Funds flow for separate charges and transfers with multiple connected accounts > Separate charges and transfers support cross-region funds flows between platforms and connected accounts only in certain regions. For other regions, the platform and connected account must be in the same region unless using `on_behalf_of`. For more information about cross-region support, see [Cross-border transfers](https://docs.stripe.com/connect/cross-border-payouts.md). For more information about separate charges and transfers, see [Separate charges and transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md). ### Indirect charges using the on_behalf_of parameter To make the connected account the business of record for the payment, use the `on_behalf_of` parameter. When `on_behalf_of` is set to the ID of the connected account, Stripe automatically: - Settles charges in the country of the specified account to minimize declines and avoid [currency conversions](https://docs.stripe.com/connect/currencies/fx-quotes-api.md#currency-conversions). - Uses the fee structure for the connected account’s country. - Uses the [connected account’s statement descriptor](https://docs.stripe.com/connect/statement-descriptors.md). - Uses the connected account’s address and phone number (rather than the platform’s) on the customer’s statement if the connected account is in a different country than the platform. - Pays out a connected account, depending on the days specified in its `delays_days` setting. ## Stripe fees There are two components to Stripe fees with Connect: which pricing plan applies to the payment and which account pays Stripe fees. When using Direct charges, you can choose how Stripe fees are billed to your connected accounts. [Read more about fee billing behaviors with Direct charges.](https://docs.stripe.com/connect/direct-charges-fee-payer-behavior.md) Destination charges and separate charges and transfers typically use the platform’s pricing plan and are assessed on the platform. When the `on_behalf_of` field is set, the country of the connected account is used to determine the country specific fees charged to your platform account. For more information on Connect fees and how to request custom pricing, see [the Connect pricing page](https://stripe.com/connect/pricing). ## Refunds You can issue a refund to pay a customer back for money spent on a returned good or to compensate for unsatisfactory service. Stripe handles refunds differently for each of the charge types: | Charge Types | Pending Refunds | | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Direct charges** | Stripe debits the refund amount from the connected account’s balance directly when you create a refund. If the connected account’s balance is insufficient, we set the refund status to `pending`. When the connected account’s balance has enough funds, Stripe automatically processes pending refunds in the order they were created and updates their status to `successful`. | | **Destination charges** | Stripe debits your platform balance for the refund amount. You can reverse the transfers made to your connected accounts to recover your refund cost. If your platform’s account balance doesn’t have the funds when you [issue the Refund](https://docs.stripe.com/connect/destination-charges.md#issue-refunds), we set the refund status to `pending`. When your platform’s balance has enough funds, Stripe automatically processes pending refunds and updates their status to `successful`. If the refund request also attempts a transfer reversal, but the connected account has an insufficient balance, the refund request returns an error instead of creating a refund with `pending` status. | | **Separate charges and transfers** | Stripe debits your platform balance for the refund amount. You can reverse the transfers made to your connected accounts to recover your refund cost. If your platform’s account balance doesn’t have the funds when you [issue the Refund](https://docs.stripe.com/connect/separate-charges-and-transfers.md#issue-refunds), we set the refund status to `pending`. When you platform balance has enough funds, Stripe automatically processes pending refunds and updates their status to `successful`. | ## Disputes and chargebacks For disputes on payments created using [direct charges](https://docs.stripe.com/connect/direct-charges.md), Stripe debits the disputed amount from the connected account’s balance, not your platform’s balance. Stripe can bill the dispute fee to either the platform or the connected account, depending on the connected account’s configuration. For more detail about how we bill fees for disputes on direct charges, see [Fee behavior on connected accounts](https://docs.stripe.com/connect/direct-charges-fee-payer-behavior.md). For disputes where payments were created on your platform using [destination charges](https://docs.stripe.com/connect/destination-charges.md) or [separate charges and transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md), with or without `on_behalf_of`, your platform balance is automatically debited for the disputed amount and fee. When this happens, your platform can attempt to recover funds from the connected account by reversing the transfer either through the [Dashboard](https://dashboard.stripe.com/test/transfers) or [using the API](https://docs.stripe.com/api.md#create_transfer_reversal). If there’s a negative balance on the connected account, Stripe attempts to debit the external account on file for the connected account only if `debit_negative_balances` is set to `true`. For more details, see [Disputes and fraud](https://docs.stripe.com/disputes.md) and [Dispute categories](https://docs.stripe.com/disputes/categories.md). You can also use [Fraud Stripe Apps](https://marketplace.stripe.com/categories/fraud) to automate dispute management and handle chargebacks. ## See also - [Create direct charges](https://docs.stripe.com/connect/direct-charges.md) - [Create destination charges](https://docs.stripe.com/connect/destination-charges.md) - [Create separate charges and transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md) - [Set statement descriptors](https://docs.stripe.com/connect/statement-descriptors.md) - [Integrate tax calculation and collection](https://docs.stripe.com/tax/connect.md) --- # Source: https://docs.stripe.com/revenue-recognition/chart-of-accounts.md # Map to your chart of accounts Map transactions from the Stripe default accounts to the chart of accounts in your general ledger. You can customize Stripe Revenue Recognition reporting to use your General Ledger (GL) chart of accounts instead of using the default [Stripe accounts](https://docs.stripe.com/revenue-recognition/methodology.md). You can configure a rule to map transactions by product, shipping region, or invoice metadata to your GL account. Stripe applies your custom mappings to the [CSV reports](https://docs.stripe.com/revenue-recognition/reports.md#statements) you download and also when you [audit your revenue numbers](https://docs.stripe.com/revenue-recognition/reports/audit-numbers.md). A mapping rule consists of the following: | Mapping rule attribute | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Stripe account | The [Stripe default account](https://docs.stripe.com/revenue-recognition/methodology.md#chart-of-accounts) that you want to override. | | GL account | The name of the GL account you want to override the Stripe account with. | | GL account number | The number corresponding to the GL account. | | Time period | The time period the mapping applies to. An [invoice line item](https://docs.stripe.com/api/invoices/line_item.md) fulfills the time period requirement if the finalization time of the invoice is within the specified time period. A [charge](https://docs.stripe.com/api/charges.md) fulfills the time period requirement if the balance transaction it corresponds to has a creation time that’s within the specified time period. | | Condition | An optional criteria to map transactions by product, shipping region, or invoice metadata. If not specified, all transactions involving the configured Stripe account are mapped to the GL account. | | Status | **Active**: The mapping rule is active and all transactions are mapped as per the rule. **Processing**: The rule is processing. On completion, the rule is active and transactions are mapped accordingly. | ## Configuring a mapping rule Mapping rule configuration is a 4-step process—click the add mapping button on the accounts mapping page to begin. 1. **Select Stripe account**: Select the default Stripe account from the dropdown for which you want to create the rule. 1. **Select GL account**: You can select your GL account from the dropdown or add one if you can’t find it in the dropdown. When setting up the rules for the first time, you have to add these accounts by specifying the GL account name and number. You have to specify at least a name or a number to add the account. 1. **Specify time period**: The time period is the time frame in which the mapping rule is applicable. Select a start and end date from the dropdown to configure the time period. If you specify an time period that overlaps with closed accounting periods, you’ll see corrections in your report in the current open accounting period. You can reopen the past accounting periods corresponding to the time period to avoid corrections. 1. (Optional) **Specify mapping condition\***: You can specify a mapping condition on any of the following attributes: - **Product**: If you have product specific accounts in your GL, you can classify your transactions based on the products that you have configured in the Stripe Dashboard. - **Shipping region**: Similar to products, you can specify the shipping region to map transactions to the relevant GL account. Only ISO-compliant country and state codes are supported. - **Invoice metadata**: You can configure a custom rule using invoice metadata if your GL accounts don’t track transactions by product or shipping region. Create a rule by selecting a key and adding a value. The keys are from metadata you created in past invoices.** - **Price**: Use Price IDs configured in the Stripe Dashboard to map transactions to the relevant GL account. - **Credit note**: Specify the credit note line item description to map transactions to the relevant GL account. - **Coupon**: Use Coupon IDs configured in the Stripe Dashboard to map transactions to the relevant GL account. Click **Map chart of accounts** to create the mapping rule and for Stripe to [process the data](https://docs.stripe.com/revenue-recognition/data-freshness.md). The rule’s status changes to active when the data processing is complete, and you can then download reports with the mapped GL accounts. ## Mapping rule configuration example The following example involves 3 different products: - Product A: Annual subscription cost of 1,200 USD - Product B: Annual subscription cost of 2,400 USD - Product C: Annual subscription cost of 3,600 USD If you sell 1 subscription each for A, B, and C in January, your journal entry at the end of the month appears as follows without account mapping: | Account | January | | ---------------- | --------- | | Revenue | +600 USD | | Deferred Revenue | +6600 USD | However, the user has 3 separate revenue accounts in its GL, say revenue_A, revenue_B, and revenue_C for tracking revenue corresponding to these 3 products. The user has to do manual work to identify revenue in these accounts before posting to its GL. If you have product-specific accounts in your General Ledger that you want to map to, you can create 3 mapping rules: | Stripe account | GL account number | GL account | Condition | Time period | | -------------- | ----------------- | ---------- | --------- | --------------------- | | Revenue | 10001 | revenue_A | Product A | Jan 2026 - Indefinite | | Revenue | 10002 | revenue_B | Product B | Jan 2026 - Indefinite | | Revenue | 10003 | revenue_C | Product C | Jan 2026 - Indefinite | After you set up these rules, your journal entries will contain three line items reflecting the revenue distribution for each product. This can help you streamline the process of posting to your GL. | GL account number | Account | January | | ----------------- | ---------------- | --------- | | 1001 | revenue_A | +100 USD | | 1002 | revenue_B | +200 USD | | 1003 | revenue_C | +300 USD | | - | Deferred Revenue | +6600 USD | If you need to create multiple mapping rules at once, you can use our [bulk account mapping feature](https://docs.stripe.com/revenue-recognition/chart-of-accounts/bulk-account-mappings.md#upload-mappings) to upload mappings via CSV file. This reduces manual effort and minimizes the risk of errors when configuring numerous GL accounts. \* For a default Stripe account, you can only pick one attribute to create a rule. Please [create a ticket](https://support.stripe.com/contact/email?topic=financial_reports) on our support page if you have any questions.\** Don’t import any personally identifiable information and/or protected health information. --- # Source: https://docs.stripe.com/payments/link/checkout-link.md # Link with Checkout Use Link with Stripe's prebuilt checkout page. You can also use Link with [Payment Links](https://docs.stripe.com/payment-links.md). Checkout is a [prebuilt payment form](https://docs.stripe.com/payments/checkout.md) that you can embed on your site or use as a Stripe-hosted payment page. Use Link with Checkout to allow your customers to securely save and reuse their payment information. For logged-in customers already using Link, it autofills this information regardless of whether they initially saved it on a different business’s checkout page. Checkout supports Link with no additional fees, and the same [pricing](https://stripe.com/pricing) applies as for other card payments. For information about how your payment integration affects Link, see [Link in different payment integrations](https://docs.stripe.com/payments/link/link-payment-integrations.md). ![Add Link to your prebuilt checkout page](https://b.stripecdn.com/docs-statics-srv/assets/link-in-checkout.2eb9f8d06da3dca74af9b81fa7524049.png) Add Link to your prebuilt checkout page ## Before you begin Build an integration to [accept a payment](https://docs.stripe.com/payments/accept-a-payment.md?integration=checkout) using Checkout. ## Enable Link in Checkout Accept payments with Link using information your customer stores in the [Link app](https://link.com/). When you receive a payment from a customer using Link in Checkout, the `payment_method.type` listed for the payment is `link`. To add Link to your [Checkout integration](https://docs.stripe.com/payments/accept-a-payment.md?integration=checkout), create a Checkout Session with `link` as a payment method type. #### Use dynamic payment methods Use [dynamic payment methods](https://docs.stripe.com/payments/payment-methods/dynamic-payment-methods.md) to increase conversion by showing the most relevant payment methods to your customers. If you collect card details for [future usage with Setup Intents](https://docs.stripe.com/payments/save-and-reuse.md), list payment methods manually instead of using dynamic payment methods. To add Link as a payment method: 1. Enable the Link payment method from your [payment method settings](https://dashboard.stripe.com/settings/payment_methods). 1. If you have an existing integration that manually lists payment methods, remove the [payment_method_types](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-payment_method_types) parameter from your integration. ![Preview of Link enabled as payment method in the Stripe Dashboard](https://b.stripecdn.com/docs-statics-srv/assets/enable-link-stripe-dashboard.1bd2411da48c323997c27a6dabee9b4c.png) Link enabled as a payment method in the Stripe Dashboard After you remove the `payment_method_types` parameter from your integration, some payment methods turn on automatically, including cards and wallets. The currency parameter restricts the payment methods that the customer sees during the checkout session. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --success-url="https://example.com/success" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price_data: { unit_amount: 2000, product_data: {name: 'T-shirt'}, currency: 'usd', }, quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [ { "price_data": { "unit_amount": 2000, "product_data": {"name": "T-shirt"}, "currency": "usd", }, "quantity": 1, }, ], "mode": "payment", "success_url": "https://example.com/success", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price_data' => [ 'unit_amount' => 2000, 'product_data' => ['name' => 'T-shirt'], 'currency' => 'usd', ], 'quantity' => 1, ], ], 'mode' => 'payment', 'success_url' => 'https://example.com/success', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setUnitAmount(2000L) .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setCurrency("usd") .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { unit_amount: 2000, product_data: { name: 'T-shirt', }, currency: 'usd', }, quantity: 1, }, ], mode: 'payment', success_url: 'https://example.com/success', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ UnitAmount: stripe.Int64(2000), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, Currency: stripe.String(stripe.CurrencyUSD), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { UnitAmount = 2000, ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, Currency = "usd", }, Quantity = 1, }, }, Mode = "payment", SuccessUrl = "https://example.com/success", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Manually list payment methods When creating a new [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md), you need to: 1. Add `link` to the list of `payment_method_types`. 1. Make sure `card` is also included in the list of `payment_method_types`. 1. Make sure all your `line_items` use the same currency. #### Ruby ```ruby Stripe::Checkout::Session.create({ mode: 'payment',payment_method_types: ['card', 'link'], line_items: [{ price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }], success_url: 'https://example.com/success', }) ``` #### Python ```python stripe.checkout.Session.create(payment_method_types=['card', 'link'], line_items=[{ 'price_data': { 'currency': 'usd', 'product_data': { 'name': 'T-shirt', }, 'unit_amount': 2000, }, 'quantity': 1, }], mode='payment', success_url='https://example.com/success', ) ``` #### PHP ```php $session = \Stripe\Checkout\Session::create(['payment_method_types' => ['card', 'link'], 'line_items' => [[ 'price_data' => [ 'currency' => 'usd', 'product_data' => [ 'name' => 'T-shirt', ], 'unit_amount' => 2000, ], 'quantity' => 1, ]], 'mode' => 'payment', 'success_url' => 'https://example.com/success', ]); ``` #### Java ```java SessionCreateParams params = SessionCreateParams.builder() .addPaymentMethodType(SessionCreateParams.PaymentMethodType.CARD).addPaymentMethodType(SessionCreateParams.PaymentMethodType.LINK) .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setCurrency("usd") .setUnitAmount(2000L) .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build()) .build()) .setQuantity(1L) .build()) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .build(); Session session = Session.create(params); ``` #### Node.js ```javascript const session = await stripe.checkout.sessions.create({payment_method_types: ['card', 'link'], line_items: [{ price_data: { currency: 'usd', product_data: { name: 'T-shirt', }, unit_amount: 2000, }, quantity: 1, }], mode: 'payment', success_url: 'https://example.com/success', }); ``` #### Go ```go params := &stripe.CheckoutSessionParams{ PaymentMethodTypes: stripe.StringSlice([]string{ "card","link", }), LineItems: []*stripe.CheckoutSessionLineItemParams{ &stripe.CheckoutSessionLineItemParams{ PriceData: &stripe.CheckoutSessionLineItemPriceDataParams{ Currency: stripe.String("usd"), ProductData: &stripe.CheckoutSessionLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, UnitAmount: stripe.Int64(2000), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(string(stripe.CheckoutSessionModePayment)), SuccessURL: stripe.String("https://example.com/success"), }; s, _ := session.New(params) ``` #### .NET ```dotnet var options = new SessionCreateOptions { PaymentMethodTypes = new List { "card","link", }, LineItems = new List { new SessionLineItemOptions { PriceData = new SessionLineItemPriceDataOptions { UnitAmount = 2000, Currency = "usd", ProductData = new SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, }, Quantity = 1, }, }, Mode = "payment", SuccessUrl = "https://example.com/success", }; var service = new SessionService(); var session = service.Create(options); ``` ## Test the integration > Don’t store real user data in *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) Link accounts. Treat them as if they’re publicly available, because these test accounts are associated with your publishable key. Currently, Link only works with credit cards, debit cards, and qualified US bank account purchases. Link requires [domain registration](https://docs.stripe.com/payments/payment-methods/pmd-registration.md). You can create sandbox accounts for Link using any valid email address. The following table shows the fixed one-time passcode values that Stripe accepts for authenticating sandbox accounts: | Value | Outcome | | ----------------------------------- | ---------------------------- | | Any other 6 digits not listed below | Success | | 000001 | Error, code invalid | | 000002 | Error, code expired | | 000003 | Error, max attempts exceeded | ### Multiple funding sources As Stripe adds additional funding source support, you don’t need to update your integration. Stripe automatically supports them with the same transaction settlement time and guarantees as card and bank account payments. ## Link for Connect platforms Link is automatically available to any connected account that uses Checkout through a Connect platform integration. - If you’re a Connect platform, you can manage Link for your platform account through [Link settings](https://dashboard.stripe.com/settings/link) in your Dashboard. Your connected accounts manage Link from within their own Dashboard settings. - If you’re a connected account processing payments through a Connect platform, you can manage Link for both payments processed through a platform and payments processed without a platform in your Link settings in the Dashboard. ## Disable Link You can disable Link in the Stripe Dashboard [payment method settings](https://dashboard.stripe.com/settings/payment_methods). You must change the settings for Link individually for each [payment method configuration](https://docs.stripe.com/payments/payment-method-configurations.md). After you disable Link for a payment method configuration, the change might take a few minutes to take effect on your website. ## See also - [Stripe Checkout](https://docs.stripe.com/payments/checkout.md) - [How Checkout works](https://docs.stripe.com/payments/checkout/how-checkout-works.md) - [Quickstart](https://docs.stripe.com/checkout/quickstart.md) --- # Source: https://docs.stripe.com/tax/checkout.md # Source: https://docs.stripe.com/payments/checkout.md # Use a prebuilt Stripe-hosted payment page [Checkout](https://stripe.com/payments/checkout) is a low-code, prebuilt payment page that Stripe hosts or that you can embed into your website. Checkout uses the [Checkout Sessions API](https://docs.stripe.com/api/checkout/sessions.md). ## Create a payments form to accept payments on your website Accept one-time and subscription payments from more than 40 local payment methods. [Start building your checkout integration](https://docs.stripe.com/checkout/quickstart.md) ## Payment UIs You can use two different payment UIs with the [Checkout Sessions API](https://docs.stripe.com/api/checkout/sessions.md). The following images highlight which aspects of the checkout UI Stripe hosts in each option. You can also see these options by [exploring our demo](https://checkout.stripe.dev). ![Hosted checkout form](https://b.stripecdn.com/docs-statics-srv/assets/checkout-hosted-hover.4f0ec46833037b6fd0f1a62d9fcf7053.png) [Stripe-hosted page](https://docs.stripe.com/checkout/quickstart.md) Customers enter their payment details in a Stripe-hosted payment page, then return to your site after payment completion. ![Embedded Checkout form](https://b.stripecdn.com/docs-statics-srv/assets/checkout-embedded-hover.19e99126cb27ab25f704d7357f672e1f.png) [Embedded form](https://docs.stripe.com/checkout/embedded/quickstart.md) Customers enter their payment details in an embedded payment form on your site without redirection. |   | [STRIPE-HOSTED PAGE](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=checkout&ui=stripe-hosted) | [EMBEDDED FORM](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=checkout&ui=embedded-form) | | ---------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | **UI** | [Checkout](https://docs.stripe.com/payments/checkout/how-checkout-works.md?payment-ui=stripe-hosted) | [Checkout](https://docs.stripe.com/payments/checkout/how-checkout-works.md?payment-ui=embedded-form) | | **API** | [Checkout Sessions](https://docs.stripe.com/api/checkout/sessions.md) | [Checkout Sessions](https://docs.stripe.com/api/checkout/sessions.md) | | **Integration effort** | Complexity: 2/5 | Complexity: 2/5 | | **Hosting** | Stripe-hosted page (optional [custom domains](https://docs.stripe.com/payments/checkout/custom-domains.md)) | Embed on your site | | **UI customization** | Limited customization1 | Limited customization1 | 1Limited customization provides [20 preset fonts](https://docs.stripe.com/payments/checkout/customization/appearance.md#font-compatibility), 3 preset border radius options, logo and background customization, and custom button color. ## Customize checkout [Customize the look and feel](https://docs.stripe.com/payments/checkout/customization.md): Customize the appearance and behavior of the checkout flow. [Collect additional information](https://docs.stripe.com/payments/checkout/collect-additional-info.md): Collect shipping details and other customer information during checkout. [Collect taxes](https://docs.stripe.com/payments/checkout/taxes.md): Collect taxes for one-time payments in Stripe Checkout. [Dynamically update checkout](https://docs.stripe.com/payments/checkout/dynamic-updates.md): Make updates while your customer checks out. [Add trials, discounts, and upsells](https://docs.stripe.com/payments/checkout/promotions.md): Add promotions, such as trials, discounts, and optional items. ## Change when and how you collect payment [Set up subscriptions](https://docs.stripe.com/payments/subscriptions.md): Create a subscription with recurring payments for your customers. [Set up future payments](https://docs.stripe.com/payments/checkout/save-and-reuse.md): Save your customers’ payment details to charge them later. [Save payment details during payment](https://docs.stripe.com/payments/checkout/save-during-payment.md): Accept a payment and save your customer’s payment details for future purchases. [Let customers pay in their local currency](https://docs.stripe.com/payments/currencies/localize-prices/adaptive-pricing.md): Use Adaptive Pricing to allow customers to pay in their local currency. ## Manage your business [Manage your product catalog](https://docs.stripe.com/payments/checkout/product-catalog.md): Handle your inventory and fulfillment with Checkout. [Migrate payment methods to the Dashboard](https://docs.stripe.com/payments/dashboard-payment-methods.md): Migrate the management of your payment methods to the Dashboard. [After the payment](https://docs.stripe.com/payments/checkout/after-the-payment.md): Customize the post-payment checkout process. ## Sample projects [One-time payments](https://github.com/stripe-samples/checkout-one-time-payments) [Subscriptions](https://github.com/stripe-samples/checkout-single-subscription) --- # Source: https://docs.stripe.com/issuing/cards/choose-bundle.md # Choose your physical bundle Set up a standard or custom physical bundle. Stripe helps you set up your physical bundle, which consists of a card, a carrier (the letter sent to cardholders on which the card is affixed), and an envelope. You have different options for both the standard and custom bundles. For [bulk orders](https://docs.stripe.com/issuing/cards/physical/ship-cards.md#bulk-issuance) of multiple cards shipped to a single destination, we don’t include carriers. ## Standard bundle options To get started, go directly to the [Designs](https://dashboard.stripe.com/issuing/personalization-designs) tab in the Issuing Dashboard. We prompt you to create a design by uploading your logo and adding your carrier text. The standard bundle includes the following: - **Card:** A plastic black or white card with your logo (company logo). - **Carrier:** A standard white tri-fold (paper is folded into three) with black text. - **Envelope:** Standard white. You can create multiple standard bundle designs with different logos and carrier text. ![A standard black card and standard white tri-fold carrier](https://b.stripecdn.com/docs-statics-srv/assets/standard-black-card.f0b1c7c22ffb2298509950eba3c90f01.png) A standard black card and standard white tri-fold carrier ![A standard envelope](https://b.stripecdn.com/docs-statics-srv/assets/standard-envelope.4544992b809143229d3f8cc6a6825a5b.png) A standard envelope ## Custom bundle options Before the bundle becomes available in the Issuing Dashboard, we work with you to design it and place a manufacturing order. To get started, contact your account executive and review [Order a custom bundle](https://docs.stripe.com/issuing/cards/physical/order-custom-bundle.md). To learn more about this process, see [Manufacturing and personalizations](https://docs.stripe.com/issuing/cards/choose-bundle.md#manufacturing-personalization). The custom bundle includes the following: - **Card:** Your custom design on a plastic, recycled plastic, or metal card. - **Carrier:** Your custom design on a trifold carrier (paper is folded in three) or bifold carrier (paper is folded in half). You can also pair your custom card with the standard white trifold carrier. - **Envelope:** White non-descript envelope (default) or we can add your logo or brand color on the exterior. Your design is printed during manufacturing, and can’t change after we produce it. However, you can print an additional logo in black or white on the card after manufacturing. ![A custom card and custom tri-fold carrier](https://b.stripecdn.com/docs-statics-srv/assets/custom-card-trifold.f222d5fee8c084b01bdbc6708d986b09.png) A custom card and custom tri-fold carrier ![A custom envelope](https://b.stripecdn.com/docs-statics-srv/assets/custom-envelope.e5c9b33cc8953ec94607630e5a11900c.png) A custom envelope ## Manufacturing and personalization The credit card manufacturing process involves creating a card body, typically made of plastic polyvinyl chloride (PVC), layered for increased durability and security. We embed chips into the card for secure, contactless transactions. The cards then undergo quality control and are shipped in bulk to the personalization site using secure transport. We store your bundle at the site and personalize it when you create cards in the Issuing Dashboard. During personalization, the printer adds unique cardholder information to the bundle, including the cardholder name, number, expiration, and security code to the card. For the carrier, the printer adds the cardholder shipping address. In some cases, the printer can add an additional logo on the card and activation text on the carrier (for standard carriers only) during this stage. To better illustrate the manufacturing and personalization process, see the following diagram. Standard bundles are pre-manufactured and managed by Stripe, allowing you to skip to step 5 and create and name your bundle design. A custom bundle follows all the steps from 1 to 7. ![Manufacturing and personalization](https://b.stripecdn.com/docs-statics-srv/assets/manufacturing-personalization.795103d769b5041160d6c832b9dcf26a.png) Manufacturing and personalization --- # Source: https://docs.stripe.com/issuing/choose-cards.md # Choose which type of card to issue Decide on physical or virtual cards for your cardholders. Stripe offers several options for the types of cards that can be issued to cardholders. This page describes these options at a high level, including tradeoffs and use cases for each. You can issue multiple card types simultaneously for your card program. You can also transition to different options as your business needs change. For example, if you wanted to create a custom card, you could issue an instant physical card while you’re working with the Stripe team to manufacture your custom design. | | [Virtual cards](https://docs.stripe.com/issuing/cards/virtual.md) | [Physical cards](https://docs.stripe.com/issuing/cards/physical.md) | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Overview** | Includes all the card information required for digital transactions, but there’s no physical card. | A customizable card that’s shipped to cardholders. | | **Use cases** | Best for use cases where card transactions are expected to be completely digitized, or where you plan to use your card to complete a backend process, such as: - Third-party logistics (a business is using a third party to fulfill a customer’s order) - B2B payments (a business is paying a supplier for a good or service) - Buy now, pay later payments (a business is paying a merchant) | Best for use cases where you expect to support a high degree of in-person point-of-sale transactions and you don’t want to rely on digital wallets alone, such as: - Fleet purchases - Contractor purchases - Expense management | | **Customization** | Not applicable for virtual cards. | Issue [standard](https://docs.stripe.com/issuing/cards/physical.md#standard-card) or [custom](https://docs.stripe.com/issuing/cards/physical.md#custom-card) physical cards. | | **Creating cards** | Create a [virtual card](https://docs.stripe.com/issuing/cards/virtual/issue-cards.md) using the Dashboard or the Cards API. | Create a [physical card](https://docs.stripe.com/issuing/cards/physical/issue-cards.md) using the Dashboard or the Cards API. | | **Cost** | Virtual cards are 0.10 USD each in the US, 0.10 GBP in the UK and 0,10 EUR in the EU. | Standard cards are 3.50 USD each in the US, 3.50 GBP in the UK, and 3,50 EUR in the EU. Shipping costs apply for each region. Custom card prices depend on the level of customization of your card design. See [Stripe Support](https://support.stripe.com/topics/issuing) for more details. | --- # Source: https://docs.stripe.com/payments/checkout/client.md # One-time payments with Checkout Learn how to accept one-time card payments with just a few lines of code. > The client-only integration of Checkout isn’t actively maintained and doesn’t support many of the features available with the [client and server integration](https://docs.stripe.com/payments/accept-a-payment.md?integration=checkout). We recommend using [Payment Links](https://docs.stripe.com/payment-links.md) for a no-code workflow. Check out the [donations](https://github.com/stripe-samples/github-pages-stripe-checkout) sample on GitHub or try the [hosted version](https://stripe-samples.github.io/github-pages-stripe-checkout/). With the client-only integration, you define your products directly in the Stripe Dashboard and reference them by ID on the client side. This approach makes it possible to integrate Checkout into your website without any server-side code. ## Enable Checkout [Dashboard] To begin using Checkout, log into the Stripe Dashboard and go to the [Checkout settings](https://dashboard.stripe.com/settings/checkout). From here you can enable the client-only integration and customize the look and feel of your checkout page. ![](https://b.stripecdn.com/docs-statics-srv/assets/checkout-disabled.ec8f13a264bf2e39b83378dd40e547e0.png) ## Create products and prices To use Checkout, you first need to create a *Product* (Products represent what your business sells—whether that's a good or a service) and a *Price* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions). Different physical goods or levels of service should be represented by products. Each product’s pricing is represented by one or more prices. For example, you can create a T-shirt *product* that has 2 *prices* for different currencies: 20 USD and 15 EUR. This allows you to change and add prices without needing to change the details of your underlying products. You can either create a product and price [through the API](https://docs.stripe.com/api/prices.md) or through [the Stripe Dashboard](https://dashboard.stripe.com/products). > If you have an existing Checkout integration that doesn’t use Prices, note that the Checkout API has changed since Prices was introduced. You can use this [migration guide](https://docs.stripe.com/payments/checkout/migrating-prices.md) to upgrade, or [keep your existing integration](https://support.stripe.com/questions/prices-api-and-existing-checkout-integrations). #### Dashboard > Products created in a sandbox can be copied to live mode so that you don’t need to re-create them. In the Product detail view in the Dashboard, click **Copy to live mode** in the upper right corner. You can only do this once for each product created in a sandbox. Subsequent updates to the test product are not reflected for the live product. Make sure you’re in a sandbox, and define the items you want to sell. To create a new product and price: - Go to the [Products](https://dashboard.stripe.com/test/products) section in the Dashboard - Click **Add product** - Select **One time** when setting the price The product name, description, and image that you supply are displayed to customers in Checkout. #### API To create a [Product](https://docs.stripe.com/api/products.md) with the API, only a `name` is required. The product `name`, `description`, and `images` that you supply are displayed to customers on Checkout. ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ -d name=T-shirt ``` ```cli stripe products create \ --name=T-shirt ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") product = client.v1.products.create({name: 'T-shirt'}) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. product = client.v1.products.create({"name": "T-shirt"}) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $product = $stripe->products->create(['name' => 'T-shirt']); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); ProductCreateParams params = ProductCreateParams.builder().setName("T-shirt").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Product product = client.v1().products().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const product = await stripe.products.create({ name: 'T-shirt', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.ProductCreateParams{Name: stripe.String("T-shirt")} result, err := sc.V1Products.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new ProductCreateOptions { Name = "T-shirt" }; var client = new StripeClient("<>"); var service = client.V1.Products; Product product = service.Create(options); ``` Next, create a [Price](https://docs.stripe.com/api/prices.md) to define how much to charge for your product. This includes how much the product costs and what currency to use. ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product="{{PRODUCT_ID}}" \ -d unit_amount=2000 \ -d currency=usd ``` ```cli stripe prices create \ --product="{{PRODUCT_ID}}" \ --unit-amount=2000 \ --currency=usd ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") price = client.v1.prices.create({ product: '{{PRODUCT_ID}}', unit_amount: 2000, currency: 'usd', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. price = client.v1.prices.create({ "product": "{{PRODUCT_ID}}", "unit_amount": 2000, "currency": "usd", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $price = $stripe->prices->create([ 'product' => '{{PRODUCT_ID}}', 'unit_amount' => 2000, 'currency' => 'usd', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PriceCreateParams params = PriceCreateParams.builder() .setProduct("{{PRODUCT_ID}}") .setUnitAmount(2000L) .setCurrency("usd") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Price price = client.v1().prices().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const price = await stripe.prices.create({ product: '{{PRODUCT_ID}}', unit_amount: 2000, currency: 'usd', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PriceCreateParams{ Product: stripe.String("{{PRODUCT_ID}}"), UnitAmount: stripe.Int64(2000), Currency: stripe.String(stripe.CurrencyUSD), } result, err := sc.V1Prices.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PriceCreateOptions { Product = "{{PRODUCT_ID}}", UnitAmount = 2000, Currency = "usd", }; var client = new StripeClient("<>"); var service = client.V1.Prices; Price price = service.Create(options); ``` ## Redirect to Checkout [Dashboard] [Client-side] To use Checkout on your website, you must add a snippet of code that includes the desired price. You can use the Dashboard to generate the necessary code, or you can write it yourself. #### Dashboard In the [Products section](https://dashboard.stripe.com/products) of the Dashboard, select the product that you want to sell. ![](https://b.stripecdn.com/docs-statics-srv/assets/price-listing.ae7c9fe11492c36509feb1e6b2364228.png) In the product detail view, click the **Get Checkout code snippet** selection in the overflow menu next to a price to generate a code snippet that you can add to your website. ![](https://b.stripecdn.com/docs-statics-srv/assets/snippet-generator.de62343b5dc9ef77465daf373f6cba9f.png) Copy and paste the snippet into the body of a web page. The snippet adds a button to the page that, when clicked, redirects the customer to Checkout. You can include multiple checkout buttons on the same page. When your customer successfully completes their payment, they’re redirected to the success URL that you specified when configuring the code snippet. Typically, this is a page on your website that informs the customer that their payment succeeded. When your customer clicks on your logo in a Checkout session without completing a payment, Checkout redirects them back to your website by navigating to the cancel URL you specified when configuring the code snippet. Typically, this is the page on your website that the customer viewed prior to redirecting to Checkout. Before going live, make sure to [configure your domains list](https://dashboard.stripe.com/account/checkout/settings) in the Dashboard to match the success and cancel URLs. #### HTML + JS Checkout relies on [Stripe.js](https://docs.stripe.com/payments/elements.md). To get started, include the following script tag on your website—always load it directly from **https://js.stripe.com**: ```javascript npm install @stripe/stripe-js ``` Next, create an instance of the [Stripe object](https://docs.stripe.com/js.md#stripe-function) by providing your publishable [API key](https://docs.stripe.com/keys.md) as the first parameter: ```javascript import {loadStripe} from '@stripe/stripe-js'; const stripe = await loadStripe('<>'); ``` When your customer is ready to pay, call [redirectToCheckout](https://docs.stripe.com/js.md#stripe-redirect-to-checkout) to begin the checkout process. Pass it an array of objects that specify the price ID and the quantity of each item that the customer wishes to purchase: ```javascript const {error} = await stripe.redirectToCheckout({ lineItems: [{ price: '{{PRICE_ID}}', // Replace with the ID of your price quantity: 1, }], mode: 'payment', successUrl: 'https://example.com/success', }) // If `redirectToCheckout` fails due to a browser or network // error, display the localized error message to your customer // using `error.message`. ``` When your customer successfully completes their payment, they’re redirected to the success URL. Typically, this is a page on your website that informs the customer that their payment succeeded. When your customer clicks on your logo in a Checkout Session without completing a payment, they’re redirected to the cancel URL. Typically, this is the page on your website the customer viewed prior to redirecting to Checkout. Before going live, make sure to [configure your domains list](https://dashboard.stripe.com/account/checkout/settings) in the Dashboard to match the success and cancel URLs. #### React Install the Stripe.js module. Always load Stripe.js directly from **https://js.stripe.com**. You can’t include it in a bundle or host it yourself. ```npm npm install @stripe/stripe-js ``` ### Add Stripe.js to your page Call `loadStripe` with your publishable key. It returns a `Promise` that resolves with the `Stripe` object after Stripe.js loads. When the customer clicks the checkout button, call [redirectToCheckout](https://docs.stripe.com/js.md#stripe-redirect-to-checkout) to begin the payment process. Pass it an array of objects containing the price ID, quantity, a success URL, and a cancel URL. ```jsx import React from 'react'; import ReactDOM from 'react-dom'; import { loadStripe } from '@stripe/stripe-js'; // Make sure to call `loadStripe` outside of a component’s render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe('<>'); function App() { const handleClick = async (event) => { // When the customer clicks on the button, redirect them to Checkout. const stripe = await stripePromise; const { error } = await stripe.redirectToCheckout({ lineItems: [{ price: '{{PRICE_ID}}', // Replace with the ID of your price quantity: 1, }], mode: 'payment', successUrl: 'https://example.com/success', }); // If `redirectToCheckout` fails due to a browser or network // error, display the localized error message to your customer // using `error.message`. }; return ( ); } ReactDOM.render(, document.getElementById('root')); ``` When your customer successfully completes their payment, they’re redirected to the success URL. Typically, this is a page on your website that informs the customer that their payment succeeded. When your customer clicks on your logo in a Checkout Session without completing a payment, they’re redirected to the cancel URL. Typically, this is the page on your website the customer viewed prior to redirecting to Checkout. > Don’t rely on the redirect to the `success_url` alone for detecting payment initiation, as: > > - Malicious users could directly access the `success_url` without paying and gain access to your goods or services. - Customers may not always reach the `success_url` after a successful payment—they might close their browser tab before the redirect occurs. ## Confirm the payment is successful When your customer completes a payment, they’re redirected to the URL that you specified as the `success_url`. This is typically a page on your website that informs your customer that their payment was successful. Use the Dashboard, a custom *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests), or a third-party plugin to handle post-payment events like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow. #### Dashboard Successful payments appear in the Dashboard’s [list of payments](https://dashboard.stripe.com/payments). When you click a payment, it takes you to the Payment details page. The **Checkout summary** section contains billing information and the list of items purchased, which you can use to manually fulfill the order. ![Checkout summary](https://b.stripecdn.com/docs-statics-srv/assets/source.16d3029596357c80a8efdbbfe106108a.png) > Stripe can help you keep up with incoming payments by sending you email notifications whenever a customer successfully completes one. Use the Dashboard to [configure email notifications](https://dashboard.stripe.com/settings/user). #### Webhooks [Set up webhooks](https://docs.stripe.com/webhooks.md) to programmatically handle post-payment events. The quickest way to develop and test webhooks locally is with the [Stripe CLI](https://docs.stripe.com/stripe-cli.md). Once you have it installed, you can forward events to your server: ```bash stripe listen --forward-to localhost:4242/webhook Ready! Your webhook signing secret is '{{WEBHOOK_SIGNING_SECRET}}' (^C to quit) ``` With a webhook endpoint, your customer is redirected to the `success_url` when you [acknowledged you received the event](https://docs.stripe.com/webhooks.md#acknowledge-events-immediately). In scenarios where your endpoint is down or the event isn’t acknowledged properly, your customer is redirected to the `success_url` 10 seconds after a successful payment. The following example endpoint demonstrates how to acknowledge and handle events. #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' # You can find your endpoint's secret in your webhook settings endpoint_secret = 'whsec_...' # Using Sinatra post '/webhook' do payload = request.body.read event = nil # Verify webhook signature and extract the event # See https://stripe.com/docs/webhooks#verify-events for more information. sig_header = request.env['HTTP_STRIPE_SIGNATURE'] begin event = Stripe::Webhook.construct_event( payload, sig_header, endpoint_secret ) rescue JSON::ParserError => e # Invalid payload status 400 return rescue Stripe::SignatureVerificationError => e # Invalid signature status 400 return end # Handle the checkout.session.completed event if event['type'] == 'checkout.session.completed' session = event['data']['object'] # Fulfill the purchase... handle_checkout_session(session) end status 200 end ``` #### Python ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' # Using Django from django.http import HttpResponse # You can find your endpoint's secret in your webhook settings endpoint_secret = 'whsec_...' @csrf_exempt def my_webhook_view(request): payload = request.body sig_header = request.META['HTTP_STRIPE_SIGNATURE'] event = None try: event = stripe.Webhook.construct_event( payload, sig_header, endpoint_secret ) except ValueError as e: # Invalid payload return HttpResponse(status=400) except stripe.error.SignatureVerificationError as e: # Invalid signature return HttpResponse(status=400) # Handle the checkout.session.completed event if event['type'] == 'checkout.session.completed': session = event['data']['object'] # Fulfill the purchase... handle_checkout_session(session) return HttpResponse(status=200) ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('<>'); // You can find your endpoint's secret in your webhook settings $endpoint_secret = 'whsec_...'; $payload = @file_get_contents('php://input'); $sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE']; $event = null; try { $event = \Stripe\Webhook::constructEvent( $payload, $sig_header, $endpoint_secret ); } catch(\UnexpectedValueException $e) { // Invalid payload http_response_code(400); exit(); } catch(\Stripe\Exception\SignatureVerificationException $e) { // Invalid signature http_response_code(400); exit(); } // Handle the checkout.session.completed event if ($event->type == 'checkout.session.completed') { $session = $event->data->object; // Fulfill the purchase... handle_checkout_session($session); } http_response_code(200); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; // You can find your endpoint's secret in your webhook settings String endpointSecret = "whsec_..."; // Using the Spark framework public Object handle(Request request, Response response) { String payload = request.body(); String sigHeader = request.headers("Stripe-Signature"); Event event = null; try { event = Webhook.constructEvent( payload, sigHeader, endpointSecret ); } catch (JsonSyntaxException e) { // Invalid payload response.status(400); return ""; } catch (SignatureVerificationException e) { // Invalid signature response.status(400); return ""; } // Handle the checkout.session.completed event if ("checkout.session.completed".equals(event.getType())) { Session session = (Session) event.getDataObjectDeserializer().getObject(); // Fulfill the purchase... handleCheckoutSession(session); } response.status(200); return ""; } ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); // Find your endpoint's secret in your Dashboard's webhook settings const endpointSecret = 'whsec_...'; // Using Express const app = require('express')(); // Use body-parser to retrieve the raw body as a buffer const bodyParser = require('body-parser'); // Match the raw body to content type application/json app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => { const sig = request.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret); } catch (err) { return response.status(400).send(`Webhook Error: ${err.message}`); } // Handle the checkout.session.completed event if (event.type === 'checkout.session.completed') { const session = event.data.object; // Fulfill the purchase... handleCheckoutSession(session); } // Return a response to acknowledge receipt of the event response.json({received: true}); }); app.listen(8000, () => console.log('Running on port 8000')); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" http.HandleFunc("/webhook", func(w http.ResponseWriter, req *http.Request) { const MaxBodyBytes = int64(65536) req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes) body, err := ioutil.ReadAll(req.Body) if err != nil { fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err) w.WriteHeader(http.StatusServiceUnavailable) return } // Pass the request body & Stripe-Signature header to ConstructEvent, along with the webhook signing key // You can find your endpoint's secret in your webhook settings endpointSecret := "whsec_..."; event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), endpointSecret) if err != nil { fmt.Fprintf(os.Stderr, "Error verifying webhook signature: %v\n", err) w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature return } // Handle the checkout.session.completed event if event.Type == "checkout.session.completed" { var session stripe.CheckoutSession err := json.Unmarshal(event.Data.Raw, &session) if err != nil { fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err) w.WriteHeader(http.StatusBadRequest) return } // Fulfill the purchase... handleCheckoutSession(session) } w.WriteHeader(http.StatusOK) }) ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; using System; using System.IO; using Microsoft.AspNetCore.Mvc; using Stripe; using System.Threading.Tasks; namespace workspace.Controllers { [Route("api/[controller]")] public class StripeWebHook : Controller { // You can find your endpoint's secret in your webhook settings const string secret = "whsec_..."; [HttpPost] public async Task Index() { var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync(); try { var stripeEvent = EventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"], secret); // Handle the checkout.session.completed event // If on SDK version < 46, use class Events instead of EventTypes if (stripeEvent.Type == EventTypes.CheckoutSessionCompleted) { var session = stripeEvent.Data.Object as Checkout.Session; // Fulfill the purchase... HandleCheckoutSession(session); } else { return Ok(); } } catch (StripeException e) { return BadRequest(); } } } } ``` You can use plugins like [Zapier](https://stripe.com/works-with/zapier) to automate updating your purchase fulfillment systems with information from Stripe payments. Some examples of automation supported by plugins include: - Updating spreadsheets used for order tracking in response to successful payments - Updating inventory management systems in response to successful payments - Triggering notifications to internal customer service teams using email or chat applications ## Test the integration There are several test cards you can use to make sure your integration is ready for production. Use them with any CVC, postal code, and future expiration date. | Number | Description | | ---------------- | ---------------------------------------------------------------------- | | 4242424242424242 | Succeeds and immediately processes the payment. | | 4000000000003220 | 3D Secure 2 authentication must be completed for a successful payment. | | 4000000000009995 | Always fails with a decline code of `insufficient_funds`. | For the full list of test cards see our guide on [testing](https://docs.stripe.com/testing.md). ### Apple Pay and Google Pay No configuration or integration changes are required to enable Apple Pay or Google Pay in Stripe Checkout. These payments are handled the same way as other card payments. #### Apple Pay The Apple Pay button is displayed in a given Checkout Session if all of the following apply: - Apple Pay is enabled for Checkout in your [Stripe Dashboard](https://dashboard.stripe.com/settings/checkout). - The customer’s device is running macOS 10.14.1+ or iOS 12.1+. - The customer is using the Safari browser. - The customer has a valid card registered with Apple Pay. This ensures that Checkout only displays the Apple Pay button to customers who are able to use it. #### Google Pay The Google Pay button is displayed in a given Checkout Session if all of the following apply: - Google Pay is enabled for Checkout in your [Stripe Dashboard](https://dashboard.stripe.com/settings/checkout). - The customer is using Google Chrome or Safari. - The customer has a valid card registered with Google Pay. This ensures that Checkout only displays the Google Pay button to customers who are able to use it. ## Optional: Collect a billing address [Client-side] You can specify whether Checkout collects the customer’s billing address by setting `billingAddressCollection` in the `redirectToCheckout` call. If set to `required`, Checkout always collects the customer’s billing address. If not set or set to `auto`, Checkout only collects the billing address when necessary. ```javascript const {error} = await stripe.redirectToCheckout({ lineItems: [ // Replace with the ID of your price {price: '{PRICE_ID}', quantity: 1}, ], mode: 'payment', successUrl: 'https://example.com/success',billingAddressCollection: 'required', }); // If `redirectToCheckout` fails due to a browser or network // error, display the localized error message to your customer // using `error.message`. ``` ## Optional: Collect a shipping address [Client-side] You can collect a customer’s shipping address in Checkout by setting `shippingAddressCollection` in the `redirectToCheckout` call. You must also specify which countries you ship to by configuring the `allowedCountries` property with an array of [two-letter ISO country codes](https://www.nationsonline.org/oneworld/country_code_list.htm). These countries appear in the Country dropdown in the shipping address form on Checkout. The collected shipping address is saved to the Checkout Session object on the `shipping` property when the session has been completed by the customer and is included in the payload of the `checkout.session.completed` *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests). Additionally, shipping information appears in the **Checkout summary** section of your payments details page in the Dashboard. > Shipping country options are specified client-side, so be sure to validate that addresses are from your expected countries during *fulfillment* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected). If you require stricter validation up front, use the [client & server integration](https://docs.stripe.com/payments/accept-a-payment.md?integration=checkout). ```javascript const {error} = await stripe.redirectToCheckout({ lineItems: [ // Replace with the ID of your price {price: '{PRICE_ID}', quantity: 1}, ], mode: 'payment', successUrl: 'https://example.com/success',shippingAddressCollection: { allowedCountries: ['US', 'CA'], } }); // If `redirectToCheckout` fails due to a browser or network // error, display the localized error message to your customer // using `error.message`. ``` ## Optional: Customize the Checkout button [Client-side] You can configure the copy displayed on the Checkout button to better align with your business model. Provide a `submitType` in the `redirectToCheckout` call: ```javascript const {error} = await stripe.redirectToCheckout({ lineItems: [ // Replace with the ID of your price {price: '{PRICE_ID}', quantity: 1} ], mode: 'payment', successUrl: 'https://example.com/success',submitType: 'donate', }) // If `redirectToCheckout` fails due to a browser or network // error, display the localized error message to your customer // using `error.message`. ``` In this example (for a 5 USD donation), your customized Checkout submit button would read **Donate $5.00**. See the [Stripe.js Reference](https://docs.stripe.com/js.md#stripe-redirect-to-checkout) for a complete list of `submitType` options. ## Optional: Prefill customer email [Client-side] You may already have collected information about your customer that you want to prefill in the Checkout page to avoid your customers needing to enter information twice. Currently, you can prefill the customer email on the Checkout page by providing `customerEmail` in the [redirectToCheckout](https://docs.stripe.com/js.md#stripe-redirect-to-checkout) call. ```javascript const {error} = await stripe.redirectToCheckout({ lineItems: [ // Replace with the ID of your price {price: '{PRICE_ID}', quantity: 1} ], mode: 'payment', successUrl: 'https://example.com/success',customerEmail: 'customer@example.com', }) // If `redirectToCheckout` fails due to a browser or network // error, display the localized error message to your customer // using `error.message`. ``` > Stripe creates a new *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) object when the Checkout Session completes successfully. Passing the email address of a returning customer results in the creation of a new Customer object with a duplicate email address. Consider using the [client & server integration](https://docs.stripe.com/payments/accept-a-payment.md?integration=checkout) if you want to reuse existing Customer objects. --- # Source: https://docs.stripe.com/declines/codes.md # Stripe decline codes Learn about Stripe decline codes and how to resolve them when a charge fails. Stripe uses its own decline codes that cover many of the same potential reasons as [issuer decline codes](https://docs.stripe.com/declines/network-codes.md). Our decline codes expand on issuer decline codes by going into more detail about the specific reason for the decline. In addition to a decline code, an error can contain an [advice_code](https://docs.stripe.com/declines/card.md#retrying-issuer-declines) with suggested next steps. > #### Other API errors > > Some [API errors](https://docs.stripe.com/api/errors.md) include a [code](https://docs.stripe.com/api/errors.md#errors-code) attribute to help you [resolve them](https://docs.stripe.com/error-handling.md). ## Card decline codes These are the Stripe decline codes that are used for card payments: | Decline code | Description | Next steps | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `authentication_required` | The card was declined because the transaction requires authentication such as *3D Secure* (3D Secure (3DS) provides an additional layer of authentication for credit card transactions that protects businesses from liability for fraudulent card payments). | When using Stripe’s front ends, in most cases a soft decline from an issuer triggers an authentication flow, allowing the customer to try again and authenticate their card. In some cases, such as *off-session payments* (A payment is described as off-session if it occurs without the direct involvement of the customer, using previously-collected payment information), you might need to request the customer to retry. If the card issuer returns this [decline code](https://support.stripe.com/questions/authenticated-payment-declined-with-an-authentication-required-decline-code) despite a successfully authenticated transaction, the customer needs to contact their card issuer for more information. | | `authentication_not_handled` | Related to `authentication_required`. You tried to proceed without performing the required authentication, so the issuer declined again. | Run the EMV 3D Secure (3DS) or strong customer authentication (SCA) flow. For off-session payments, collect and prepare authentication on-session first, then fall back to on-session if needed. | | `approve_with_id` | The payment can’t be authorized. | Attempt the payment again. If you still can’t process it, the customer needs to contact their card issuer. | | `call_issuer` | The card was declined for an unknown reason. | The customer needs to contact their card issuer for more information. | | `card_not_supported` | The card doesn’t support this type of purchase. | The customer needs to contact their card issuer to make sure their card can be used to make this type of purchase. | | `card_velocity_exceeded` | The customer has exceeded the balance, credit limit, or transaction amount limit available on their card. | The customer needs to contact their card issuer for more information. | | `currency_not_supported` | The card doesn’t support the specified currency. | The customer needs to check with the issuer whether the card can be used for the type of currency specified. | | `do_not_honor` | The card was declined for an unknown reason. | The customer needs to contact their card issuer for more information. | | (deprecated)`do_not_try_again` | The card was declined for an unknown reason. | The customer needs to contact their card issuer for more information. | | `duplicate_transaction` | A transaction with identical amount and credit card information was submitted very recently. | Check to see if a recent payment already exists. | | `expired_card` | The card has expired. | The customer needs to use another card. | | `fraudulent` | The payment was declined because Stripe suspects that it’s fraudulent. | Don’t report more detailed information to your customer. Instead, present it in the same manner as `generic_decline` below. | | `generic_decline` | The card was declined for an unknown reason or Stripe Radar or Adaptive Acceptance [blocked the payment](https://docs.stripe.com/declines.md#blocked-payments). | The customer needs to contact their card issuer for more information. | | `incorrect_address` | The address entered by the customer is incorrect. | The customer needs to try again using the correct address. | | `incorrect_cvc` | The CVC number is incorrect. | The customer needs to try again using the correct CVC. | | `incorrect_number` | The card number is incorrect. | The customer needs to try again using the correct card number. | | `incorrect_pin` | The PIN entered is incorrect. This decline code only applies to payments made with a card reader. | The customer needs to try again using the correct PIN. | | `incorrect_zip` | The postal code is incorrect. | The customer needs to try again using the correct billing postal code. | | `insufficient_funds` | The card has insufficient funds to complete the purchase. | The customer needs to use an alternative payment method. | | `invalid_account` | The card, or account the card is connected to, is invalid. | The customer needs to contact their card issuer to check that the card is working correctly. | | `invalid_amount` | The payment amount is invalid, or exceeds the amount that’s allowed. | If the amount appears to be correct, the customer needs to check with their card issuer that they can make purchases of that amount. | | `invalid_cvc` | The CVC number is incorrect. | The customer needs to try again using the correct CVC. | | `invalid_expiry_month` | The expiration month is invalid. | The customer needs to try again using the correct expiration date. | | `invalid_expiry_year` | The expiration year is invalid. | The customer needs try again using the correct expiration date. | | `invalid_number` | The card number is incorrect. | The customer needs try again using the correct card number. | | `invalid_pin` | The PIN entered is incorrect. | The customer needs to try again using the correct PIN. | | `issuer_not_available` | The card issuer couldn’t be reached, so the payment couldn’t be authorized. | Attempt the payment again. If you still can’t process it, the customer needs to contact their card issuer. | | `lost_card` | The payment was declined because the card is reported lost. | The specific reason for the decline shouldn’t be reported to the customer. Instead, present it as a `generic_decline`. | | `merchant_blacklist` | The payment was declined because it matches a value on the Stripe user’s block list. | Don’t report more detailed information to your customer. Instead, present it in the same manner as `generic_decline` below. | | `new_account_information_available` | The card, or account the card is connected to, is invalid. | The customer needs to contact their card issuer for more information. | | `no_action_taken` | The card was declined for an unknown reason. | The customer needs to contact their card issuer for more information. | | `not_permitted` | The payment isn’t permitted. | The customer needs to contact their card issuer for more information. | | `offline_pin_required` | The card was declined because it requires a PIN. | The customer needs to try again by inserting their card and entering a PIN. | | `online_or_offline_pin_required` | The card was declined as it requires a PIN. | If the card reader supports Online PIN, prompt the customer for a PIN without creating a new transaction. If the card reader doesn’t support Online PIN, the customer needs to try again by inserting their card and entering a PIN. | | `pickup_card` | The customer can’t use this card to make this payment (it’s possible it was reported lost or stolen). | They need to contact their card issuer for more information. | | `pin_try_exceeded` | The allowable number of PIN tries was exceeded. | The customer must use another card or method of payment. | | `processing_error` | An error occurred while processing the card. | The payment needs to be attempted again. If it still can’t be processed, try again later. | | `reenter_transaction` | The payment couldn’t be processed by the issuer for an unknown reason. | The payment needs to be attempted again. If it still can’t be processed, the customer needs to contact their card issuer. | | `restricted_card` | The customer can’t use this card to make this payment (it’s possible it was reported lost or stolen). | The customer needs to contact their card issuer for more information. | | `revocation_of_all_authorizations` | The card was declined for an unknown reason. | The customer needs to contact their card issuer for more information. | | `revocation_of_authorization` | The card was declined for an unknown reason. | The customer needs to contact their card issuer for more information. | | `security_violation` | The card was declined for an unknown reason. | The customer needs to contact their card issuer for more information. | | `service_not_allowed` | The card was declined for an unknown reason. | The customer needs to contact their card issuer for more information. | | `stolen_card` | The payment was declined because the card is reported stolen. | Don’t report more detailed information to your customer. Instead, present it in the same manner as `generic_decline` below. | | `stop_payment_order` | The card was declined for an unknown reason. | The customer needs to contact their card issuer for more information. | | `testmode_decline` | A Stripe test card number was used. | A genuine card must be used to make a payment. | | `transaction_not_allowed` | The card was declined for an unknown reason. | The customer needs to contact their card issuer for more information. | | (deprecated)`try_again_later` | The card was declined for an unknown reason. | Ask the customer to attempt the payment again. If subsequent payments are declined, the customer needs to contact their card issuer for more information. | | `withdrawal_count_limit_exceeded` | The customer has exceeded the balance or credit limit available on their card. | The customer needs to use an alternative payment method. | | `mobile_device_authentication_required` | The card was declined because the transaction requires authentication. | Retry attempts by tapping your mobile device again. | ## Local payment method decline codes The following Stripe decline codes can be used for Local Payment Method (LPM) payments: | Decline code | Charge outcome reason | Seller message | API error message | | ----------------------------- | ------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `partner_generic_decline` | `partner_generic_decline` | The payment provider has declined the payment. | The payment provider has declined the payment. | | `invalid_customer_account` | `invalid_customer_account` | We can’t charge the customer’s account. | We can’t charge the customer’s account. Retry attempts might succeed after the customer takes action to resolve the issue with their account. | | `payment_limit_exceeded` | `payment_limit_exceeded` | The order exceeds a limit on the customer’s account. | The order exceeds a limit on the customer’s account. Retry attempts might succeed after the customer takes action to resolve the issue with their account. | | `invalid_billing_agreement` | `invalid_billing_agreement` | The customer’s billing agreement is invalid. | The customer’s payment method is invalid due to an invalid billing agreement. Retries won’t succeed. | | `expired_card` | `partner_expired_card` | The card registered with the payment provider has expired. | The card registered with the payment provider has expired. Retry attempts might succeed after the customer takes action to resolve the issue with their account. | | `processing_error` | `partner_processing_error` | The payment provider encountered a processing error. | The payment provider encountered a processing error. | | `insufficient_funds` | `partner_insufficient_funds` | The customer has insufficient funds with the payment provider. | The customer has insufficient funds with the payment provider. Retry attempts might succeed after the customer takes action to resolve the issue with their account. | | `currency_not_supported` | `partner_invalid_currency` | The payment provider doesn’t support this currency. | The payment provider doesn’t support this currency. Retries won’t succeed. | | `invalid_amount` | `partner_invalid_amount` | The payment provider doesn’t allow the amount. | The payment provider doesn’t allow the amount. Retries won’t succeed. | | `invalid_business_account` | `invalid_business_account` | The business account is deactivated. | The business account you’re trying to use for processing a payment or issuing a refund is deactivated and incapable of sending or receiving funds. If the account is reactivated, retry attempts might succeed. | | `partner_high_risk_customer` | `partner_high_risk_customer` | The payment provider labeled this customer as high risk. | The payment provider labeled this customer as high risk. | | `compliance_violation` | `compliance_violation` | The payment violates terms of service, program rules, or applicable laws. | The payment violates terms of service, program rules, or applicable laws. Retries won’t succeed. | | `payment_disputed` | `payment_disputed` | There’s a dispute over the payment. | There’s a dispute over the payment. If the dispute resolves in favor of the business, retry attempts might succeed. | | `invalid_authorization` | `invalid_authorization` | The authorization is invalid or has been revoked. | The payment didn’t receive authorization or has revoked its authorization. Retries won’t succeed. | | `invalid_payment_information` | `invalid_payment_information` | The payment has invalid information. | The payment has invalid information. Retries won’t succeed. | | `partner_payment_not_found` | `partner_payment_not_found` | The payment provider can’t find this payment. | The payment provider can’t find this payment. | | `expired_payment_information` | `expired_payment_information` | The underlying payment instrument is expired. | The payment has expired information. Retries may succeed after the customer updates their payment information. | | `duplicate_transaction` | `partner_duplicate_transaction` | A recent transaction with identical details was submitted recently. | A recent transaction with identical details was submitted recently to the partner. | --- # Source: https://docs.stripe.com/payments/no-code/collect-addresses.md # Source: https://docs.stripe.com/payments/mobile/collect-addresses.md # Source: https://docs.stripe.com/payments/advanced/collect-addresses.md # Source: https://docs.stripe.com/payments/collect-addresses.md # Collect physical addresses Learn how to collect billing and shipping addresses. When you use a Stripe-hosted payment page or embedded payment form, you can collect billing and shipping addresses. ## Collect a billing address By default, a Checkout Session only collects a customer’s billing address when necessary (for example, to calculate tax). To always collect a billing address, set `billing_address_collection` to `required` when you [create a Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md). #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d billing_address_collection=required \ -d "automatic_tax[enabled]"=true \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" ``` ```cli stripe checkout sessions create \ --billing-address-collection=required \ -d "automatic_tax[enabled]"=true \ --mode=payment \ --success-url="https://example.com/success" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ billing_address_collection: 'required', automatic_tax: {enabled: true}, mode: 'payment', success_url: 'https://example.com/success', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "billing_address_collection": "required", "automatic_tax": {"enabled": True}, "mode": "payment", "success_url": "https://example.com/success", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'billing_address_collection' => 'required', 'automatic_tax' => ['enabled' => true], 'mode' => 'payment', 'success_url' => 'https://example.com/success', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setBillingAddressCollection(SessionCreateParams.BillingAddressCollection.REQUIRED) .setAutomaticTax(SessionCreateParams.AutomaticTax.builder().setEnabled(true).build()) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ billing_address_collection: 'required', automatic_tax: { enabled: true, }, mode: 'payment', success_url: 'https://example.com/success', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ BillingAddressCollection: stripe.String(stripe.CheckoutSessionBillingAddressCollectionRequired), AutomaticTax: &stripe.CheckoutSessionCreateAutomaticTaxParams{ Enabled: stripe.Bool(true), }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { BillingAddressCollection = "required", AutomaticTax = new Stripe.Checkout.SessionAutomaticTaxOptions { Enabled = true }, Mode = "payment", SuccessUrl = "https://example.com/success", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d billing_address_collection=required \ -d "automatic_tax[enabled]"=true \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" ``` ```cli stripe checkout sessions create \ --billing-address-collection=required \ -d "automatic_tax[enabled]"=true \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ billing_address_collection: 'required', automatic_tax: {enabled: true}, mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "billing_address_collection": "required", "automatic_tax": {"enabled": True}, "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'billing_address_collection' => 'required', 'automatic_tax' => ['enabled' => true], 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setBillingAddressCollection(SessionCreateParams.BillingAddressCollection.REQUIRED) .setAutomaticTax(SessionCreateParams.AutomaticTax.builder().setEnabled(true).build()) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ billing_address_collection: 'required', automatic_tax: { enabled: true, }, mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ BillingAddressCollection: stripe.String(stripe.CheckoutSessionBillingAddressCollectionRequired), AutomaticTax: &stripe.CheckoutSessionCreateAutomaticTaxParams{ Enabled: stripe.Bool(true), }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { BillingAddressCollection = "required", AutomaticTax = new Stripe.Checkout.SessionAutomaticTaxOptions { Enabled = true }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Collect a shipping address To collect a customer’s shipping address in Checkout, pass the `shipping_address_collection` parameter when you [create a Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md). When you collect a shipping address, you must also specify which countries to allow shipping to. Configure the `allowed_countries` property with an array of [two-letter ISO country codes](https://www.nationsonline.org/oneworld/country_code_list.htm). #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d billing_address_collection=required \ -d "shipping_address_collection[allowed_countries][]"=US \ -d "shipping_address_collection[allowed_countries][]"=CA \ -d "automatic_tax[enabled]"=true \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" ``` ```cli stripe checkout sessions create \ --billing-address-collection=required \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_address_collection[allowed_countries][1]"=CA \ -d "automatic_tax[enabled]"=true \ --mode=payment \ --success-url="https://example.com/success" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ billing_address_collection: 'required', shipping_address_collection: {allowed_countries: ['US', 'CA']}, automatic_tax: {enabled: true}, mode: 'payment', success_url: 'https://example.com/success', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "billing_address_collection": "required", "shipping_address_collection": {"allowed_countries": ["US", "CA"]}, "automatic_tax": {"enabled": True}, "mode": "payment", "success_url": "https://example.com/success", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'billing_address_collection' => 'required', 'shipping_address_collection' => ['allowed_countries' => ['US', 'CA']], 'automatic_tax' => ['enabled' => true], 'mode' => 'payment', 'success_url' => 'https://example.com/success', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setBillingAddressCollection(SessionCreateParams.BillingAddressCollection.REQUIRED) .setShippingAddressCollection( SessionCreateParams.ShippingAddressCollection.builder() .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.US ) .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.CA ) .build() ) .setAutomaticTax(SessionCreateParams.AutomaticTax.builder().setEnabled(true).build()) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ billing_address_collection: 'required', shipping_address_collection: { allowed_countries: ['US', 'CA'], }, automatic_tax: { enabled: true, }, mode: 'payment', success_url: 'https://example.com/success', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ BillingAddressCollection: stripe.String(stripe.CheckoutSessionBillingAddressCollectionRequired), ShippingAddressCollection: &stripe.CheckoutSessionCreateShippingAddressCollectionParams{ AllowedCountries: []*string{stripe.String("US"), stripe.String("CA")}, }, AutomaticTax: &stripe.CheckoutSessionCreateAutomaticTaxParams{ Enabled: stripe.Bool(true), }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { BillingAddressCollection = "required", ShippingAddressCollection = new Stripe.Checkout.SessionShippingAddressCollectionOptions { AllowedCountries = new List { "US", "CA" }, }, AutomaticTax = new Stripe.Checkout.SessionAutomaticTaxOptions { Enabled = true }, Mode = "payment", SuccessUrl = "https://example.com/success", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d billing_address_collection=required \ -d "shipping_address_collection[allowed_countries][]"=US \ -d "shipping_address_collection[allowed_countries][]"=CA \ -d "automatic_tax[enabled]"=true \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" ``` ```cli stripe checkout sessions create \ --billing-address-collection=required \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_address_collection[allowed_countries][1]"=CA \ -d "automatic_tax[enabled]"=true \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ billing_address_collection: 'required', shipping_address_collection: {allowed_countries: ['US', 'CA']}, automatic_tax: {enabled: true}, mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "billing_address_collection": "required", "shipping_address_collection": {"allowed_countries": ["US", "CA"]}, "automatic_tax": {"enabled": True}, "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'billing_address_collection' => 'required', 'shipping_address_collection' => ['allowed_countries' => ['US', 'CA']], 'automatic_tax' => ['enabled' => true], 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setBillingAddressCollection(SessionCreateParams.BillingAddressCollection.REQUIRED) .setShippingAddressCollection( SessionCreateParams.ShippingAddressCollection.builder() .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.US ) .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.CA ) .build() ) .setAutomaticTax(SessionCreateParams.AutomaticTax.builder().setEnabled(true).build()) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ billing_address_collection: 'required', shipping_address_collection: { allowed_countries: ['US', 'CA'], }, automatic_tax: { enabled: true, }, mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ BillingAddressCollection: stripe.String(stripe.CheckoutSessionBillingAddressCollectionRequired), ShippingAddressCollection: &stripe.CheckoutSessionCreateShippingAddressCollectionParams{ AllowedCountries: []*string{stripe.String("US"), stripe.String("CA")}, }, AutomaticTax: &stripe.CheckoutSessionCreateAutomaticTaxParams{ Enabled: stripe.Bool(true), }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { BillingAddressCollection = "required", ShippingAddressCollection = new Stripe.Checkout.SessionShippingAddressCollectionOptions { AllowedCountries = new List { "US", "CA" }, }, AutomaticTax = new Stripe.Checkout.SessionAutomaticTaxOptions { Enabled = true }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` When the customer completes the session, the [Checkout Session](https://docs.stripe.com/api/checkout/sessions/object.md) object saves the collected shipping address on the `shipping_details` property and includes it in the payload of the `checkout.session.completed` *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests). You can also see shipping information in the Dashboard on the payment details page. ## See also - [Charge for shipping](https://docs.stripe.com/payments/during-payment/charge-shipping.md) - [Collect phone numbers](https://docs.stripe.com/payments/checkout/phone-numbers.md) --- # Source: https://docs.stripe.com/tax/supported-countries/latin-america-and-caribbean/collect-tax.md # Source: https://docs.stripe.com/tax/supported-countries/asia-pacific/collect-tax.md # Collect tax in Asia Pacific Learn how to collect tax in a country in Asia Pacific. In the Asia Pacific (APAC) region, Stripe supports tax calculation for businesses making sales into a range of countries. The requirements for tax registration, as well as which types of transactions are included, vary from country to country. For each country listed, you can find information about: - The types of tax Stripe can help you collect. - The registration threshold that determines when you’re required to register for tax collection. - What kinds of products or sales are subject to tax calculation. - The types of transactions covered. - Resources about how to register with local tax authorities. Stripe can collect tax if your business is based in Australia, Hong Kong, Japan, New Zealand, Singapore and United Arab Emirates. To collect tax on Stripe in other listed APAC countries, your business needs to be a remote seller with no physical presence (such as a shop or warehouse). - **Status** - None No transactions - **Tax type** VAT - **Product type** Digital products - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital products - **Registration resources** [Domestic VAT registration](https://file-online.taxservice.am/pages/evatuser/evatUser.jsf) ## Threshold and registration for Armenia Remote sellers providing electronically supplied services (digital products) to individuals in Armenia have to register for tax from their first sale there. Sales to [business customers](https://docs.stripe.com/tax/checkout/tax-ids.md) don’t trigger any tax registration obligations as remote sellers aren’t required to collect tax on those sales. ## Supported calculations for Armenia In Armenia, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Armenia. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Armenia, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** GST - **Threshold** 75,000 AUD (or 150,000 AUD for non-profit organizations) - **Time frame** Previous or current year - **Included transactions** Any taxable transactions that reverse charge doesn’t apply to - **Registration resources** - [Registration for businesses with a head office in Australia](https://www.ato.gov.au/Business/GST/Registering-for-GST/) - [Registration for remote sellers](https://www.ato.gov.au/Business/International-tax-for-business/Non-resident-businesses-and-GST/) (businesses based outside of Australia selling into Australia) ## Threshold and registration for Australia Remote sellers must register in Australia if their sales of services or low-value goods to Australian individuals exceed 75,000 AUD in the past 12 months or are expected to in the next 12 months. Sales to GST-registered Australian businesses that are subject to reverse charge don’t count toward the threshold. Non-profit organizations who sell remotely have a higher 150,000 AUD threshold but the threshold monitoring tool doesn’t track this. If a remote business sells digital services or low-value goods into Australia exclusively through online marketplaces that are responsible for collecting tax on these sales, the seller isn’t required to register for GST in Australia. These sales don’t count toward the seller’s registration threshold. ## Supported calculations for Australia When both your business and your customer are in Australia, Stripe calculates Australian GST unless the sale is exempt or zero-rated. If you’re a remote seller and sell services to Australian customers, GST is typically collected on sales to individuals. No tax is charged on sales to business customers who provide their [Australian Business Register (ABN) number](https://docs.stripe.com/tax/checkout/tax-ids.md). If you provide services related to admission to events and other venues, Stripe Tax considers them taxable in the country where the venue or event is located. ### Cross-border sales of goods to Australia When goods are shipped into Australia from abroad, Stripe treats the sale as an export and doesn’t calculate tax, unless you choose to calculate tax on cross-border sales of goods into Australia through the [tax registration settings](https://docs.stripe.com/tax/registering.md#track-your-registrations-in-the-tax-dashboard). Generally, businesses need to collect tax on these sales if they act as the importer for customs purposes. If goods are imported in the customer’s name, the sale is considered to occur outside Australia, and no Australian VAT is due. Cross-border sales of goods into Australia might also be subject to import taxes and customs duties in Australia, which Stripe doesn’t calculate. Stripe doesn’t calculate GST on sales of imported low-value goods (valued 1,000 AUD or less) to Australian individuals unless you select the option to calculate tax on cross-border sales of goods into Australia. ### Marketplace tax liability in Australia Australia defines electronic distribution platform (EDP) operators as marketplace operators that might have tax collection obligations. To qualify as an EDP, a marketplace operator must set terms or conditions for the sale, process or enable customer payments, or handle ordering or delivery of the product. Businesses that only provides payment processing or maintain the technical infrastructure behind an online marketplace don’t qualify as EDPs. EDP operators must collect GST on: - Sales of imported low-value goods by remote sellers to private individuals in Australia. - Sales of digital services by remote sellers to private individuals in Australia. - **Status** - None No transactions - **Tax type** VAT - **Product type** Digital products - **Threshold** 1 transaction if you’re selling digital services to customers in Azerbaijan. - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) from your first sale in Azerbaijan. - **Registration resources** [Register to collect tax in Azerbaijan](https://www.taxes.gov.az/en/post/3388) ## Threshold and registration for Azerbaijan Registering to collect tax in Azerbaijan is voluntary if you’re selling digital services to customers in Azerbaijan. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Time frame** 12 months - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Domestic VAT registration](https://nbr.gov.bd/eservices/2/eng) ## Threshold and registration for Bangladesh Remote sellers providing digital goods or electronically supplied services (digital products) to Bangladeshi customers must register for VAT purposes if there is at least one transaction of digital goods and services provided to private individuals in Bangladesh within a period of 12 months. Sales to business customers in Bangladesh don’t trigger any tax registration obligations because non-resident businesses aren’t required to collect tax on these sales. ## Supported calculations for Bangladesh In Bangladesh, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Bangladesh. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Bangladesh, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Threshold** 1 transaction - **Time frame** 12 months - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Domestic VAT registration](https://www.nbr.gov.bh/vat_registration) ## Threshold and registration for Bahrain Remote sellers providing digital goods or electronically supplied services (digital products) to consumers in Bahrain have no registration threshold. They must register for VAT purposes from the first sale. Sales to business customers in Bahrain don’t trigger any tax registration obligations because non-resident businesses aren’t required to collect tax on these sales. - **Status** - None No transactions - **Threshold** KHR 250 million - **Time frame** Current year - **Included transactions** Business-to-consumer (B2C) and Business-to-business (B2B) sales of digital goods and services - **Registration resources** [Domestic VAT registration](https://www.tax.gov.kh/en/faq#) ## Threshold and registration for Cambodia Remote sellers supplying digital goods and services to consumers in Cambodia are required to register for VAT within 30 days when their taxable sales of digital goods and services exceeds KHR 250,000,000. Businesses also have to register if they expect to exceed KHR 60 million (approximately USD 15,000) in any 3-month-consecutive period. ## Supported calculations for Cambodia In Cambodia, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Cambodia. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Cambodia, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Time frame** 12 months - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Domestic VAT registration](https://nr.rs.ge/home) ## Threshold and registration for Georgia Remote sellers providing electronically supplied services (digital products) to individuals in Georgia have no registration threshold. The Georgian tax administration refers to a remote seller as a “foreign taxable person that pays VAT without an obligation of registration.” ## Supported calculations for Georgia In Georgia, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Georgia. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Georgia, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** N/A - **Registration resources** - [Hong Kong profits tax](https://www.gov.hk/en/business/taxes/profittax/index.htm) - [Registering for sales tax in the United States](https://stripe.com/guides/sales-tax-registration-process-us)1 - [Registering for VAT in the European Union](https://stripe.com/guides/tax-registration-process-europe)1 1Because Hong Kong doesn’t impose VAT or sales tax, you might need to register to collect tax on your sales in other countries. ## Threshold and registration for Hong Kong Hong Kong doesn’t impose VAT or sales tax. This means you won’t see an option to add your registration for Hong Kong to Stripe and collect taxes from your customers based in Hong Kong. However, Hong Kong does impose other taxes on businesses, including a profits tax. ## Supported calculations for Hong Kong Generally, most transactions are taxable in the jurisdiction where your customer is. Stripe assumes the sale of most goods or services to be taxable unless specifically exempted. If you provide services related to admission to events and other venues, Stripe Tax considers them taxable in the country where the venue or event is located. - **Status** - None No transactions - **Tax type** IGST - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Domestic VAT registration](https://tutorial.gst.gov.in/userguide/registration/index.htm#t=Non-Resident_Online_Services_Provider_manual.htm) ## Threshold and registration for India Remote sellers providing digital goods or electronically supplied services (digital products) to consumers in India have no registration threshold. They must register for IGST purposes from the first sale. Sales to [business customers](https://docs.stripe.com/tax/checkout/tax-ids.md) in India don’t trigger any tax registration obligations because non-resident businesses aren’t required to collect tax on these sales. ## Supported calculations for India In India, Stripe only supports collecting integrated goods and services tax (IGST) for online information and database access or retrieval services (OIDAR). Stripe refers to these as “digital products." To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. ## Additional address requirements To calculate tax in India, Stripe Tax needs the Indian state or union territory as part of the customer address information, and the reports show the province based on this information. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 50 million IDR - **Time frame** Calendar month - **Included transactions** Sales of digital goods and services - **Registration resources** [Domestic VAT registration](https://www.pajak.go.id/en/digitaltax) ## Threshold and registration for Indonesia Remote sellers providing digital goods or electronically supplied services (digital products) to Indonesian customers are appointed as VAT collectors when they meet either of the following thresholds: - The total value of digital goods and services provided to customers in Indonesia exceeds IDR 600 million in a period of 12 months or IDR 50 million in one calendar month. - Website traffic in Indonesia exceeds 12,000 users in one year or 1,000 users in one month. Remote sellers who meet the registration thresholds can ask to be appointed a VAT collector and start collecting VAT voluntarily but aren’t obligated to do so. ## Supported calculations for Indonesia In Indonesia, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Indonesia. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Indonesia, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** Consumption Tax - **Threshold** 10 million JPY - **Time frame** - Japanese base period - Japanese specified period - **Included transactions** Any taxable transactions that reverse charge doesn’t apply to - **Registration resources** - [General information about Consumption Tax in Japan](https://www.nta.go.jp/english/taxes/consumption_tax/01.htm) - [Registration for remote sellers of electronic services](https://www.nta.go.jp/english/taxes/consumption_tax/04.htm) ## Threshold and registration for Japan Remote sellers must register in Japan in either of the following cases: - Their taxable sales in Japan exceed the registration threshold of 10 million JPY in the base period. - Their taxable sales exceed 10 million JPY in the specified period. The specified period refers to the first 6 months of the previous calendar year (for sole proprietors) or the first 6 months of a fiscal year (for corporations). Registered remote sellers must have an office located in Japan or have a tax representative in Japan. Remote sellers that provide electronic services to Japanese consumers can use a simplified registration procedure. ## Supported calculations for Japan When both your business and your customer are in Japan, Stripe calculates Japanese Consumption Tax unless the sale is exempt or zero-rated.If you’re a remote seller and sell services to Japanese customers, Consumption Tax is typically collected on sales to individuals. No tax is charged on sales to business customers who provide their [tax registration number](https://docs.stripe.com/tax/checkout/tax-ids.md). If you provide services related to admission to events and other venues, Stripe Tax considers them taxable in the country where the venue or event is located. ### Cross-border sales of goods to Japan When goods are shipped into Japan from abroad, Stripe treats the sale as an export and doesn’t calculate tax, unless you choose to calculate tax on cross-border sales of goods into Japan through the [tax registration settings](https://docs.stripe.com/tax/registering.md#track-your-registrations-in-the-tax-dashboard). Generally, businesses need to collect tax these sales if they act as the importer for customs purposes. If goods are imported in the customer’s name, the sale is considered to occur outside Japan, and no Japanese Consumption Tax is due. Cross-border sales of goods into Japan might also be subject to import taxes and customs duties in Japan, which Stripe doesn’t calculate. Cross-border sales of goods into Japan might also be subject to import taxes and customs duties in Japan, which Stripe doesn’t calculate. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Domestic VAT registration](https://kgd.gov.kz/en/content/taxation-foreign-companies-engaged-electronic-trade-goods-and-provision-electronic-services) ## Threshold and registration for Kazakhstan Remote sellers providing digital goods or electronically supplied services (digital products) to consumers in Kazakhstan have no registration threshold. They must register for VAT purposes from the first sale. Sales to business customers in Kazakhstan don’t trigger any tax registration obligations because non-resident businesses aren’t required to collect tax on these sales. ## Supported calculations for Kazakhstan In Kazakhstan, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Kazakhstan. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Kazakhstan, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Domestic VAT registration](https://kgd.gov.kz/en/content/taxation-foreign-companies-engaged-electronic-trade-goods-and-provision-electronic-services) ## Threshold and registration for Kyrgyzstan Remote sellers providing digital goods or electronically supplied services (digital products) to Kyrgyz customers must register for VAT purposes if there is at least one transaction of digital goods and services provided to customers in Kyrgyzstan within a year. ## Supported calculations for Kyrgyzstan In Kyrgyzstan, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Kyrgyzstan. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Kyrgyzstan, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) and Business-to-business (B2B) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Domestic VAT registration](https://taxservice.mof.gov.la/) ## Threshold and registration for Laos Remote sellers providing digital goods or electronically supplied services (digital products) to Lao customers must register for VAT purposes if there is at least one transaction of digital goods and services provided to customers in Laos within a period of 12 months. ## Supported calculations for Laos In Laos, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Laos. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Laos, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 500,000 MYR - **Time frame** 12 months - **Included transactions** Sales of digital goods and services - **Registration resources** [Registering for Service Tax in Malaysia](https://mystods.customs.gov.my/) ## Threshold and registration for Malaysia Remote sellers providing digital goods or electronically supplied services (digital products) to Malaysian customers must register for Service Tax purposes if the total value of digital goods and services provided to customers in Malaysia within a period of 12 months exceeds 500,000 MYR. ## Supported calculations for Malaysia In Malaysia, Stripe only supports collecting the [Service Tax](https://mystods.customs.gov.my/) on digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. - **Status** - None No transactions - **Tax type** VAT - **Threshold** NPR 3 million - **Time frame** 12 months - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [General information about VAT registration](http://ereturns.ird.gov.np:8289/registration) ## Threshold and registration for Nepal Remote sellers providing digital services (digital products) to customers in Nepal must register for VAT if the total value within a period of 12 months exceeds NPR 3,000,000. Sales to business customers don’t trigger any tax registration obligations as remote sellers aren’t required to collect tax on those sales. ## Supported calculations for Nepal In Nepal, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Nepal. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Nepal, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 60,000 NZD - **Time frame** Previous or current year - **Included transactions** Any taxable transactions that reverse charge doesn’t apply to - **Registration resources** - [Register for GST](https://www.ird.govt.nz/gst/registering-for-gst/register-for-gst) - [How GST works for remote sellers](https://www.ird.govt.nz/gst/gst-for-overseas-businesses) ## Threshold and registration for New Zealand Remote sellers supplying goods or services in New Zealand must register if their taxable turnover from these transactions exceeded 60,000 NZD within the past 12-month period or will exceed this amount in the next 12 months. These rules apply to businesses supplying remote services such as digital content or low-value goods from outside New Zealand to customers who are resident in New Zealand and aren’t registered for GST. Sales to New Zealand GST-registered businesses that are subject to reverse charge don’t count towards the threshold. ## Supported calculations for New Zealand When both your business and your customer are in New Zealand, Stripe calculates GST unless the sale is exempt or zero-rated. If you’re a remote seller and sell services to customers in New Zealand, GST is typically collected on sales to individuals. No tax is charged on sales to business customers who provide their [GST number](https://docs.stripe.com/tax/checkout/tax-ids.md). If you provide services related to admission to events and other venues, Stripe Tax considers them taxable in the country where the venue or event is located. ### Cross-border sales of goods to New Zealand When goods are shipped into New Zealand from abroad, Stripe treats the sale as an export and doesn’t calculate tax, unless you choose to calculate tax on cross-border sales of goods into New Zealand through the [tax registration settings](https://docs.stripe.com/tax/registering.md#track-your-registrations-in-the-tax-dashboard). Whether you need to charge GST depends on the location of the goods at the time of sale. You don’t need to charge GST if the goods are outside New Zealand at the time of supply. However, if the goods are inside New Zealand during the supply, you must charge GST if you’re GST-registered or required to be GST-registered. Cross-border goods sales into New Zealand might also be subject to import taxes and customs duties, which Stripe doesn’t calculate. Stripe doesn’t calculate GST on sales of imported low-value goods, valued at 1000 NZD or less, to individuals in New Zealand unless you select the option to calculate tax on cross-border goods sales into New Zealand. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Register for VAT in Oman](https://taxoman.gov.om/portal/web/taxportal/e-services) ## Threshold and registration for Oman Remote sellers providing digital goods or electronically supplied services (digital products) to consumers in Oman have no registration threshold. They must register for VAT purposes from the first sale. Sales to business customers in Oman don’t trigger any tax registration obligations because non-resident businesses aren’t required to collect tax on these sales. ## Supported calculations for Oman In Oman, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Oman. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Oman, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 3,000,000 PHP - **Time frame** Current year - **Registration resources** [Register for VAT in Philippines](https://www.bir.gov.ph/vat-on-ds) ## Threshold and registration for Philippines Remote sellers providing digital goods or electronically supplied services (digital products) to Filipino customers must register for VAT purposes if the total value of digital goods and services provided to private individuals in Philippines within the current year exceeds 3,000,000 PHP. Sales to business customers in the Philippines don’t trigger any tax registration obligations because non-resident businesses aren’t required to collect tax on these sales. ## Supported calculations for Philippines We only support calculations for digital products (non-physical items or services that are delivered, given, or rendered electronically) in Philippines. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. If you’re a remote seller and sell digital products to customers in the Philippines, VAT is typically collected on sales to individuals. No tax is charged on sales to business customers (B2B) who provide their tax ID number. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Register for VAT in Saudi Arabia](https://zatca.gov.sa/en/eServices/Pages/eServices_001.aspx) ## Threshold and registration for Saudi Arabia Remote sellers providing digital goods or electronically supplied services (digital products) to consumers in Saudi Arabia have no registration threshold. They must register for VAT purposes from the first sale. Sales to business customers in Saudi Arabia don’t trigger any tax registration obligations because non-resident businesses aren’t required to collect tax on these sales. ## Supported calculations for Saudi Arabia In Saudi Arabia, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Saudi Arabia. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Saudi Arabia, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** - 1 million SGD (Domestic registration) - 100,000 SGD (Overseas vendor registration) - **Time frame** - Previous or current year (Domestic registration) - Calendar year - **Included transactions** - Any taxable transactions that reverse charge doesn’t apply to (Domestic registration) - For the 100,000 SGD threshold, Business-to-consumer (B2C) sales of digital goods or electronically supplied services (Overseas vendor registration) - **Registration resources** - [Register for GST](https://www.iras.gov.sg/taxes/goods-services-tax-\(gst\)) - [How to register](https://www.iras.gov.sg/taxes/goods-services-tax-\(gst\)/gst-registration-deregistration/applying-for-gst-registration) ## Threshold and registration for Singapore Remote sellers must register for GST if the Singaporean taxable turnover exceeded 1 million SGD in the past 12 months (retrospective basis) or is likely to exceed 1 million SGD in the next 12 months (prospective basis). A special registration rule applies to remote sellers of digital services. As of Jan 1, 2020, non-resident suppliers must register under the Overseas Vendor Registration regime if in a calendar year: - They have a global turnover exceeding 1 million SGD. - They make B2C supplies of digital services to customers in Singapore exceeding 100,000 SGD. Global turnover refers to all supplies made that would be taxable supplies if made in Singapore. ## Supported calculations for Singapore When both your business and your customer are in Singapore, Stripe calculates GST unless the sale is exempt or zero-rated. If you’re a remote seller and sell services to customers in Singapore, GST is typically collected on sales to individuals. No tax is charged on sales to business customers who provide their [GST registration number](https://docs.stripe.com/tax/checkout/tax-ids.md). If you provide services related to admission to events and other venues, Stripe Tax considers them taxable in the country where the venue or event is located. ### Cross-border sales of goods to Singapore When goods are shipped into Singapore from abroad, Stripe treats the sale as an export and doesn’t calculate tax, unless you choose to calculate tax on cross-border sales of goods into Singapore through the [tax registration settings](https://docs.stripe.com/tax/registering.md#track-your-registrations-in-the-tax-dashboard). Generally, businesses need to collect tax on these sales if they act as the importer for customs purposes. If goods are imported in the customer’s name, the sale is considered to occur outside Singapore, and no Singapore GST is due. Cross-border sales of goods into Singapore might also be subject to import taxes and customs duties in Singapore, which Stripe doesn’t calculate. Stripe doesn’t calculate GST on sales of imported low-value goods, valued at 400 SGD or less, to individuals in Singapore unless you select the option to calculate tax on cross-border goods sales into Singapore. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital goods and services - **Registration resources** [Register for VAT in South Korea](https://www.nts.go.kr/english/na/ntt/selectNttList.do?mi=11210&bbsId=30699) ## Threshold and registration for South Korea Remote sellers providing digital goods or electronically supplied services (digital products) to consumers in South Korea must register for VAT purposes as from the first sale. There are no registration thresholds for non-resident service providers. Sales to business customers in South Korea don’;t trigger any tax registration obligations as remote sellers aren’t required to collect tax on such sales. ## Supported calculations for South Korea In South Korea, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in South Korea. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in South Korea, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 600,000 TWD - **Time frame** Calendar year - **Included transactions** Business-to-consumer (B2C) sales of digital products - **Registration resources** [Register for VAT in Taiwan](https://www.etax.nat.gov.tw/etwmain/en/cbec-tax-area/business-tax/file-taxation-registration) ## Threshold and registration for Taiwan Remote sellers providing digital products to customers in Taiwan are required to register if their annual sales to individuals exceed TWD 600,000. ## Supported calculations for Taiwan If you’re a remote seller and sell services to Taiwanese customers, VAT is collected on sales to individuals. No tax is charged on sales to business customers who provide their tax identification number. ## Electronic invoicing If you’re a remote seller providing digital products to customers in Taiwan, you need to issue e-invoices through Taiwan’s eGUI system. The easiest way to meet this requirement is by partnering with a certified service provider to manage the e-invoicing process for you. The [Stripe App Marketplace](https://marketplace.stripe.com/) includes options for third-party service providers that can help with these e-invoicing needs. For instance, [Billit](https://marketplace.stripe.com/apps/billit) automatically converts your Stripe invoices into the eGUI format, sends them to your customers, reports them to the tax administration, and keeps you updated through the Stripe Dashboard. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Register for VAT in Tajikistan](https://www.financnasprava.sk/en/businesses/taxes-businesses#ZahranicnaOsobaDPH) ## Threshold and registration for Tajikistan Remote sellers providing electronic services (digital products) to customers in Tajikistan must register for VAT from their first sale. Sales to business customers don’t trigger any tax registration obligations as remote sellers aren’t required to collect tax on those sales. ## Supported calculations for Tajikistan In Tajikistan, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Tajikistan. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Tajikistan, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** THB 1.8 million - **Included transactions** Business-to-consumer (B2C) sales of digital goods and services - **Registration resources** [Register for VAT in Thailand](https://eservice.rd.go.th/rd-ves-web/landing) ## Threshold and registration for Thailand Remote sellers supplying digital goods and services to Thai consumers are required to register for VAT purposes if their taxable sales of digital goods and services exceed THB 1.8 million. The threshold period is an accounting period (for corporations) or a calendar year (for individuals). Remote sellers are required to register for VAT within 30 days from the day they have satisfied the registration threshold. ## Supported calculations for Thailand In Thailand, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Thailand. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Thailand, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital goods or electronically supplied services (digital products) - **Registration resources** [Register for VAT in Türkiye](https://digitalservice.gib.gov.tr/kdv3_side/main.jsp) ## Threshold and registration for Türkiye Remote sellers providing digital goods or electronically supplied services (digital products) to customers in Türkiye must register for VAT purposes if their taxable sales of digital goods or electronically supplied services (digital products) exceed 1 million TL in the past 12 months (retrospective basis) or is likely to exceed 1 million TL in the next 12 months (prospective basis). ## Supported calculations for Türkiye In Türkiye, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Türkiye. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Türkiye, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Any taxable transactions that reverse charge doesn’t apply to - **Registration resources** [Register for VAT in United Arab Emirates](https://tax.gov.ae/en/taxes/vat.aspx) ## Threshold and registration for United Arab Emirates Remote sellers providing digital goods or electronically supplied services (digital products) to customers in United Arab Emirates have to register for tax from their first sale there. Sales to business customers don’t trigger any tax registration obligations as remote sellers aren’t required to collect tax on those sales. ## Supported calculations for United Arab Emirates When both your business and your customer are in the UAE, Stripe calculates VAT unless the sale is exempt or zero-rated. If you’re a remote seller and sell services to customers in the UAE, VAT is typically collected on sales to individuals. No tax is charged on sales to business customers who provide their VAT number. If you provide services related to admission to events and other venues, Stripe Tax considers them taxable in the country where the venue or event is located. ### Cross-border sales of goods to United Arab Emirates When goods are shipped into the UAE from abroad, Stripe treats the sales as an export and doesn’t calculate tax, unless you choose to calculate tax on cross-border goods sales into the UAE through the [tax registration settings](https://docs.stripe.com/tax/registering.md#track-your-registrations-in-the-tax-dashboard). Generally, businesses need to collect tax on these sales if they act as the importer for customs purposes. If goods are imported in the customer’s name, the sale is considered to occur outside the UAE, and no UAE VAT is due on the sale. The customer may be responsible under the reverse charge mechanism, which usually applies if the customer is registered and resident in the UAE. Cross-border sales of goods into the UAE might also be subject to import taxes and customs duties, which Stripe doesn’t calculate. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital products - **Registration resources** [Register for VAT in Uzbekistan](https://tax.uz/en/pages/view?id=1) ## Threshold and registration for Uzbekistan Remote sellers providing electronically supplied services (digital products) to individuals in Uzbekistan have to register for tax from their first sale there. Sales to business customers don’t trigger any tax registration obligations as remote sellers aren’t required to collect tax on those sales. ## Supported calculations for Uzbekistan In Uzbekistan, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Uzbekistan. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Uzbekistan, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. - **Status** - None No transactions - **Tax type** VAT - **Threshold** 1 transaction - **Included transactions** Business-to-consumer (B2C) sales of digital products - **Registration resources** [Register for VAT in Uzbekistan](https://tax.uz/en/pages/view?id=1) ## Threshold and registration for Vietnam In Vietnam, the Foreign Contractor Tax (FCT) applies to sales of digital services by remote sellers without a physical presence in the country. This tax consists of VAT and income tax. Stripe only supports collecting VAT for digital services, which Stripe refers to as digital products. Stripe doesn’t calculate the income tax component of the FCT. ## Supported calculations for Vietnam In Vietnam, Stripe only supports collecting VAT for digital services. In Stripe, these are referred to as “digital products.” To collect this tax on Stripe, you must be a remote seller without a physical presence in the country. We only support calculations for [digital products](https://docs.stripe.com/tax/tax-codes.md?type=digital) (non-physical items or services that are delivered, given, or rendered electronically) in Vietnam. Stripe doesn’t calculate tax for products that don’t use a digital product tax code. View the list of supported [digital product tax codes](https://docs.stripe.com/tax/tax-codes.md?type=digital). To calculate taxes in Vietnam, make sure that you [assign a tax code](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-code-on-product) to each of your products. ## See also - [Set up Stripe Tax](https://docs.stripe.com/tax/set-up.md) - [Register for sales tax, VAT, and GST](https://docs.stripe.com/tax/registering.md) - [Use Stripe to register](https://docs.stripe.com/tax/use-stripe-to-register.md) --- # Source: https://docs.stripe.com/billing/taxes/collect-taxes.md # Collect taxes for recurring payments Learn how to collect and report taxes for recurring payments. To calculate tax for recurring payments, Stripe offers Stripe Tax and Tax Rates. - **Stripe Tax**—a paid product that automatically calculates the tax on your transactions without the need to define the rates and rules. Fees only apply after you’ve added at least one location where you’re registered to calculate and remit tax. For more information, see [Stripe Tax](https://docs.stripe.com/tax.md). - **Tax Rates**—a free feature that allows you to define any number of tax rates for *invoices* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice), *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis), and one-time payments that use Checkout. Stripe won’t create or maintain any tax rates on your behalf. For more information, see [Tax Rates](https://docs.stripe.com/api/tax_rates.md) and [how to use them](https://docs.stripe.com/billing/taxes/tax-rates.md). # Stripe Tax > This is a Stripe Tax for when tax-calculation is stripe-tax. View the full page at https://docs.stripe.com/billing/taxes/collect-taxes?tax-calculation=stripe-tax. Stripe Tax allows you to calculate the tax amount on your recurring payments when using Stripe Billing. Use your customer’s location details to preview the tax amount before creating a subscription and then create it with Stripe Tax enabled when your customer is ready to pay. Stripe Tax integrates with Stripe Billing and automatically handles tax calculation with your [pricing model](https://docs.stripe.com/products-prices/pricing-models.md), [prorations](https://docs.stripe.com/billing/subscriptions/prorations.md), [discounts](https://docs.stripe.com/billing/subscriptions/coupons.md), [trials](https://docs.stripe.com/billing/subscriptions/trials.md), and so on. A diagram providing a high level overview of a Stripe Tax and Billing integration. (See full diagram at https://docs.stripe.com/billing/taxes/collect-taxes) This guide assumes you’re setting up Stripe Tax and Billing for the first time. See how to [update existing subscriptions](https://docs.stripe.com/tax/subscriptions/update.md). If you’re using Stripe Checkout to create new subscriptions, see how to [automatically collect tax on Checkout sessions](https://docs.stripe.com/tax/checkout.md), or watch the short video below: [Watch on YouTube](https://www.youtube.com/watch?v=3QBRs4IfDNo) ## Estimate taxes and total [Server-side] #### Before address collection When a customer first enters your checkout flow, you might not have their address information yet. In this case, [create a preview invoice](https://docs.stripe.com/api/invoices/create_preview.md) and set [customer_details.tax.ip_address](https://docs.stripe.com/api/invoices/create_preview.md#create_create_preview-customer_details-tax-ip_address) to let Stripe locate them using their IP address. > In most cases, Stripe can resolve an IP address to a physical area, but its precision varies and might not reflect your customer’s actual location. We don’t recommend relying on a customer’s IP address to determine their address beyond an initial estimate. ```curl curl https://api.stripe.com/v1/invoices/create_preview \ -u "<>:" \ -d "automatic_tax[enabled]"=true \ -d "customer_details[tax][ip_address]"={{IP_ADDRESS}} \ -d "subscription_details[items][0][price]"="{{PRICE_ID}}" ``` ```cli stripe invoices create_preview \ -d "automatic_tax[enabled]"=true \ -d "customer_details[tax][ip_address]"={{IP_ADDRESS}} \ -d "subscription_details[items][0][price]"="{{PRICE_ID}}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") invoice = client.v1.invoices.create_preview({ automatic_tax: {enabled: true}, customer_details: {tax: {ip_address: '{{IP_ADDRESS}}'}}, subscription_details: {items: [{price: '{{PRICE_ID}}'}]}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. invoice = client.v1.invoices.create_preview({ "automatic_tax": {"enabled": True}, "customer_details": {"tax": {"ip_address": "{{IP_ADDRESS}}"}}, "subscription_details": {"items": [{"price": "{{PRICE_ID}}"}]}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $invoice = $stripe->invoices->createPreview([ 'automatic_tax' => ['enabled' => true], 'customer_details' => ['tax' => ['ip_address' => '{{IP_ADDRESS}}']], 'subscription_details' => ['items' => [['price' => '{{PRICE_ID}}']]], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); InvoiceCreatePreviewParams params = InvoiceCreatePreviewParams.builder() .setAutomaticTax( InvoiceCreatePreviewParams.AutomaticTax.builder().setEnabled(true).build() ) .setCustomerDetails( InvoiceCreatePreviewParams.CustomerDetails.builder() .setTax( InvoiceCreatePreviewParams.CustomerDetails.Tax.builder() .setIpAddress("{{IP_ADDRESS}}") .build() ) .build() ) .setSubscriptionDetails( InvoiceCreatePreviewParams.SubscriptionDetails.builder() .addItem( InvoiceCreatePreviewParams.SubscriptionDetails.Item.builder() .setPrice("{{PRICE_ID}}") .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Invoice invoice = client.v1().invoices().createPreview(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const invoice = await stripe.invoices.createPreview({ automatic_tax: { enabled: true, }, customer_details: { tax: { ip_address: '{{IP_ADDRESS}}', }, }, subscription_details: { items: [ { price: '{{PRICE_ID}}', }, ], }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.InvoiceCreatePreviewParams{ AutomaticTax: &stripe.InvoiceCreatePreviewAutomaticTaxParams{ Enabled: stripe.Bool(true), }, CustomerDetails: &stripe.InvoiceCreatePreviewCustomerDetailsParams{ Tax: &stripe.InvoiceCreatePreviewCustomerDetailsTaxParams{ IPAddress: stripe.String("{{IP_ADDRESS}}"), }, }, SubscriptionDetails: &stripe.InvoiceCreatePreviewSubscriptionDetailsParams{ Items: []*stripe.InvoiceCreatePreviewSubscriptionDetailsItemParams{ &stripe.InvoiceCreatePreviewSubscriptionDetailsItemParams{ Price: stripe.String("{{PRICE_ID}}"), }, }, }, } result, err := sc.V1Invoices.CreatePreview(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new InvoiceCreatePreviewOptions { AutomaticTax = new InvoiceAutomaticTaxOptions { Enabled = true }, CustomerDetails = new InvoiceCustomerDetailsOptions { Tax = new InvoiceCustomerDetailsTaxOptions { IpAddress = "{{IP_ADDRESS}}" }, }, SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = new List { new InvoiceSubscriptionDetailsItemOptions { Price = "{{PRICE_ID}}" }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Invoices; Invoice invoice = service.CreatePreview(options); ``` #### After address collection When your customer fills in their address details, set [customer_details.address](https://docs.stripe.com/api/invoices/create_preview.md#create_create_preview-customer_details-address) also. Use [customer_details.shipping](https://docs.stripe.com/api/invoices/create_preview.md#create_create_preview-customer_details-shipping) if you’re collecting shipping addresses. ```curl curl https://api.stripe.com/v1/invoices/create_preview \ -u "<>:" \ -d "automatic_tax[enabled]"=true \ -d "customer_details[address][line1]"={{LINE1}} \ -d "customer_details[address][line2]"={{LINE2}} \ -d "customer_details[address][city]"={{CITY}} \ -d "customer_details[address][state]"={{STATE}} \ -d "customer_details[address][postal_code]"={{POSTAL_CODE}} \ -d "customer_details[address][country]"={{COUNTRY}} \ -d "customer_details[tax][ip_address]"={{IP_ADDRESS}} \ -d "subscription_details[items][0][price]"="{{PRICE_ID}}" ``` ```cli stripe invoices create_preview \ -d "automatic_tax[enabled]"=true \ -d "customer_details[address][line1]"={{LINE1}} \ -d "customer_details[address][line2]"={{LINE2}} \ -d "customer_details[address][city]"={{CITY}} \ -d "customer_details[address][state]"={{STATE}} \ -d "customer_details[address][postal_code]"={{POSTAL_CODE}} \ -d "customer_details[address][country]"={{COUNTRY}} \ -d "customer_details[tax][ip_address]"={{IP_ADDRESS}} \ -d "subscription_details[items][0][price]"="{{PRICE_ID}}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") invoice = client.v1.invoices.create_preview({ automatic_tax: {enabled: true}, customer_details: { address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: {ip_address: '{{IP_ADDRESS}}'}, }, subscription_details: {items: [{price: '{{PRICE_ID}}'}]}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. invoice = client.v1.invoices.create_preview({ "automatic_tax": {"enabled": True}, "customer_details": { "address": { "line1": "{{LINE1}}", "line2": "{{LINE2}}", "city": "{{CITY}}", "state": "{{STATE}}", "postal_code": "{{POSTAL_CODE}}", "country": "{{COUNTRY}}", }, "tax": {"ip_address": "{{IP_ADDRESS}}"}, }, "subscription_details": {"items": [{"price": "{{PRICE_ID}}"}]}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $invoice = $stripe->invoices->createPreview([ 'automatic_tax' => ['enabled' => true], 'customer_details' => [ 'address' => [ 'line1' => '{{LINE1}}', 'line2' => '{{LINE2}}', 'city' => '{{CITY}}', 'state' => '{{STATE}}', 'postal_code' => '{{POSTAL_CODE}}', 'country' => '{{COUNTRY}}', ], 'tax' => ['ip_address' => '{{IP_ADDRESS}}'], ], 'subscription_details' => ['items' => [['price' => '{{PRICE_ID}}']]], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); InvoiceCreatePreviewParams params = InvoiceCreatePreviewParams.builder() .setAutomaticTax( InvoiceCreatePreviewParams.AutomaticTax.builder().setEnabled(true).build() ) .setCustomerDetails( InvoiceCreatePreviewParams.CustomerDetails.builder() .setAddress( InvoiceCreatePreviewParams.CustomerDetails.Address.builder() .setLine1("{{LINE1}}") .setLine2("{{LINE2}}") .setCity("{{CITY}}") .setState("{{STATE}}") .setPostalCode("{{POSTAL_CODE}}") .setCountry("{{COUNTRY}}") .build() ) .setTax( InvoiceCreatePreviewParams.CustomerDetails.Tax.builder() .setIpAddress("{{IP_ADDRESS}}") .build() ) .build() ) .setSubscriptionDetails( InvoiceCreatePreviewParams.SubscriptionDetails.builder() .addItem( InvoiceCreatePreviewParams.SubscriptionDetails.Item.builder() .setPrice("{{PRICE_ID}}") .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Invoice invoice = client.v1().invoices().createPreview(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const invoice = await stripe.invoices.createPreview({ automatic_tax: { enabled: true, }, customer_details: { address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: { ip_address: '{{IP_ADDRESS}}', }, }, subscription_details: { items: [ { price: '{{PRICE_ID}}', }, ], }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.InvoiceCreatePreviewParams{ AutomaticTax: &stripe.InvoiceCreatePreviewAutomaticTaxParams{ Enabled: stripe.Bool(true), }, CustomerDetails: &stripe.InvoiceCreatePreviewCustomerDetailsParams{ Address: &stripe.InvoiceCreatePreviewCustomerDetailsAddressParams{ Line1: stripe.String("{{LINE1}}"), Line2: stripe.String("{{LINE2}}"), City: stripe.String("{{CITY}}"), State: stripe.String("{{STATE}}"), PostalCode: stripe.String("{{POSTAL_CODE}}"), Country: stripe.String("{{COUNTRY}}"), }, Tax: &stripe.InvoiceCreatePreviewCustomerDetailsTaxParams{ IPAddress: stripe.String("{{IP_ADDRESS}}"), }, }, SubscriptionDetails: &stripe.InvoiceCreatePreviewSubscriptionDetailsParams{ Items: []*stripe.InvoiceCreatePreviewSubscriptionDetailsItemParams{ &stripe.InvoiceCreatePreviewSubscriptionDetailsItemParams{ Price: stripe.String("{{PRICE_ID}}"), }, }, }, } result, err := sc.V1Invoices.CreatePreview(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new InvoiceCreatePreviewOptions { AutomaticTax = new InvoiceAutomaticTaxOptions { Enabled = true }, CustomerDetails = new InvoiceCustomerDetailsOptions { Address = new AddressOptions { Line1 = "{{LINE1}}", Line2 = "{{LINE2}}", City = "{{CITY}}", State = "{{STATE}}", PostalCode = "{{POSTAL_CODE}}", Country = "{{COUNTRY}}", }, Tax = new InvoiceCustomerDetailsTaxOptions { IpAddress = "{{IP_ADDRESS}}" }, }, SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = new List { new InvoiceSubscriptionDetailsItemOptions { Price = "{{PRICE_ID}}" }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Invoices; Invoice invoice = service.CreatePreview(options); ``` Check the [automatic_tax.status](https://docs.stripe.com/api/invoices/object.md#invoice_object-automatic_tax-status) of the invoice. If the status is `requires_location_inputs`, it means that the address details are invalid or insufficient. In this case, prompt your customer to re-enter their address details or provide accurate address details. The invoice [total](https://docs.stripe.com/api/invoices/object.md#invoice_object-total) is how much your customer pays and [tax](https://docs.stripe.com/api/invoices/object.md#invoice_object-tax) is the sum of all tax amounts on the invoice. If you want a breakdown of taxes, see [total_tax_amounts](https://docs.stripe.com/api/invoices/object.md#invoice_object-total_tax_amounts). All amounts are in cents. > #### Zero tax > > If the `tax` is zero, make sure that you have a tax registration in your customer’s location. See how to [register for sales tax, VAT, and GST](https://docs.stripe.com/tax/registering.md) and learn more about [zero tax amounts and reverse charges](https://docs.stripe.com/tax/zero-tax.md). ## Collect customer information [Client-side] After you have an estimate of the taxes and the total, start collecting customer information including their shipping address (if applicable), billing address, and their payment details. Notice that when you use Stripe Tax, you collect payment details without an Intent. The first step is to [create an Elements object without an Intent](https://docs.stripe.com/js/elements_object/create_without_intent): ```javascript const stripe = Stripe("<>"); const elements = stripe.elements({ mode: 'subscription', currency: '{{CURRENCY}}', amount: {{TOTAL}}, // This is the invoice total. }); ``` Next, [create an Address Element](https://docs.stripe.com/js/elements_object/create_address_element) and [a Payment Element](https://docs.stripe.com/js/elements_object/create_payment_element) and [mount](https://docs.stripe.com/js/element/mount) both: ```javascript const addressElement = elements.create('address', { mode: 'billing' // or 'shipping', if you are shipping goods }); addressElement.mount('#address-element'); const paymentElementOptions = { layout: 'accordion'}; const paymentElement = elements.create('payment', paymentElementOptions); paymentElement.mount('#payment-element'); ``` Then you can listen to [change events](https://docs.stripe.com/js/element/events/on_change?type=paymentElement#element_on_change-event) on the Address Element. When the address changes, [re-estimate](https://docs.stripe.com/tax/subscriptions.md?estimate=after#estimate-taxes-total) the taxes and the total. ```javascript addressElement.on('change', function(event) { // Throttle your requests to avoid overloading your server or hitting // Stripe's rate limits. const { tax, total } = await updateEstimate(event.value.address); elements.update({ amount: total }); // Update your page to display the new tax and total to the user... }); ``` > When your customer is entering their address, Address Element fires a `change` event for each keystroke. To avoid overloading your server and hitting Stripe’s [rate limits](https://docs.stripe.com/rate-limits.md), wait for some time after the last `change` event before re-estimating the taxes and the total. ## Handle submission [Client-side] When your customer submits the form, call [elements.submit()](https://docs.stripe.com/js/elements/submit) to validate the form fields and collect any data required for wallets. You must wait for this function’s promise to resolve before performing any other operations. ```javascript document.querySelector("#form").addEventListener("submit", function(event) { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); const { error: submitError } = await elements.submit(); if (submitError) { // Handle error... return; } const { value: customerDetails } = await addressElement.getValue(); // See the "Save customer details" section below to implement this // server-side. await saveCustomerDetails(customerDetails); // Makes a request to your server to save the customer details. // See the "Create subscription" section below to implement this server-side. const { clientSecret } = await createSubscription(); // latest_invoice.confirmation_secret.client_secret of the new subscription. // Makes a request to your server to create a subscription. const { error: confirmError } = await stripe.confirmPayment({ elements, clientSecret, confirmParams: { return_url: {{RETURN_URL}}, // The URL Stripe redirects your customer to after they complete the payment. }, }); if (confirmError) { // Handle error... return; } // Upon a successful confirmation, your user will be redirected to the // return_url you provide before the Promise ever resolves. }); ``` ## Save customer details [Server-side] [Update](https://docs.stripe.com/api/customers/update.md) your `Customer` object using the details you’ve collected from your customer, so that Stripe Tax can determine their precise location for accurate results. > If your customer is in the United States, provide a full address if possible. We use the term “rooftop-accurate” to mean that we can attribute your customer’s location to a specific house or building. This provides greater accuracy, where two houses located side-by-side on the same street might be subject to different tax rates, because of complex jurisdiction boundaries. If you haven’t already created a `Customer` object (for example, when your customer first signs up on your website), you can [create](https://docs.stripe.com/api/customers/create.md) one now. #### Update customer ```curl curl https://api.stripe.com/v1/customers/{{CUSTOMER_ID}} \ -u "<>:" \ -d "address[line1]"={{LINE1}} \ -d "address[line2]"={{LINE2}} \ -d "address[city]"={{CITY}} \ -d "address[state]"={{STATE}} \ -d "address[postal_code]"={{POSTAL_CODE}} \ -d "address[country]"={{COUNTRY}} \ -d "tax[validate_location]"=immediately ``` ```cli stripe customers update {{CUSTOMER_ID}} \ -d "address[line1]"={{LINE1}} \ -d "address[line2]"={{LINE2}} \ -d "address[city]"={{CITY}} \ -d "address[state]"={{STATE}} \ -d "address[postal_code]"={{POSTAL_CODE}} \ -d "address[country]"={{COUNTRY}} \ -d "tax[validate_location]"=immediately ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer = client.v1.customers.update( '{{CUSTOMER_ID}}', { address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: {validate_location: 'immediately'}, }, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer = client.v1.customers.update( "{{CUSTOMER_ID}}", { "address": { "line1": "{{LINE1}}", "line2": "{{LINE2}}", "city": "{{CITY}}", "state": "{{STATE}}", "postal_code": "{{POSTAL_CODE}}", "country": "{{COUNTRY}}", }, "tax": {"validate_location": "immediately"}, }, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $customer = $stripe->customers->update( '{{CUSTOMER_ID}}', [ 'address' => [ 'line1' => '{{LINE1}}', 'line2' => '{{LINE2}}', 'city' => '{{CITY}}', 'state' => '{{STATE}}', 'postal_code' => '{{POSTAL_CODE}}', 'country' => '{{COUNTRY}}', ], 'tax' => ['validate_location' => 'immediately'], ] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CustomerUpdateParams params = CustomerUpdateParams.builder() .setAddress( CustomerUpdateParams.Address.builder() .setLine1("{{LINE1}}") .setLine2("{{LINE2}}") .setCity("{{CITY}}") .setState("{{STATE}}") .setPostalCode("{{POSTAL_CODE}}") .setCountry("{{COUNTRY}}") .build() ) .setTax( CustomerUpdateParams.Tax.builder() .setValidateLocation(CustomerUpdateParams.Tax.ValidateLocation.IMMEDIATELY) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Customer customer = client.v1().customers().update("{{CUSTOMER_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const customer = await stripe.customers.update( '{{CUSTOMER_ID}}', { address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: { validate_location: 'immediately', }, } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerUpdateParams{ Address: &stripe.AddressParams{ Line1: stripe.String("{{LINE1}}"), Line2: stripe.String("{{LINE2}}"), City: stripe.String("{{CITY}}"), State: stripe.String("{{STATE}}"), PostalCode: stripe.String("{{POSTAL_CODE}}"), Country: stripe.String("{{COUNTRY}}"), }, Tax: &stripe.CustomerUpdateTaxParams{ValidateLocation: stripe.String("immediately")}, } result, err := sc.V1Customers.Update(context.TODO(), "{{CUSTOMER_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CustomerUpdateOptions { Address = new AddressOptions { Line1 = "{{LINE1}}", Line2 = "{{LINE2}}", City = "{{CITY}}", State = "{{STATE}}", PostalCode = "{{POSTAL_CODE}}", Country = "{{COUNTRY}}", }, Tax = new CustomerTaxOptions { ValidateLocation = "immediately" }, }; var client = new StripeClient("<>"); var service = client.V1.Customers; Customer customer = service.Update("{{CUSTOMER_ID}}", options); ``` > If your customer has other existing subscriptions with automatic tax enabled and you update their address information, the tax and total amounts on their future invoices might be different. This is because tax rates vary depending on customer location. #### Create customer ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ -d "address[line1]"={{LINE1}} \ -d "address[line2]"={{LINE2}} \ -d "address[city]"={{CITY}} \ -d "address[state]"={{STATE}} \ -d "address[postal_code]"={{POSTAL_CODE}} \ -d "address[country]"={{COUNTRY}} \ -d "tax[validate_location]"=immediately ``` ```cli stripe customers create \ -d "address[line1]"={{LINE1}} \ -d "address[line2]"={{LINE2}} \ -d "address[city]"={{CITY}} \ -d "address[state]"={{STATE}} \ -d "address[postal_code]"={{POSTAL_CODE}} \ -d "address[country]"={{COUNTRY}} \ -d "tax[validate_location]"=immediately ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer = client.v1.customers.create({ address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: {validate_location: 'immediately'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer = client.v1.customers.create({ "address": { "line1": "{{LINE1}}", "line2": "{{LINE2}}", "city": "{{CITY}}", "state": "{{STATE}}", "postal_code": "{{POSTAL_CODE}}", "country": "{{COUNTRY}}", }, "tax": {"validate_location": "immediately"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $customer = $stripe->customers->create([ 'address' => [ 'line1' => '{{LINE1}}', 'line2' => '{{LINE2}}', 'city' => '{{CITY}}', 'state' => '{{STATE}}', 'postal_code' => '{{POSTAL_CODE}}', 'country' => '{{COUNTRY}}', ], 'tax' => ['validate_location' => 'immediately'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CustomerCreateParams params = CustomerCreateParams.builder() .setAddress( CustomerCreateParams.Address.builder() .setLine1("{{LINE1}}") .setLine2("{{LINE2}}") .setCity("{{CITY}}") .setState("{{STATE}}") .setPostalCode("{{POSTAL_CODE}}") .setCountry("{{COUNTRY}}") .build() ) .setTax( CustomerCreateParams.Tax.builder() .setValidateLocation(CustomerCreateParams.Tax.ValidateLocation.IMMEDIATELY) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Customer customer = client.v1().customers().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const customer = await stripe.customers.create({ address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: { validate_location: 'immediately', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerCreateParams{ Address: &stripe.AddressParams{ Line1: stripe.String("{{LINE1}}"), Line2: stripe.String("{{LINE2}}"), City: stripe.String("{{CITY}}"), State: stripe.String("{{STATE}}"), PostalCode: stripe.String("{{POSTAL_CODE}}"), Country: stripe.String("{{COUNTRY}}"), }, Tax: &stripe.CustomerCreateTaxParams{ValidateLocation: stripe.String("immediately")}, } result, err := sc.V1Customers.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CustomerCreateOptions { Address = new AddressOptions { Line1 = "{{LINE1}}", Line2 = "{{LINE2}}", City = "{{CITY}}", State = "{{STATE}}", PostalCode = "{{POSTAL_CODE}}", Country = "{{COUNTRY}}", }, Tax = new CustomerTaxOptions { ValidateLocation = "immediately" }, }; var client = new StripeClient("<>"); var service = client.V1.Customers; Customer customer = service.Create(options); ``` The [tax.validate_location](https://docs.stripe.com/api/customers/update.md#update_customer-tax-validate_location) enum value helps you make sure that the tax location of the customer becomes (or remains) valid as a result of this operation. If not, Stripe fails your request with the [customer_tax_location_invalid](https://docs.stripe.com/error-codes.md#customer-tax-location-invalid) error code. This is important because you can’t create an automatic tax enabled subscription for a customer with an invalid tax location. If you’ve been checking the [automatic_tax.status](https://docs.stripe.com/api/invoices/object.md#invoice_object-automatic_tax-status) of your preview invoices as [advised](https://docs.stripe.com/billing/taxes/collect-taxes.md#estimate-taxes-total) previously, this additional validation won’t ever fail. However, it’s good practice to set `tax[validate_location]="immediately"` whenever you’re creating or updating a `Customer` object. ## Create subscription [Server-side] [Create](https://docs.stripe.com/api/subscriptions/create.md) a subscription with automatic tax enabled. ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d "automatic_tax[enabled]"=true \ -d customer="{{CUSTOMER_ID}}" \ -d "items[0][price]"="{{PRICE_ID}}" \ -d "payment_settings[save_default_payment_method]"=on_subscription \ -d "expand[0]"="latest_invoice.confirmation_secret" ``` ```cli stripe subscriptions create \ -d "automatic_tax[enabled]"=true \ --customer="{{CUSTOMER_ID}}" \ -d "items[0][price]"="{{PRICE_ID}}" \ -d "payment_settings[save_default_payment_method]"=on_subscription \ -d "expand[0]"="latest_invoice.confirmation_secret" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.create({ automatic_tax: {enabled: true}, customer: '{{CUSTOMER_ID}}', items: [{price: '{{PRICE_ID}}'}], payment_settings: {save_default_payment_method: 'on_subscription'}, expand: ['latest_invoice.confirmation_secret'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.create({ "automatic_tax": {"enabled": True}, "customer": "{{CUSTOMER_ID}}", "items": [{"price": "{{PRICE_ID}}"}], "payment_settings": {"save_default_payment_method": "on_subscription"}, "expand": ["latest_invoice.confirmation_secret"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->create([ 'automatic_tax' => ['enabled' => true], 'customer' => '{{CUSTOMER_ID}}', 'items' => [['price' => '{{PRICE_ID}}']], 'payment_settings' => ['save_default_payment_method' => 'on_subscription'], 'expand' => ['latest_invoice.confirmation_secret'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionCreateParams params = SubscriptionCreateParams.builder() .setAutomaticTax( SubscriptionCreateParams.AutomaticTax.builder().setEnabled(true).build() ) .setCustomer("{{CUSTOMER_ID}}") .addItem( SubscriptionCreateParams.Item.builder().setPrice("{{PRICE_ID}}").build() ) .setPaymentSettings( SubscriptionCreateParams.PaymentSettings.builder() .setSaveDefaultPaymentMethod( SubscriptionCreateParams.PaymentSettings.SaveDefaultPaymentMethod.ON_SUBSCRIPTION ) .build() ) .addExpand("latest_invoice.confirmation_secret") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.create({ automatic_tax: { enabled: true, }, customer: '{{CUSTOMER_ID}}', items: [ { price: '{{PRICE_ID}}', }, ], payment_settings: { save_default_payment_method: 'on_subscription', }, expand: ['latest_invoice.confirmation_secret'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionCreateParams{ AutomaticTax: &stripe.SubscriptionCreateAutomaticTaxParams{Enabled: stripe.Bool(true)}, Customer: stripe.String("{{CUSTOMER_ID}}"), Items: []*stripe.SubscriptionCreateItemParams{ &stripe.SubscriptionCreateItemParams{Price: stripe.String("{{PRICE_ID}}")}, }, PaymentSettings: &stripe.SubscriptionCreatePaymentSettingsParams{ SaveDefaultPaymentMethod: stripe.String(stripe.SubscriptionPaymentSettingsSaveDefaultPaymentMethodOnSubscription), }, } params.AddExpand("latest_invoice.confirmation_secret") result, err := sc.V1Subscriptions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionCreateOptions { AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true }, Customer = "{{CUSTOMER_ID}}", Items = new List { new SubscriptionItemOptions { Price = "{{PRICE_ID}}" }, }, PaymentSettings = new SubscriptionPaymentSettingsOptions { SaveDefaultPaymentMethod = "on_subscription", }, Expand = new List { "latest_invoice.confirmation_secret" }, }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Create(options); ``` The [latest_invoice.confirmation_secret.client_secret](https://docs.stripe.com/api/invoices/object.md#invoice_object-confirmation_secret-client_secrett) is the *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)) of the *payment intent* (API object that represents your intent to collect payment from a customer, tracking charge attempts and payment state changes throughout the process) of the first (and the latest) invoice of the new subscription. You need to pass the client secret to your front end to be able to *confirm* (Confirming a PaymentIntent indicates that the customer intends to pay with the current or provided payment method. Upon confirmation, the PaymentIntent attempts to initiate a payment) the payment intent. > Don’t store, log, or expose the client secret to anyone other than the customer. Make sure that you have TLS enabled on any page that includes the client secret. If your customer has a default payment method, the first invoice of the subscription is paid automatically. You can confirm this using [latest_invoice.status](https://docs.stripe.com/api/invoices/object.md#invoice_object-status) of the subscription. If you want to use the new payment details you collected from your customer in your checkout flow, make sure that the first invoice isn’t paid automatically. Pass `default_incomplete` for the [payment_behavior](https://docs.stripe.com/api/subscriptions/create.md#create_subscription-payment_behavior) when you’re creating your subscription and confirm the payment intent using [stripe.confirmPayment()](https://docs.stripe.com/js/payment_intents/confirm_payment) as shown. See [Billing collection methods](https://docs.stripe.com/billing/collection-method.md) for more information. ## Optional: Update your products and prices Stripe Tax uses information stored on *products* (Products represent what your business sells—whether that's a good or a service) and *prices* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) to calculate tax, such as *tax code* (A tax code is the category of your product for tax purposes) and *tax behavior* (Tax behavior determines whether you want to include taxes in the price ("inclusive") or add them on top ("exclusive")). If you don’t explicitly specify these configurations, Stripe Tax will use the default tax code selected in [Tax Settings](https://dashboard.stripe.com/settings/tax). For more information, see [Specify product tax codes and tax behavior](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md). ## Optional: Handle refunds [Server-side] When you create a refund for an Invoice payment, Stripe Tax automatically reduces your tax liability. Alternatively, you can issue [Credit Notes](https://docs.stripe.com/api/credit_notes/object.md) to track tax liability decreases and provide records to your customers. #### Refund invoice amount To refund an amount associated with an invoice total, create a Credit Note and a Refund. #### Credit Note with automatic Refund Create a Credit Note and a [Refund](https://docs.stripe.com/api/refunds/object.md) together by calling [create Credit Note](https://docs.stripe.com/api/credit_notes/create.md) and providing a `refund_amount` value. ```curl curl https://api.stripe.com/v1/credit_notes \ -u "<>:" \ -d invoice="{{INVOICE_ID}}" \ -d refund_amount=1000 ``` ```cli stripe credit_notes create \ --invoice="{{INVOICE_ID}}" \ --refund-amount=1000 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") credit_note = client.v1.credit_notes.create({ invoice: '{{INVOICE_ID}}', refund_amount: 1000, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. credit_note = client.v1.credit_notes.create({ "invoice": "{{INVOICE_ID}}", "refund_amount": 1000, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $creditNote = $stripe->creditNotes->create([ 'invoice' => '{{INVOICE_ID}}', 'refund_amount' => 1000, ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CreditNoteCreateParams params = CreditNoteCreateParams.builder() .setInvoice("{{INVOICE_ID}}") .setRefundAmount(1000L) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. CreditNote creditNote = client.v1().creditNotes().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const creditNote = await stripe.creditNotes.create({ invoice: '{{INVOICE_ID}}', refund_amount: 1000, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CreditNoteCreateParams{ Invoice: stripe.String("{{INVOICE_ID}}"), RefundAmount: stripe.Int64(1000), } result, err := sc.V1CreditNotes.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CreditNoteCreateOptions { Invoice = "{{INVOICE_ID}}", RefundAmount = 1000, }; var client = new StripeClient("<>"); var service = client.V1.CreditNotes; CreditNote creditNote = service.Create(options); ``` #### Credit Note with manual Refund [Create a Refund](https://docs.stripe.com/api/refunds/create.md), then include its ID when you create a [Credit Note](https://docs.stripe.com/api/credit_notes/object.md). In this case, don’t include a `refund_amount` value. ```curl curl https://api.stripe.com/v1/credit_notes \ -u "<>:" \ -d invoice="{{INVOICE_ID}}" \ -d refund="{{REFUND_ID}}" \ -d amount=1000 ``` Stripe Tax automatically distributes the total refund amount between taxes and the net amount. #### Refund invoice line item amount If you want to refund an amount associated with an invoice line item, first calculate the [total](https://docs.stripe.com/api/credit_notes/object.md#credit_note_object-total) and [total_excluding_tax](https://docs.stripe.com/api/credit_notes/object.md#credit_note_object-total_excluding_tax) amounts by calling [preview Credit Note](https://docs.stripe.com/api/credit_notes/preview.md). ```curl curl -G https://api.stripe.com/v1/credit_notes/preview \ -u "<>:" \ -d invoice="{{INVOICE_ID}}" \ -d "lines[0][type]"=invoice_line_item \ --data-urlencode "lines[0][invoice_line_item]"="{{line item id from invoice}}" \ -d "lines[0][amount]"=1000 ``` ```cli stripe credit_notes preview \ --invoice="{{INVOICE_ID}}" \ -d "lines[0][type]"=invoice_line_item \ -d "lines[0][invoice_line_item]"="{{line item id from invoice}}" \ -d "lines[0][amount]"=1000 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") credit_note = client.v1.credit_notes.preview({ invoice: '{{INVOICE_ID}}', lines: [ { type: 'invoice_line_item', invoice_line_item: '{{line item id from invoice}}', amount: 1000, }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. credit_note = client.v1.credit_notes.preview({ "invoice": "{{INVOICE_ID}}", "lines": [ { "type": "invoice_line_item", "invoice_line_item": "{{line item id from invoice}}", "amount": 1000, }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $creditNote = $stripe->creditNotes->preview([ 'invoice' => '{{INVOICE_ID}}', 'lines' => [ [ 'type' => 'invoice_line_item', 'invoice_line_item' => '{{line item id from invoice}}', 'amount' => 1000, ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CreditNotePreviewParams params = CreditNotePreviewParams.builder() .setInvoice("{{INVOICE_ID}}") .addLine( CreditNotePreviewParams.Line.builder() .setType(CreditNotePreviewParams.Line.Type.INVOICE_LINE_ITEM) .setInvoiceLineItem("{{line item id from invoice}}") .setAmount(1000L) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. CreditNote creditNote = client.v1().creditNotes().preview(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const creditNote = await stripe.creditNotes.preview({ invoice: '{{INVOICE_ID}}', lines: [ { type: 'invoice_line_item', invoice_line_item: '{{line item id from invoice}}', amount: 1000, }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CreditNotePreviewParams{ Invoice: stripe.String("{{INVOICE_ID}}"), Lines: []*stripe.CreditNotePreviewLineParams{ &stripe.CreditNotePreviewLineParams{ Type: stripe.String("invoice_line_item"), InvoiceLineItem: stripe.String("{{line item id from invoice}}"), Amount: stripe.Int64(1000), }, }, } result, err := sc.V1CreditNotes.Preview(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CreditNotePreviewOptions { Invoice = "{{INVOICE_ID}}", Lines = new List { new CreditNoteLineOptions { Type = "invoice_line_item", InvoiceLineItem = "{{line item id from invoice}}", Amount = 1000, }, }, }; var client = new StripeClient("<>"); var service = client.V1.CreditNotes; CreditNote creditNote = service.Preview(options); ``` Then, create a [Credit Note](https://docs.stripe.com/api/credit_notes/object.md) and a [Refund](https://docs.stripe.com/api/refunds/object.md). #### Credit Note with automatic Refund Create a Credit Note and a [Refund](https://docs.stripe.com/api/refunds/object.md) together by calling [create Credit Note](https://docs.stripe.com/api/credit_notes/create.md) and providing a `refund_amount` value. ```curl curl https://api.stripe.com/v1/credit_notes \ -u "<>:" \ -d invoice="{{INVOICE_ID}}" \ -d refund_amount=1000 \ -d "lines[0][type]"=invoice_line_item \ -d "lines[0][invoice_line_item]"="{{line item id from invoice}}" \ -d "lines[0][amount]"=1000 ``` #### Credit Note with manual Refund [Create a Refund](https://docs.stripe.com/api/refunds/create.md) using the `total` calculated by the Credit Note preview, then include its ID when you create a [Credit Note](https://docs.stripe.com/api/credit_notes/object.md). In this case, don’t include a `refund_amount` value. ```curl curl https://api.stripe.com/v1/credit_notes \ -u "<>:" \ -d invoice="{{INVOICE_ID}}" \ -d refund="{{REFUND_ID}}" \ -d "lines[0][type]"=invoice_line_item \ -d "lines[0][invoice_line_item]"="{{line item id from invoice}}" \ -d "lines[0][amount]"=1000 ``` ## Use webhooks We recommend listening to subscription events with *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) because most subscription activity happens asynchronously. When you start using Stripe Tax, make sure to listen to [invoice.finalization_failed](https://docs.stripe.com/api/events/types.md#event_types-invoice.finalization_failed) events. If the [automatic_tax.status](https://docs.stripe.com/api/invoices/object.md#invoice_object-automatic_tax-status) of the invoice is `requires_location_inputs`, it means that the address details of your customer are invalid or insufficient. In this case, Stripe can’t calculate the taxes, can’t finalize the invoice, and can’t collect the payment. Notify your customer to re-enter their address details or provide an accurate address. See [Using webhooks with subscriptions](https://docs.stripe.com/billing/subscriptions/webhooks.md) to learn more. # Tax Rates > This is a Tax Rates for when tax-calculation is tax-rates. View the full page at https://docs.stripe.com/billing/taxes/collect-taxes?tax-calculation=tax-rates. To collect taxes on a subscription, set [tax rates on the subscription](https://docs.stripe.com/billing/taxes/collect-taxes.md#static-configuration) or [set the tax rates on invoices as the subscription renews](https://docs.stripe.com/billing/taxes/collect-taxes.md#dynamic-configuration). Or, if you use Checkout, you can [specify tax rates in Checkout Sessions](https://docs.stripe.com/billing/taxes/collect-taxes.md#adding-tax-rates-to-checkout) to apply taxes to subscriptions. ## Set tax rates on a subscription (Recommended) Subscriptions create draft invoices that stay editable for about an hour. During this time, you can correct the tax rates using the steps outlined below. You can apply taxes at the subscription level and the subscription item level and set up to [five tax rates](https://docs.stripe.com/billing/taxes/tax-rates.md#using-multiple-tax-rates) on each subscription item. When invoices are generated for subscriptions, tax rates are copied from the subscription to the invoice. In the example below, the first subscription item has two tax rates: 3% and 5%, which overrides the 1% from the subscription level tax rate. The second item doesn’t have any tax rates set directly on it, so the 1% from the subscription level tax rate is automatically applied. | Subscription item 1 | 3% and 5% | ➡️ | Invoice item 1 | 3% and 5% | | ------------------- | ------------ | -- | -------------- | ------------ | | Subscription item 2 | (no tax set) | ➡️ | Invoice item 2 | (no tax set) | | Subscription | 1% | ➡️ | Invoice | 1% | You can set tax rates when you create or update subscription items by passing the [tax rate IDs](https://docs.stripe.com/api/subscription_items/object.md#subscription_item_object-tax_rates-id). The example below updates an existing subscription item with two tax rates: ```curl curl https://api.stripe.com/v1/subscription_items/si_F2yjdxUlCCOAtv \ -u "<>:" \ -d "tax_rates[]"=txr_1F6kmAAJVYItwOKqV9IWehUH \ -d "tax_rates[]"=txr_2J8lmBBGHJYyuUJqF6QJtkNM ``` ```cli stripe subscription_items update si_F2yjdxUlCCOAtv \ -d "tax_rates[0]"=txr_1F6kmAAJVYItwOKqV9IWehUH \ -d "tax_rates[1]"=txr_2J8lmBBGHJYyuUJqF6QJtkNM ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription_item = client.v1.subscription_items.update( 'si_F2yjdxUlCCOAtv', {tax_rates: ['txr_1F6kmAAJVYItwOKqV9IWehUH', 'txr_2J8lmBBGHJYyuUJqF6QJtkNM']}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription_item = client.v1.subscription_items.update( "si_F2yjdxUlCCOAtv", {"tax_rates": ["txr_1F6kmAAJVYItwOKqV9IWehUH", "txr_2J8lmBBGHJYyuUJqF6QJtkNM"]}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscriptionItem = $stripe->subscriptionItems->update( 'si_F2yjdxUlCCOAtv', ['tax_rates' => ['txr_1F6kmAAJVYItwOKqV9IWehUH', 'txr_2J8lmBBGHJYyuUJqF6QJtkNM']] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionItemUpdateParams params = SubscriptionItemUpdateParams.builder() .addTaxRate("txr_1F6kmAAJVYItwOKqV9IWehUH") .addTaxRate("txr_2J8lmBBGHJYyuUJqF6QJtkNM") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. SubscriptionItem subscriptionItem = client.v1().subscriptionItems().update("si_F2yjdxUlCCOAtv", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscriptionItem = await stripe.subscriptionItems.update( 'si_F2yjdxUlCCOAtv', { tax_rates: ['txr_1F6kmAAJVYItwOKqV9IWehUH', 'txr_2J8lmBBGHJYyuUJqF6QJtkNM'], } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionItemUpdateParams{ TaxRates: []*string{ stripe.String("txr_1F6kmAAJVYItwOKqV9IWehUH"), stripe.String("txr_2J8lmBBGHJYyuUJqF6QJtkNM"), }, } result, err := sc.V1SubscriptionItems.Update(context.TODO(), "si_F2yjdxUlCCOAtv", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionItemUpdateOptions { TaxRates = new List { "txr_1F6kmAAJVYItwOKqV9IWehUH", "txr_2J8lmBBGHJYyuUJqF6QJtkNM", }, }; var client = new StripeClient("<>"); var service = client.V1.SubscriptionItems; SubscriptionItem subscriptionItem = service.Update("si_F2yjdxUlCCOAtv", options); ``` You can set subscription level tax rates when you create or update subscriptions. Set the tax rates you want to apply by passing the [default tax rate IDs](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-default_tax_rates). The example below updates an existing subscription with two tax rates: ```curl curl https://api.stripe.com/v1/subscriptions/sub_BVxXIrxAAYb7Fb \ -u "<>:" \ -d "default_tax_rates[]"=txr_1EO66sClCIKljWvs98IiVfHW \ -d "default_tax_rates[]"=txr_1EEOvcClCIKljWvsqYb9U0MB ``` ```cli stripe subscriptions update sub_BVxXIrxAAYb7Fb \ -d "default_tax_rates[0]"=txr_1EO66sClCIKljWvs98IiVfHW \ -d "default_tax_rates[1]"=txr_1EEOvcClCIKljWvsqYb9U0MB ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.update( 'sub_BVxXIrxAAYb7Fb', {default_tax_rates: ['txr_1EO66sClCIKljWvs98IiVfHW', 'txr_1EEOvcClCIKljWvsqYb9U0MB']}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.update( "sub_BVxXIrxAAYb7Fb", {"default_tax_rates": ["txr_1EO66sClCIKljWvs98IiVfHW", "txr_1EEOvcClCIKljWvsqYb9U0MB"]}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->update( 'sub_BVxXIrxAAYb7Fb', [ 'default_tax_rates' => [ 'txr_1EO66sClCIKljWvs98IiVfHW', 'txr_1EEOvcClCIKljWvsqYb9U0MB', ], ] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionUpdateParams params = SubscriptionUpdateParams.builder() .addDefaultTaxRate("txr_1EO66sClCIKljWvs98IiVfHW") .addDefaultTaxRate("txr_1EEOvcClCIKljWvsqYb9U0MB") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().update("sub_BVxXIrxAAYb7Fb", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.update( 'sub_BVxXIrxAAYb7Fb', { default_tax_rates: ['txr_1EO66sClCIKljWvs98IiVfHW', 'txr_1EEOvcClCIKljWvsqYb9U0MB'], } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionUpdateParams{ DefaultTaxRates: []*string{ stripe.String("txr_1EO66sClCIKljWvs98IiVfHW"), stripe.String("txr_1EEOvcClCIKljWvsqYb9U0MB"), }, } result, err := sc.V1Subscriptions.Update(context.TODO(), "sub_BVxXIrxAAYb7Fb", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionUpdateOptions { DefaultTaxRates = new List { "txr_1EO66sClCIKljWvs98IiVfHW", "txr_1EEOvcClCIKljWvsqYb9U0MB", }, }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Update("sub_BVxXIrxAAYb7Fb", options); ``` ## Dynamically configure tax rates on each subscription service period If you add [extra invoice items](https://docs.stripe.com/billing/invoices/subscription.md#adding-upcoming-invoice-items), or sell in enough jurisdictions that tax rates change frequently, you can dynamically calculate and assign tax rates to the subscription’s invoice as it’s created. When a subscription renews and creates an invoice, Stripe sends the `invoice.created` *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) event. Stripe [waits approximately one hour](https://docs.stripe.com/billing/subscriptions/webhooks.md#understand) before finalizing the invoice and attempting payment or sending an email. During that delay, the invoice is a [draft](https://docs.stripe.com/api/invoices/object.md#invoice_object-status) and can be edited. Follow the process to [assign tax rates](https://docs.stripe.com/invoicing/taxes/tax-rates.md) to that invoice. If you have credit [prorations](https://docs.stripe.com/billing/subscriptions/prorations.md), use the `proration_details` parameter in the [(Invoice) Line Item](https://docs.stripe.com/api/invoices/line_item.md) object to reference to the original debit line items that the credit proration applies to. Use this reference to adjust the tax amounts correctly for credit prorations. ## Add tax rates to Checkout You can specify [tax rates](https://docs.stripe.com/billing/taxes/tax-rates.md) (Sales, VAT, GST, and others) in Checkout Sessions to apply taxes to *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis). - Use fixed tax rates when you know the exact tax rate to charge your customers before they start the checkout process (for example, you only sell to customers in the UK and always charge 20% VAT). - With the *Prices* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) API, you can use dynamic tax rates when you require more information from your customer (for example, their billing or shipping address) before determining the tax rate to charge. With dynamic tax rates, you create tax rates for different regions (for example, a 20% VAT tax rate for customers in the UK and a 7.25% sales tax rate for customers in California, US) and Stripe attempts to match your customer’s location to one of those tax rates. #### Fixed tax rates Set [subscription_data.default_tax_rates](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-subscription_data-default_tax_rates) to apply a default tax rate to a subscription started with Checkout. #### curl ```bash curl https://api.stripe.com/v1/checkout/sessions \ -u <>: \ -d "payment_method_types[]"=card \ -d "line_items[][price]"="{{PRICE_ID}}" \ -d "line_items[][quantity]"=1 \-d "subscription_data[default_tax_rates][]"="{{TAX_RATE_ID}}" \ -d mode=subscription \ -d success_url="https://example.com/success" \ ``` #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' session = Stripe::Checkout::Session.create( payment_method_types: ['card'], line_items: [{ price: '{{PRICE_ID}}', quantity: 1 }], subscription_data: {default_tax_rates: ['{{TAX_RATE_ID}}'], }, mode: 'subscription', success_url: 'https://example.com/success', ) ``` #### Python ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' session = stripe.checkout.Session.create( payment_method_types=['card'], line_items=[{ 'price': '{{PRICE_ID}}', 'quantity': 1 }], subscription_data={'default_tax_rates': ['{{TAX_RATE_ID}}'], }, mode='subscription', success_url='https://example.com/success', ) ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('<>'); $session = \Stripe\Checkout\Session::create([ 'payment_method_types' => ['card'], 'line_items' => [[ 'price' => '{{PRICE_ID}}', 'quantity' => 1 ]], 'subscription_data' => ['default_tax_rates' => ['{{TAX_RATE_ID}}'], ], 'mode' => 'subscription', 'success_url' => 'https://example.com/success' ]); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; SessionCreateParams params = SessionCreateParams.builder() .addPaymentMethodType(SessionCreateParams.PaymentMethodType.CARD) .setMode(SessionCreateParams.Mode.SUBSCRIPTION) .setSuccessUrl("https://example.com/success") .addLineItem( SessionCreateParams.LineItem.builder() .setQuantity(1L) .setPrice(""{{PRICE_ID}}"") .build()).setSubscriptionData( SessionCreateParams.SubscriptionData.builder() .addDefaultTaxRate("{{TAX_RATE_ID}}") .build()) .build(); Session session = Session.create(params); ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ payment_method_types: ['card'], subscription_data: {default_tax_rates: ['{{TAX_RATE_ID}}'], }, line_items: [{ price: '{{PRICE_ID}}', quantity: 1 }], mode: 'subscription', success_url: 'https://example.com/success' }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" params := &stripe.CheckoutSessionParams{ PaymentMethodTypes: stripe.StringSlice([]string{ "card" }), SubscriptionData: &stripe.CheckoutSessionSubscriptionDataParams{DefaultTaxRates: stripe.StringSlice([]string{ "{{TAX_RATE_ID}}" }), }, LineItems: []*stripe.CheckoutSessionLineItemParams{ &stripe.CheckoutSessionLineItemParams{ Price: stripe.String(""{{PRICE_ID}}""), Quantity: stripe.Int64(1) } }, Mode: stripe.String("subscription"), SuccessURL: stripe.String("https://example.com/success"), } session, err := session.New(params) ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; var options = new SessionCreateOptions { PaymentMethodTypes = new List { "card" }, SubscriptionData = new SessionSubscriptionDataOptions {DefaultTaxRates = new List { "{{TAX_RATE_ID}}" }, }, LineItems = new List { new SessionLineItemOptions { Price = ""{{PRICE_ID}}"", Quantity = 1 } }, Mode = "subscription", SuccessUrl = "https://example.com/success", }; var service = new SessionService(); Session session = service.Create(options); ``` You can also specify [line_items.tax_rates](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-tax_rates) or [subscription_data.items.tax_rates](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-subscription_data-items-tax_rates) to apply tax rates to specific plans or invoice line items. #### curl ```bash curl https://api.stripe.com/v1/checkout/sessions \ -u <>: \ -d "payment_method_types[]"="card" \ -d "line_items[][price]"="{{PRICE_ID}}" \ -d "line_items[][quantity]"=1 \-d "line_items[][tax_rates][0]"="{{TAX_RATE_ID}}" \ -d "mode"="subscription" \ -d "success_url"="https://example.com/success" \ ``` #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' session = Stripe::Checkout::Session.create( payment_method_types: ['card'], line_items: [{ price: '{{PRICE_ID}}', quantity: 1,tax_rates: [ '{{TAX_RATE_ID}}' ], }], mode: 'subscription', success_url: 'https://example.com/success', ) ``` #### Python ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' session = stripe.checkout.Session.create( payment_method_types=['card'], line_items=[{ 'price': '{{PRICE_ID}}', 'quantity': 1,'tax_rates': [ '{{TAX_RATE_ID}}' ], }], mode='subscription', success_url='https://example.com/success', ) ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('<>'); $session = \Stripe\Checkout\Session::create([ 'payment_method_types' => ['card'], 'line_items' => [[ 'price' => '{{PRICE_ID}}', 'quantity' => 1,'tax_rates' => [ '{{TAX_RATE_ID}}' ], ]], 'mode' => 'subscription', 'success_url' => 'https://example.com/success' ]); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; SessionCreateParams params = SessionCreateParams.builder() .addPaymentMethodType(SessionCreateParams.PaymentMethodType.CARD) .setMode(SessionCreateParams.Mode.SUBSCRIPTION) .setSuccessUrl("https://example.com/success") .addLineItem( SessionCreateParams.LineItem.builder() .setQuantity(1L) .setPrice(""{{PRICE_ID}}"").addTaxRate("{{TAX_RATE_ID}}") .build()) .build(); Session session = Session.create(params); ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ payment_method_types: ['card'], line_items: [{ price: '{{PRICE_ID}}', quantity: 1,tax_rates: [ '{{TAX_RATE_ID}}' ], }], mode: 'subscription', success_url: 'https://example.com/success' }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" params := &stripe.CheckoutSessionParams{ PaymentMethodTypes: stripe.StringSlice([]string{ "card" }), LineItems: []*stripe.CheckoutSessionLineItemParams{ &stripe.CheckoutSessionLineItemParams{ Price: stripe.String(""{{PRICE_ID}}""), Quantity: stripe.Int64(1),TaxRates: stripe.StringSlice([]string{ "{{TAX_RATE_ID}}" }), } }, Mode: stripe.String("subscription"), SuccessURL: stripe.String("https://example.com/success"), } session, err := session.New(params) ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; var options = new SessionCreateOptions { PaymentMethodTypes = new List { "card" }, LineItems = new List { new SessionLineItemOptions { Price = ""{{PRICE_ID}}"", Quantity = 1,TaxRates = new List { "{{TAX_RATE_ID}}" }, } }, Mode = "subscription", SuccessUrl = "https://example.com/success", }; var service = new SessionService(); Session session = service.Create(options); ``` #### Dynamic tax rates Pass an array of [tax rates](https://docs.stripe.com/api/tax_rates/object.md) to [line_items.dynamic_tax_rates](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-dynamic_tax_rates). Each tax rate must have a [supported](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-dynamic_tax_rates) `country`, and for the US, a `state`. This list matches tax rates to your customer’s [shipping address](https://docs.stripe.com/payments/collect-addresses.md), billing address, or country. The shipping address takes precedence over the billing address for determining the tax rate to charge. If you’re not collecting shipping or billing addresses, your customer’s country (and postal code where applicable) is used to determine the tax rate. If you haven’t passed a tax rate that matches your customer’s shipping address, billing address, or country, no tax rate is applied. #### curl ```bash curl https://api.stripe.com/v1/checkout/sessions \ -u <>: \ -d "payment_method_types[]"="card" \ -d "line_items[][price]"="{{PRICE_ID}}" \ -d "line_items[][quantity]"=1 \-d "line_items[][dynamic_tax_rates][]"="{{FIRST_TAX_RATE_ID}}" \ -d "line_items[][dynamic_tax_rates][]"="{{SECOND_TAX_RATE_ID}}" \ -d "mode"="subscription" \ -d "success_url"="https://example.com/success" \ ``` #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' session = Stripe::Checkout::Session.create( payment_method_types: ['card'], line_items: [{ price: '{{PRICE_ID}}', quantity: 1,dynamic_tax_rates: [ '{{FIRST_TAX_RATE_ID}}', '{{SECOND_TAX_RATE_ID}}', # additional tax rates ], }], mode: 'subscription', success_url: 'https://example.com/success', ) ``` #### Python ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' session = stripe.checkout.Session.create( payment_method_types=['card'], line_items=[{ 'price': '{{PRICE_ID}}', 'quantity': 1,'dynamic_tax_rates': [ '{{FIRST_TAX_RATE_ID}}', '{{SECOND_TAX_RATE_ID}}', # additional tax rates ], }], mode='subscription', success_url='https://example.com/success', ) ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('<>'); $session = \Stripe\Checkout\Session::create([ 'payment_method_types' => ['card'], 'line_items' => [[ 'price' => '{{PRICE_ID}}', 'quantity' => 1,'dynamic_tax_rates' => [ '{{FIRST_TAX_RATE_ID}}', '{{SECOND_TAX_RATE_ID}}', // additional tax rates ], ]], 'mode' => 'subscription', 'success_url' => 'https://example.com/success' ]); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; Map params = new HashMap(); ArrayList paymentMethodTypes = new ArrayList<>(); paymentMethodTypes.add("card"); params.put("payment_method_types", paymentMethodTypes); ArrayList> lineItems = new ArrayList<>(); HashMap lineItem = new HashMap(); lineItem.put("price", ""{{PRICE_ID}}""); lineItem.put("quantity", 1); ArrayList taxRates = new ArrayList<>(); taxRates.add("{{FIRST_TAX_RATE_ID}}"); taxRates.add("{{SECOND_TAX_RATE_ID}}"); // additional tax rates lineItem.put("dynamic_tax_rates", taxRates); lineItems.add(lineItem); params.put("line_items", lineItems); params.put("mode", "subscription"); params.put("success_url", "https://example.com/success"); Session session = Session.create(params); ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ payment_method_types: ['card'], line_items: [{ price: '{{PRICE_ID}}', quantity: 1,dynamic_tax_rates: [ '{{FIRST_TAX_RATE_ID}}', '{{SECOND_TAX_RATE_ID}}', // additional tax rates ], }], mode: 'subscription', success_url: 'https://example.com/success' }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" params := &stripe.CheckoutSessionParams{ PaymentMethodTypes: stripe.StringSlice([]string{ "card" }), LineItems: []*stripe.CheckoutSessionLineItemParams{ &stripe.CheckoutSessionLineItemParams{ Price: stripe.String(""{{PRICE_ID}}""), Quantity: stripe.Int64(1),DynamicTaxRates: stripe.StringSlice([]string{ "{{FIRST_TAX_RATE_ID}}", "{{SECOND_TAX_RATE_ID}}", // additional tax rates }), } }, Mode: stripe.String("subscription"), SuccessURL: stripe.String("https://example.com/success"), } session, err := session.New(params) ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; var options = new SessionCreateOptions { PaymentMethodTypes = new List { "card" }, LineItems = new List { new SessionLineItemOptions { Price = ""{{PRICE_ID}}"", Quantity = 1,DynamicTaxRates = new List { "{{FIRST_TAX_RATE_ID}}", "{{SECOND_TAX_RATE_ID}}", // additional tax rates }, } }, Mode = "subscription", SuccessUrl = "https://example.com/success", }; var service = new SessionService(); Session session = service.Create(options); ``` > [subscription_data.default_tax_rates](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-subscription_data-default_tax_rates) and [line_items.tax_rates](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-tax_rates) can’t be used in combination with [line_items.dynamic_tax_rates](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-dynamic_tax_rates). You can use Stripe’s data exports to populate the periodic reports required for remittance. Visit [Tax reporting and remittance](https://docs.stripe.com/billing/taxes/tax-rates.md#remittance) for more information. ## See also - [Determining customer locations](https://docs.stripe.com/tax/customer-locations.md) - [Customer tax IDs](https://docs.stripe.com/billing/customer/tax-ids.md) - [Reporting and filing](https://docs.stripe.com/tax/reports.md) - [Tax Rates](https://docs.stripe.com/billing/taxes/tax-rates.md) - [Tax Rates on Invoices](https://docs.stripe.com/invoicing/taxes/tax-rates.md) --- # Source: https://docs.stripe.com/climate/commitments.md # Climate Commitments Direct a fraction of your revenue to help advance carbon removal. Help emerging permanent carbon removal technologies scale by allocating a fraction of your revenue to Climate Commitments in the [Dashboard](https://dashboard.stripe.com/setup/climate/activate). Stripe puts these contributions toward projects that remove carbon dioxide (CO2) from the atmosphere to help those projects scale. We select [various projects with the help of scientific expert reviewers](https://stripe.com/climate) and use a [transparent application process](https://github.com/stripe/negative-emissions-source-materials). Following the common pattern of a portfolio approach, some projects might deliver results, and others might fail. To make carbon neutral or net zero claims, use [Climate Orders](https://docs.stripe.com/climate/orders.md). ## Manage and understand your commitment You can manage your contribution percentage and monitor impact in the [Dashboard](https://dashboard.stripe.com/climate). Stripe Climate Commitments also sends you regular updates with details about your contribution. ## Enable Climate Commitments for Connect You can enable Climate Commitments for your platform, without affecting accounts on your platform, in your [Dashboard](https://dashboard.stripe.com/climate). If you take an application fee from your connected accounts, you’ll see this reflected in your percentage-based contributions. For destination charges, we apply the percentage-based contribution to the charge minus the transferred amount. For separate charges and transfers, we apply the percentage-based contribution to the entire charge amount. **For Standard accounts**: - You can allow new Standard account users to enable Climate contributions during onboarding with the [Climate setting in the Dashboard](https://dashboard.stripe.com/settings/connect/climate). This contributes a portion of their revenue towards carbon removal. ![The Stripe Climate onboarding page for connected accounts](https://b.stripecdn.com/docs-statics-srv/assets/ClimateConnectOnboardingPreview.b8ec04318a01e28f3a24b6ffc0381911.png) Optional step shown during Standard account onboarding - Existing Standard accounts can log into their Dashboard to independently enable Climate Commitments. Doing so won’t affect your platform. To inform your Standard connected accounts about Climate Commitments, you can share this direct link to the Climate section of their Dashboard: [https://dashboard.stripe.com/get-started/climate](https://dashboard.stripe.com/get-started/climate). ## Promote your commitment You can demonstrate and explain your commitment to users by doing the following: - Use the [Climate badge](https://dashboard.stripe.com/climate/commitment) on [Stripe Checkout](https://docs.stripe.com/payments/checkout.md), [Invoices](https://docs.stripe.com/invoicing.md), or [Receipts](https://docs.stripe.com/receipts.md?payment-ui=payment-links). - Direct them to your Stripe-hosted custom [webpage](https://dashboard.stripe.com/climate/commitment). - Add an [embeddable badge](https://dashboard.stripe.com/climate/commitment) directly on your website. - Use reference language from the [Stripe Climate](http://stripe.com/climate) page. All Climate Commitments users can publish a custom climate page in a few clicks, create embeddable badges, or download our badge asset kit to add the Climate logo to your site, directly from your [Stripe Dashboard](https://dashboard.stripe.com/climate/commitment). --- # Source: https://docs.stripe.com/atlas/company-types.md # Company types Form a C corporation or an LLC using Stripe Atlas. With Stripe Atlas, you can incorporate a Delaware C corporation (C corp), a Delaware Limited Liability Company (LLC), or a subsidiary (also a C corp). Each entity type is suited to different business needs. This guide outlines what you need to know about each entity. #### C corporation With Stripe Atlas, you can incorporate a new Delaware C corporation or a subsidiary of an existing corporation. Here are a few characteristics that are common to C corporations. - **Ownership**: Used to grant equity to employees, advisors, and investors. - **Capital** : Preferred by institutional investors who might be unable to invest in LLCs. - **Tax treatment**: Can typically use early startup losses to offset future taxes, subject to some limitations. If your company is a subsidiary of an existing company, you need to issue shares to your parent company after incorporation. Atlas provides a standard template that you can customize with a lawyer based on your specific circumstances. #### LLC With Stripe Atlas, you can incorporate a Delaware LLC that is owned by a single founder or a group of founders. Here are a few characteristics that are common to LLCs: - **Ownership**: Often used by self-funded or small businesses that don’t plan to give equity to employees. - **Capital**: Common for founders who don’t plan to raise venture capital. - **Tax treatment:** Profits and losses are passed through to founders by default. This simplifies taxes for LLCs with a single founder in the US. However, if you have multiple founders or a non-US founder, [tax filings can become complex](https://stripe.com/guides/atlas/business-taxes#llc-federal-income-tax). ## Tax implications of incorporating near the end of a calendar year If you plan to incorporate near the end of the calendar year, consider the tax implications. C corps and LLCs operating in Delaware before December 31 are subject to annual tax for that year. Annual tax isn’t prorated. Waiting until January 1 to incorporate could save you a full year of Delaware annual tax. Your company might also owe federal corporate income tax or taxes in other states and countries. Consult with a tax professional to understand the tax implications of incorporating near the end of a calendar year. ## Next steps - [Get started with Stripe Atlas](https://docs.stripe.com/atlas/signup.md) - [Learn more about Section 83(b) elections](https://docs.stripe.com/atlas/83b-election.md) --- # Source: https://docs.stripe.com/issuing/compliance-us.md # Issuing and Financial Accounts product marketing, design, and compliance guidelines Learn how to launch and maintain compliant Issuing and Financial Accounts programs. > #### Legal Disclaimer > > Don’t consider any of the information in this guide as legal advice. If you use Financial Accounts for platforms and Stripe Issuing, consult your own legal counsel for advice about product branding and using Stripe products to offer financial services. This information applies to both Financial Accounts for platforms and Issuing integrations. To offer and promote Financial Accounts for platforms and Issuing products to your customers and connected accounts, your marketing and user interfaces must adhere to the guidelines that we outline here. These guidelines help you navigate the financial regulations that apply to Stripe products. We’ve organized them into the following sections: - [Account management](https://docs.stripe.com/issuing/compliance-us.md#account-management) - [Required agreements and disclosures for Issuing](https://docs.stripe.com/issuing/compliance-us.md#issuing-terms) - [Required agreements and disclosures for Financial Accounts for platforms](https://docs.stripe.com/issuing/compliance-us.md#treasury-terms) - [Required agreements and disclosures for fees, credits, and rewards programs](https://docs.stripe.com/issuing/compliance-us.md#fees-credits-rewards-terms) - [Customer communications and documents](https://docs.stripe.com/issuing/compliance-us.md#customer-communications-and-documents) - [Going live and marketing](https://docs.stripe.com/issuing/compliance-us.md#going-live) - [Recordkeeping](https://docs.stripe.com/issuing/compliance-us.md#recordkeeping) The following table outlines the steps you must complete before onboarding your first connected accounts. If you need help, contact the Stripe Compliance team at [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com). If you make changes to any items in the table at a later date, you must submit a request to the Stripe Compliance team using the [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835). | Topic | Checklist | Product applicability | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | | Application flow | Your application flow: - Includes bank disclosures - Includes required agreements - Required KYC fields - Approved by Stripe Compliance | Financial Accounts for platforms and Issuing | | Fees and credits | You’ve [submitted your planned fees and credits to Stripe](https://docs.stripe.com/financial-accounts/connect/compliance.md#fees-credits-rewards-terms) | Financial Accounts for platforms and Issuing | | Marketing and user interfaces | Your marketing materials, including your website landing pages, dashboards, and support pages: - Are approved by Stripe Compliance (or align with messaging guidelines) - Include bank disclosures | Financial Accounts for platforms and Issuing | | Customer service channels | Your customers can access your customer service channels and they can: - Submit complaints - Submit disputes | Financial Accounts for platforms and Issuing | | Account statements (optional) | If you choose to send account statements, they must: - Be approved by Stripe Compliance - Include Bank disclosures and relevant contact information | Financial Accounts for platforms | | Receipts | You have a mechanism to send your customers Stripe-generated money transmission receipts | Financial Accounts for platforms and Issuing | | Regulated customer notices | You send regulated customer notices to applicants and accountholders, and they’re either: - Sent by Stripe on your behalf - Sent by your platform with templates approved by Stripe Compliance | Issuing Spend Card and Charge Card | | Recordkeeping | You have a mechanism to retain copies of: - Customer consent to open accounts - Marketing materials and user interfaces - Customer communications, such as support emails - Account statements, if applicable | Financial Accounts for platforms and Issuing | ## Account management Before you launch Financial Accounts for platforms or Issuing, you must implement the proper internal compliance controls. You also need to build the processes described in this section into your various workflows, customer service, and product channels. ### Complaints program guidance Complaints are any expression of dissatisfaction with a product, service, policy, or employee related to Financial Accounts for platforms or Issuing, except those expressions made by employees of your company. Properly handling complaints is mandatory when offering financial services products. See the [Handling complaints](https://docs.stripe.com/financial-accounts/connect/handling-complaints.md) guide for detailed complaint management requirements. ### Disputes and charge errors As part of providing customer support, you might be notified of suspected disputed charges, charge errors, or both. The two most common types of disputes or errors are: - You or your customer believe a charge is unauthorized - You or your customer see an error on an account statement If these errors occur, submit the dispute through the Stripe Dashboard. Select the relevant transactions and choose **Dispute**. Be prepared to provide Stripe with specific information to investigate the dispute, such as: - Details about the authorized user - Details about the disputed charge amount - The transaction date - An explanation of why the disputed charge is an error or unauthorized You must report any disputed charge or error immediately upon notification of it. Failure to do so might impact your financial liability. To avoid a sustained reduction to your available balance, you can pay the disputed charge while we determine the validity of the dispute. If Stripe deems the dispute valid, we credit the disputed charge amount back to the appropriate account. ### Application flow Your platform must provide for three main compliance requirement workflows: - Collection of required KYC information - Presentation of the required bank disclosure - Ensuring that your applicant reads and accepts the required legal agreements ## Required agreements and disclosures for Issuing If you’re a platform and you’re not using [Stripe-hosted onboarding](https://docs.stripe.com/connect/hosted-onboarding.md), you must: - Present the following program-specific agreements and disclosures for your connected accounts to accept when they open their account. - Provide connected accounts with ongoing access to these agreements. - Present each agreement separately. You can’t combine them into one agreement for your cardholders to accept. *Connected Account Agreements and Disclosures.* You must provide the following agreements to your connected accounts before they can start using the Issuing Spend Card Program: - [Stripe Connected Account Agreement](https://stripe.com/legal/connect-account) - [Stripe Issuing Accountholder Terms](https://stripe.com/legal/ssa-services-terms#stripe-issuing-accountholder-united-states) - **Issuing Bank Terms** - *Celtic Bank Users only:* [Issuing Bank Terms - Spend Card (Celtic Bank)](https://stripe.com/legal/celtic-spend-card) - *Cross River Bank Users only:* [Issuing Bank Terms - Spend Card (Cross River Bank)](https://stripe.com/legal/issuing/crb-spend-card) - **Apple Pay Terms** (if enabled for your program) - [Apple Pay Accountholder Terms](https://stripe.com/issuing/celtic/apple-payment-platform-program-manager-customer-terms-and-conditions/legal#exhibit-c-pass-through-provisions) In addition to the above agreements, you must provide the following disclosures to your connected accounts before they can start using the Issuing Spend Card Program: - **Electronic Signature Consent**: You must include text near the “Issuing Bank Terms” link that states: “By clicking “submit application,” you agree to the Issuing Bank Terms, Stripe Connected Account Agreement, and Stripe Issuing Accountholder Terms, and you consent to electronic signatures as set forth in the Issuing Bank Terms.” - **Commercial Financing Disclosure**: For Connected Accounts with a business address in NY or UT, you must present one of the following disclosures: - For platforms that don’t charge fees: - *Celtic Bank Users only:* [Commercial Financing Disclosure (Celtic Bank) (no fee)](https://stripe.com/legal/issuing-offer-document) - *Cross River Bank Users only:* [Commercial Financing Disclosure (Cross River Bank) (no fee)](https://stripe.com/legal/crb-issuing-offer-document) - For platforms that charge a $0.10 fee when creating cards for users: - *Celtic Bank Users only:* [Commercial Financing Disclosure (Celtic Bank) (fee included)](https://stripe.com/legal/issuing-offer-document-fees) - *Cross River Bank Users only:* [Commercial Financing Disclosure (Cross River Bank) (fee included)](https://stripe.com/legal/crb-issuing-offer-document-fees) - For platforms that charge fees other than a $0.10 fee when creating cards for users: - If you charge fees beyond Stripe’s fee of 0.10 USD, you might be required to create your own commercial financing disclosure to present to your connected accounts for creating virtual cards. You must report custom fees through Stripe’s [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835), and you must submit custom commercial financing disclosures to [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com). Both the custom fee and custom disclosure are subject to Stripe’s review and approval. To assess the applicability of commercial financing disclosures to your program, contact [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com). *Authorized User Agreements and Disclosures.* If you or your connected accounts create an `individual` type [Cardholder](https://docs.stripe.com/api/issuing/cardholders/object.md), also known as an “authorized user,” you must present to cardholders—typically during the card activation process—the following agreements: - [Stripe E-Sign Disclosure](https://stripe.com/issuing/e-sign-disclosure/legal) - Authorized User Terms - *Celtic Bank Users only:* [Authorized User Terms (Celtic Bank)](https://stripe.com/legal/issuing/celtic-authorized-user-terms) - *Cross River Bank Users only:* [Authorized User Terms (Cross River Bank)](https://stripe.com/legal/issuing/crb-authorized-user-terms) - *Fifth Third Bank Users only:* [Authorized User Terms (Fifth Third Bank)](https://stripe.com/legal/issuing/fifth-third-authorized-user-terms) ### Charge card users *Connected Account Agreements and Disclosures.* You must provide the following agreements to your connected accounts before they can start using the Issuing Charge Card Program: - [Stripe Connected Account Agreement](https://stripe.com/legal/connect-account) - [Stripe Issuing Accountholder Terms](https://stripe.com/legal/ssa-services-terms#stripe-issuing-accountholder-united-states) or Custom Platform Accountholder Terms - **Issuing Bank Terms** - *Celtic Bank Users only:* [Issuing Bank Terms - Charge Card (Celtic Bank)](https://stripe.com/legal/celtic-charge-card) - *Cross River Bank Users only:* [Issuing Bank Terms - Charge Card (Cross River Bank)](https://stripe.com/legal/issuing/crb-charge-card) - *Fifth Third Bank Users only:* [Issuing Bank Terms - Charge Card (Fifth Third Bank)](https://stripe.com/legal/issuing/fifth-third-bank-terms) - **Apple Pay Terms** (if enabled for your program) - [Apple Pay Accountholder Terms](https://stripe.com/issuing/celtic/apple-payment-platform-program-manager-customer-terms-and-conditions/legal#exhibit-c-pass-through-provisions) - **Card Program Terms**: These are your bespoke program terms that supplement the Issuing Bank Terms. At a minimum, consider including the following items in your terms. Consult your legal counsel about which items to define within your own Card Program Terms. - Repayment methods, including automatic withdrawal consents - Billing cycles, including due dates - Fees - Rewards - Credit limits - Account closure requirements In addition to the above agreements, you must provide the following disclosures to your connected accounts before they can start using the Issuing Spend Card Program: - **Electronic Signature Consent**: You must include text near the **Issuing Bank Terms** link stating that signing the Issuing Bank Terms signifies consent to electronic signatures and communications. For example, your message might read: “By clicking the submit application button, you agree to the Issuing Bank Terms, Stripe Connected Account Agreement, and Stripe Issuing Accountholder Terms; and you consent to electronic signatures as set forth in the Issuing Bank Terms.” - **Commercial Financing Disclosure**: For connected accounts with a business address in NY or UT, you must present your own custom commercial financing disclosure. You must report custom fees through Stripe’s [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835), and you must submit custom commercial financing disclosures to [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com). Both the custom fee and custom disclosure are subject to Stripe’s review and approval. Contact [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com) to assess the commercial financing disclosure requirements of your program. In the context of authorized user agreements and disclosures, if you or your connected accounts create an `individual` type [Cardholder](https://docs.stripe.com/api/issuing/cardholders/object.md), also known as an “authorized user,” you must present to cardholders—typically during the card activation process—the following agreements: - [Stripe E-Sign Disclosure](https://stripe.com/issuing/e-sign-disclosure/legal) - Authorized User Terms - *Celtic Bank Users only:* [Authorized User Terms (Celtic Bank)](https://stripe.com/legal/issuing/celtic-authorized-user-terms) - *Cross River Bank Users only:* [Authorized User Terms (Cross River Bank)](https://stripe.com/legal/issuing/crb-authorized-user-terms) - *Fifth Third Bank Users only:* [Authorized User Terms (Fifth Third Bank)](https://stripe.com/legal/issuing/fifth-third-authorized-user-terms) ### Commercial prepaid debit users You must provide the following agreements to your connected accounts before they can start using your Issuing Commercial Prepaid Debit Card Program: - [Stripe Connected Account Agreement](https://stripe.com/legal/ssa-services-terms#stripe-financial-accounts-for-platforms-formerly-stripe-treasury-connected-accounts) - [Stripe Issuing Accountholder Terms](https://stripe.com/legal/issuing-accountholder) - **Issuing Bank Terms** - *Sutton Bank users only*: [Issuing Bank Terms - Payout Card (Sutton Bank)](https://stripe.com/legal/issuing/sutton/payout-card-terms) - *Cross River Bank users only*: [Issuing Bank Terms - Commercial Prepaid Card (Cross River Bank)](https://stripe.com/legal/crb-commercial-prepaid-card) In the context of authorized user agreements and disclosures, if you or your connected accounts create an `individual` type [Cardholder](https://docs.stripe.com/api/issuing/cardholders/object.md), also known as an “authorized user,” you must present to cardholders—typically during the card activation process—the following agreements: - [Stripe E-Sign Disclosure](https://stripe.com/issuing/e-sign-disclosure/legal) - **Authorized User Terms** - *Sutton Bank users only*: [Sutton Bank Authorized User Terms](https://stripe.com/legal/issuing/sutton-authorized-user-terms) - *Cross River Bank users only*: [Cross River Bank Authorized User Terms](https://stripe.com/legal/issuing/crb-authorized-user-terms) ## Required agreements and disclosures for Financial Accounts for platforms You must provide the following terms of service to your connected accounts and record their agreement before they can start using your Financial Accounts for platforms Program: - [Stripe Services Agreement](https://stripe.com/legal/ssa) - [Financial Accounts for platforms Terms - Connected Accounts](https://stripe.com/legal/ssa-services-terms#stripe-issuing-accountholder-united-states) ## Required agreements and disclosures for fees, credits, and rewards programs In addition to the previous agreements, your terms of service and fee schedule must clearly outline the fees and terms that you implement as part of your Financial Accounts for platforms or Issuing program. You must report to Stripe the details of any fees, credits, and rewards programs that you plan to offer. That helps make sure your user interfaces and marketing materials are compliant with financial regulations regarding fees or offer credits, especially in the form of rewards programs. Use the [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835). ## Customer communications and documents To comply with applicable laws and regulations, you must send certain communications to both your applicants and accountholders upon certain trigger events. To learn about customer communication requirements when using Issuing and Financial Accounts for platforms together, see [Issuing regulated customer notices](https://docs.stripe.com/issuing/compliance-us/issuing-regulated-customer-notices.md). ### Statements Providing statements, while optional, is a best practice that allows your Financial Accounts for platforms or Issuing customers to periodically check their transaction history. If you send statements, make sure they contain the following information: - [Company] name and address. - Your company’s customer support contact number and website - Customer account number - Customer name and address - Required disclosures - Transaction history (including opening and closing balances for the statement period) - Fees and credits. - Information about how you resolve errors and complaints ### Receipts One of the most important ongoing obligations you have in overseeing your Financial Accounts for platforms or Issuing program is providing your customers with money transmissions receipts. Every regulated transaction your customers initiate generates a compliant money transmission receipt URL that you must share with your customer. You can provide these URL receipts in a few different ways, such as emailing them or making them available in your customer’s Dashboard. See the [Regulatory receipts guide](https://docs.stripe.com/financial-accounts/connect/moving-money/regulatory-receipts.md) for more information on how to access hosted receipts. If you plan to charge your connected account owners any fees, whether they’re transactional or monthly recurring, include a description of the fee on the receipt so that they can reconcile it to corresponding transactions or monthly statements. ## Going live and marketing The following information pertains to marketing and releasing your Financial Accounts for platforms or Issuing programs to the public. ### General requirements for marketing your account offerings Any message or communication you provide to the public for financial products or services they don’t currently use must be truthful and fair, and in the interest of your potential customers. ### UDAP and correct messaging Federal regulation prohibits unfair and deceptive acts or practices (UDAP). To avoid UDAP violations, you must think of the end user first when developing and deploying any marketing materials. Make sure that marketing materials use clear messaging that fully explains product features, costs, benefits, and limitations. Don’t leave out key terms or fees, and don’t advertise product uses or features that aren’t true. | Do | Don’t | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Only use statements about products that are true, accurate, and aligned with how users engage with the products. | Don’t leave out key information from marketing content. If the information is likely to affect whether someone uses the product, then it’s “key." | | If you make claims that require additional data to support them, or if an end user needs to know more details to know how a certain claim is true, you must: - Provide documented evidence - Disclose that information | Make exaggerated claims that are hard to prove. Don’t make absolute statements that are disproved by a single exception. For example, “number 1," “every," “only," “all," “never," “always." | | Clearly explain all qualifying limitations and requirements needed by end users to get the product or features that you’ve advertised. | Don’t advertise features or programs that only a few applicants actually qualify for. | | All disclosures must meet a “clear and conspicuous” standard: - Font size must be large enough to read. - Font color must visibly contrast with the background. - Dynamic or video ads must have the disclosure on screen long enough to be read. | Don’t make disclosures hard to read. | | Disclosures used to explain or modify a claim must be tied to the claim they’re explaining. - Use a hyperlink directly linking to the disclosure (or include the disclosure next to the claim in the copy itself) - Use reference text or symbols (an asterisk, for example) directly after the claim and before the disclosure language. | Don’t bury disclosures in other non-key disclosures or footnotes. | | Disclose all account fees, costs, benefits, and terms as part of onboarding before your end users take out a product. | Don’t advertise products as “free” if you’re charging fees. | | Make sure all images used are properly licensed and that you can document this fact. | Don’t use images, formatting, or copy that implies products are endorsed by, or affiliated with, government entities or celebrities. | ### Messaging guidelines Use the following suggested messaging guidelines to convey key aspects of Issuing, Financial Accounts for platforms, or both programs. Stripe or our banking partners have validated (proven as true) this content, so you can confidently use this messaging in user-facing materials. - [Issuing](https://docs.stripe.com/issuing/compliance-us.md#issuing-messaging-guidelines) - [Financial Accounts for platforms](https://docs.stripe.com/issuing/compliance-us.md#treasury-messaging-guidelines) The following tables include validated content you can provide in your marketing campaigns. You can make non-substantive changes (for example, changing the design or infusing your brand’s voice) to the suggested messaging as long as the key information remains the same. Any substantive deviations from these guidelines require you to submit marketing materials and get approval from Stripe and our bank partners. Approvals might take up to 10 business days to process. You’re responsible for training employees on these requirements if they engage in marketing or sales activities for your Financial Accounts for platforms or Issuing program. #### Issuing messaging guidelines The following table provides guidelines for you to follow when developing messaging around your Issuing program. | Topic category | Do | Don’t | | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Logo and name usage | Your card program name and your brand name must have equal status, as with plain text: Widget balance® + Stripe. When referencing registered brand products, you must adhere to their separate brand guidelines. You only need to use the ®, ™, SM, mark once per asset. | Don’t maintain unequal status between the card program name and your brand name: **Widget balance®** + Stripe | | Comparison value propositions | Use language promoting the benefits of the card: - Better than cash - Safer than carrying cash - Manage your money hassle free - Spend only what you load - Spend only what you have on your card | Don’t make disparaging remarks about other financial products or institutions: this includes debit, credit, bank accounts, banks, or other financial products used or issued by financial institutions. Don’t allude to prepaid card programs as superior to other card products with terms like: - Better than credit - Better than a bank account - No interest - No security deposit - No debt | | Currency and using the funds | Use phrases like: - Access your contractor earnings - All [card program] cards are USD denominated - [Card program] cards can be used anywhere that accepts Visa cards | Don’t use phrases like: - Access your wages - Get funds in any format you want - Can spend money across the world | | What you can use the card for and limitations | Use phrases like: - Use [card program] for business needs - Get [card program] for your commercial needs - [Card program] can only be used for commercial purposes, and can’t be used for personal, family, or household purposes - Spend only what you load - Spend only what you have on your card | Don’t use phrases like: - Use [card program] for anything you want - Spend funds to buy the things you love - Personal cards - Use these cards like a payday loan, title loan, or pawn shop loan | | Where to spend funds | Use phrases like: - [Card program] can only be used for commercial purposes, and can’t be used for personal, family, or household purposes - Spend funds easily on your business | Don’t use phrases like: - Can be used just like a personal account - Get consumer cards - Spend funds to buy the things you love | #### Issuing messaging specifics per product The following table provides guidelines for you to follow when developing messaging for specific cards in your Issuing program. | Card | Do | Don’t | | ------------------------------ | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Spend card only | Use phrases like: - …is a commercial credit program - A business credit card | Don’t use phrases like: - Debit card - Prepaid card - Better than a debit card | | Payout or prepaid account only | Use phrases like: - Money management account | Don’t use phrases like: - Bank account - Deposit account - Checking account - Savings account - Similar terms to the previous ones that connote a traditional bank account product | #### Financial Accounts for platforms messaging guidelines Don’t use words like “bank account,” “deposit account," “checking account,” “savings account,” or similar terms that imply a traditional bank account product because Stripe isn’t a bank. Pre-approved terms include the following: - Business account - Cash management account - Financial account - Money transfer account See [Marketing Financial Accounts for platforms-based services](https://docs.stripe.com/financial-accounts/connect/marketing-financial-accounts.md) for a full list of terms you can and can’t use to describe your accounts and to learn how to talk about FDIC pass-through insurance eligibility. If you’re planning to describe FDIC pass-through insurance at all, your content must include [Stripe’s required FDIC pass-through insurance disclosure language](https://docs.stripe.com/financial-accounts/connect/marketing-financial-accounts.md#how-to-talk-about-fdic-pass-through-insurance-eligibility). Inaccurately referring to financial accounts as “bank accounts” could result in regulatory action, including fines. | Category | Do | Don’t | | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Logo and name usage | When referencing registered/® brand products, you must adhere to their separate brand guidelines. You only need to reference the ®, ™, SM mark once per asset. | Don’t apply unequal status between the card program name and your brand name: **Widget balance®** + Stripe | | Description of account value propositions | Use the following terms: - Business account - Cash management account - Financial account - Money transfer account | Don’t use the following terms: - “Bank account” - “Deposit account” - “Checking account” - “Savings account” - Similar terms to the previous ones that imply a traditional bank account product, because Stripe isn’t a bank | | FDIC insurance | Use the following terms that incorporate the term “eligible”: - “Eligible for FDIC pass-through insurance” - “Eligible for FDIC pass-through insurance up to the standard maximum deposit insurance per depositor in the same category" - “Eligible for FDIC pass-through insurance up to $250K” | Don’t use the following terms: - “FDIC insured” - “FDIC insured accounts” - “FDIC pass-through insurance guaranteed” | ### CAN-SPAM The CAN-SPAM Act regulates marketing activity conducted by email. An email is deemed a commercial message, subject to the CAN-SPAM act, if the primary purpose of the email is to convey a commercial advertisement, or to promote a product or service. A transactional email is an email sent to a customer that has a primary purpose relating to a particular transaction or relationship between you and the customer, such as a payment reminder. The CAN-SPAM Act imposes more rigorous requirements on commercial email messages, as compared with transactional messages. Transactional messages aren’t subject to most of the requirements of the CAN-SPAM Act. If a message contains both transactional content and commercial content, the CAN-SPAM Act commercial email requirements might apply, if the primary purpose of the message can be considered commercial. To facilitate compliance with the CAN-SPAM Act, any employee or staff using or having access to your email systems and resources for marketing must adhere to the following guidelines: - Misleading header information. Any email message, whether commercial or transactional, must not contain: - False or misleading header information. - A “from” line that doesn’t accurately identify any person (individual or business) who initiated the message. - Inaccurate or misleading identification of a protected computer used to initiate the message for purposes of disguising its origin. - Deceptive subject headings. Any commercial email message must not contain deceptive subject headings. For example, a deceptive subject heading is one that likely misleads the recipient about a material fact regarding the message’s contents or subject matter. - Opt-out mechanism. You must provide your customers with the ability to opt-out of receiving future commercial messages, and you must honor customer requests to opt-out within 10 days. You can’t require a user to pay a fee or provide information other than an email address to opt-out. - Advertisement identification. Any commercial email message must contain clear and conspicuous identification that the message is an advertisement or solicitation. - Physical address disclosure. Any commercial email message must disclose a valid physical address of the sender. Failure to comply with CAN-SPAM could result in large fines for each violation. ### Testimonials If you’re using testimonials or endorsements in advertising Stripe products to your users, consider the following: - The person giving a testimonial must be a real person and a true, bona fide user of the service or product they’re talking about. - You must obtain and keep their permission in writing to use their quote. You must update that permission every 24 months. - Product benefits, costs, or features in any quotes must be verifiable and true to what most users can expect to get. - If you paid someone for their quote, or gave them anything of value, you must put a disclaimer near the quote stating this fact. This includes paid actors, if their scripting makes it sound like they’re giving a testimonial. ### Prohibited advertising You can’t advertise Issuing or Financial Accounts for platforms in print, radio, TV, on the internet, or in any other format in a manner that promotes any unlawful activity or that causes reputation concerns for Stripe or our bank partners. ### Prohibition on international marketing Financial Accounts for platforms isn’t available to users or merchants located outside the US, so limit all marketing for Financial Accounts for platforms to US domestic audiences. For Issuing, although you can ship cards to international addresses for US-domiciled cardholders, you must not market the Issuing program internationally or to persons outside of the United States. That includes advertising or promoting Issuing through marketing channels such as social media, email, and paid search results. As with all other aspects of the Issuing program, your marketing activities must comply with card network rules. ### Required marketing disclosures Your users must understand the role that Stripe’s bank partners play in offering and operating certain financial products—and in many cases, that they’re entering into a contractual relationship with these banks. Your users must also understand the material costs and fees associated with their use of each financial product. We require you to build the following disclosures into your marketing materials: #### Disclosures when marketing Issuing If you offer Issuing products, you must include the following information in an easily discoverable and accessible area on all marketing materials, account opening flows, and product interfaces: - The name for your card program (for example, Rocket Rides Corporate Card). - The relevant statement from the following table identifying the issuing bank. It can be in the footers section of your materials; however, the font must be a legible size and a contrasting color to the background. | Statement for Celtic Bank users | Statement for Sutton Bank users | Statement for Cross River Bank users (Charge Card) | Statement for Cross River Bank users (Commercial Prepaid) | Statement for Fifth Third Bank users | | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | [Card Program Name] Visa® Commercial cards are powered by Stripe and issued by Celtic Bank. | [Card Program Name] Visa® Prepaid Cards are issued by Sutton Bank®, Member FDIC, pursuant to a license from Visa USA Inc. | [Card Program Name] Charge Cards are issued by Cross River Bank, Member FDIC. | [Card Program Name] Debit Cards are issued by Cross River Bank, Member FDIC. | [Card Program Name] Charge Cards are issued by Fifth Third Bank, N.A., Member FDIC. | In addition to the disclosures above, if you offer an Issuing Spend Card, you must also include the following statement. You can place it in the footers section of your materials, but the font must be a legible size and have a contrasting color as the background | Statement for Issuing Spend Card users | | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Stripe Issuing balances are provided in the US by Stripe Payments Company, licensed money transmitter, with funds held at Stripe’s bank partners, Members FDIC. | In addition to the disclosures above, if you offer a Commercial Prepaid Debit Card, you must also include the following statement. You can place it in the footers section of your materials, but the font must be a legible size and have a contrasting color as the background. | Statement for Commercial Prepaid Debit Users | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Commercial Prepaid Account balances are provided in the US by Stripe Payments Company, licensed money transmitter, with funds held at Stripe’s bank partners, Members FDIC. | #### Disclosures when marketing Financial Accounts for platforms If you offer Financial Accounts for platforms products, you must include the following information in an easily discoverable and accessible area on all marketing materials, account opening flows, and product interfaces: - A statement that you’re neither a bank nor a money transmitter. - Statement of partnership with Stripe. - “Stripe Payments Company” must be hyperlinked and point to `https://stripe.com`. | Statement for Fifth Third bank users | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Company Name] partners with [Stripe Payments Company](https://stripe.com/) for money transmission services and account services with funds held at Fifth Third Bank N.A., Member FDIC. | #### Disclosures when marketing both Financial Accounts for platforms and Issuing If you offer both Financial Accounts for platforms and Issuing products, you must include the following information in an easily discoverable and accessible area on all marketing materials, account opening flows, and product interfaces: - A name for your card program (for example, Rocket Rides Corporate Card). - A combined statement identifying both the issuing and Financial Accounts banks and saying that you’re neither a bank nor a money transmitter. | Example combined statement | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Company Name] partners with [Stripe Payments Company](https://stripe.com/) for money transmission services and account services with funds held at Fifth Third Bank, N.A., Member FDIC. [Card Program Name] Visa® Prepaid Cards are issued by [Issuing bank], Member FDIC. | ### Materials submission Submit copies of your marketing materials and user interface mockups through our [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835) for review before you launch. If you make any changes to marketing materials, application flows, or user communications, Stripe’s compliance team must perform a review before going live. Our team of compliance specialists reviews them with our bank partners and responds within 10 business days. When submitting your materials: - Provide full screenshots of product pages that include headings and footers. - The preferable format for materials is PDF, however any format where all text is legible is acceptable. - Describe the types of marketing material you’re submitting (for example, web banners, emails, search engine marketing, and whether it’s only text or images and text). - You can send up to 5 attachments per submission. Send any additional questions to our team at [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com). We might request that you change your marketing materials to comply with regulatory requirements. If we request a change, it’s your responsibility to update the materials and provide evidence of the change to Stripe. Failure to update materials at our request might result in Stripe disabling your Financial Accounts for platforms or Issuing capabilities. ## Recordkeeping You must demonstrate your adherence to the requirements listed in this guide. Keep thorough records of all marketing materials, customer data, account information, and other disclosures you make to customers for at least 5 years. The following is a list of all records to keep, with examples of record types. | Record type | Example form of records | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Product user experience | Screenshots of all deployed versions of the product user experience and their deployment dates. Include application flow, customer dashboard, support pages, and so on. | | Marketing | Inventory of all marketing copy deployed, email distribution lists used, and email solicitation opt-out lists, including timestamps of user opt-outs. | | Customer communications and complaints | Email interactions and documentation developed in the course of resolving complaints. | | Receipts | Receipts provided by Stripe and evidence that they’re uploaded to the customer’s Dashboard. | | Customer statements | Historical statements generated and made available to customers for download. | ## See also - [Customer communications](https://docs.stripe.com/issuing/compliance-us/issuing-regulated-customer-notices.md) --- # Source: https://docs.stripe.com/financial-accounts/connect/compliance.md # Financial Accounts for platforms product marketing, design, and compliance guidelines Learn how to keep your Financial Accounts for platforms program and marketing campaigns compliant. > #### Legal Disclaimer > > Don’t consider any of the information in this guide as legal advice. If you use Financial Accounts for platforms and Stripe Issuing, consult your own legal counsel for advice about product branding and using Stripe products to offer financial services. This information applies to both Financial Accounts for platforms and Issuing integrations. To offer and promote Financial Accounts for platforms and Issuing products to your customers and connected accounts, your marketing and user interfaces must adhere to the guidelines that we outline here. These guidelines help you navigate the financial regulations that apply to Stripe products. We’ve organized them into the following sections: - [Account management](https://docs.stripe.com/financial-accounts/connect/compliance.md#account-management) - [Required agreements and disclosures for Issuing](https://docs.stripe.com/financial-accounts/connect/compliance.md#issuing-terms) - [Required agreements and disclosures for Financial Accounts for platforms](https://docs.stripe.com/financial-accounts/connect/compliance.md#treasury-terms) - [Required agreements and disclosures for fees, credits, and rewards programs](https://docs.stripe.com/financial-accounts/connect/compliance.md#fees-credits-rewards-terms) - [Customer communications and documents](https://docs.stripe.com/financial-accounts/connect/compliance.md#customer-communications-and-documents) - [Going live and marketing](https://docs.stripe.com/financial-accounts/connect/compliance.md#going-live) - [Recordkeeping](https://docs.stripe.com/financial-accounts/connect/compliance.md#recordkeeping) The following table outlines the steps you must complete before onboarding your first connected accounts. If you need help, contact the Stripe Compliance team at [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com). If you make changes to any items in the table at a later date, you must submit a request to the Stripe Compliance team using the [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835). | Topic | Checklist | Product applicability | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | | Application flow | Your application flow: - Includes bank disclosures - Includes required agreements - Required KYC fields - Approved by Stripe Compliance | Financial Accounts for platforms and Issuing | | Fees and credits | You’ve [submitted your planned fees and credits to Stripe](https://docs.stripe.com/financial-accounts/connect/compliance.md#fees-credits-rewards-terms) | Financial Accounts for platforms and Issuing | | Marketing and user interfaces | Your marketing materials, including your website landing pages, dashboards, and support pages: - Are approved by Stripe Compliance (or align with messaging guidelines) - Include bank disclosures | Financial Accounts for platforms and Issuing | | Customer service channels | Your customers can access your customer service channels and they can: - Submit complaints - Submit disputes | Financial Accounts for platforms and Issuing | | Account statements (optional) | If you choose to send account statements, they must: - Be approved by Stripe Compliance - Include Bank disclosures and relevant contact information | Financial Accounts for platforms | | Receipts | You have a mechanism to send your customers Stripe-generated money transmission receipts | Financial Accounts for platforms and Issuing | | Regulated customer notices | You send regulated customer notices to applicants and accountholders, and they’re either: - Sent by Stripe on your behalf - Sent by your platform with templates approved by Stripe Compliance | Issuing Spend Card and Charge Card | | Recordkeeping | You have a mechanism to retain copies of: - Customer consent to open accounts - Marketing materials and user interfaces - Customer communications, such as support emails - Account statements, if applicable | Financial Accounts for platforms and Issuing | ## Account management Before you launch Financial Accounts for platforms or Issuing, you must implement the proper internal compliance controls. You also need to build the processes described in this section into your various workflows, customer service, and product channels. ### Complaints program guidance Complaints are any expression of dissatisfaction with a product, service, policy, or employee related to Financial Accounts for platforms or Issuing, except those expressions made by employees of your company. Properly handling complaints is mandatory when offering financial services products. See the [Handling complaints](https://docs.stripe.com/financial-accounts/connect/handling-complaints.md) guide for detailed complaint management requirements. ### Disputes and charge errors As part of providing customer support, you might be notified of suspected disputed charges, charge errors, or both. The two most common types of disputes or errors are: - You or your customer believe a charge is unauthorized - You or your customer see an error on an account statement If these errors occur, submit the dispute through the Stripe Dashboard. Select the relevant transactions and choose **Dispute**. Be prepared to provide Stripe with specific information to investigate the dispute, such as: - Details about the authorized user - Details about the disputed charge amount - The transaction date - An explanation of why the disputed charge is an error or unauthorized You must report any disputed charge or error immediately upon notification of it. Failure to do so might impact your financial liability. To avoid a sustained reduction to your available balance, you can pay the disputed charge while we determine the validity of the dispute. If Stripe deems the dispute valid, we credit the disputed charge amount back to the appropriate account. ### Application flow Your platform must provide for three main compliance requirement workflows: - Collection of required KYC information - Presentation of the required bank disclosure - Ensuring that your applicant reads and accepts the required legal agreements ## Required agreements and disclosures for Issuing If you’re a platform and you’re not using [Stripe-hosted onboarding](https://docs.stripe.com/connect/hosted-onboarding.md), you must: - Present the following program-specific agreements and disclosures for your connected accounts to accept when they open their account. - Provide connected accounts with ongoing access to these agreements. - Present each agreement separately. You can’t combine them into one agreement for your cardholders to accept. *Connected Account Agreements and Disclosures.* You must provide the following agreements to your connected accounts before they can start using the Issuing Spend Card Program: - [Stripe Connected Account Agreement](https://stripe.com/legal/connect-account) - [Stripe Issuing Accountholder Terms](https://stripe.com/legal/ssa-services-terms#stripe-issuing-accountholder-united-states) - **Issuing Bank Terms** - *Celtic Bank Users only:* [Issuing Bank Terms - Spend Card (Celtic Bank)](https://stripe.com/legal/celtic-spend-card) - *Cross River Bank Users only:* [Issuing Bank Terms - Spend Card (Cross River Bank)](https://stripe.com/legal/issuing/crb-spend-card) - **Apple Pay Terms** (if enabled for your program) - [Apple Pay Accountholder Terms](https://stripe.com/issuing/celtic/apple-payment-platform-program-manager-customer-terms-and-conditions/legal#exhibit-c-pass-through-provisions) In addition to the above agreements, you must provide the following disclosures to your connected accounts before they can start using the Issuing Spend Card Program: - **Electronic Signature Consent**: You must include text near the “Issuing Bank Terms” link that states: “By clicking “submit application,” you agree to the Issuing Bank Terms, Stripe Connected Account Agreement, and Stripe Issuing Accountholder Terms, and you consent to electronic signatures as set forth in the Issuing Bank Terms.” - **Commercial Financing Disclosure**: For Connected Accounts with a business address in NY or UT, you must present one of the following disclosures: - For platforms that don’t charge fees: - *Celtic Bank Users only:* [Commercial Financing Disclosure (Celtic Bank) (no fee)](https://stripe.com/legal/issuing-offer-document) - *Cross River Bank Users only:* [Commercial Financing Disclosure (Cross River Bank) (no fee)](https://stripe.com/legal/crb-issuing-offer-document) - For platforms that charge a $0.10 fee when creating cards for users: - *Celtic Bank Users only:* [Commercial Financing Disclosure (Celtic Bank) (fee included)](https://stripe.com/legal/issuing-offer-document-fees) - *Cross River Bank Users only:* [Commercial Financing Disclosure (Cross River Bank) (fee included)](https://stripe.com/legal/crb-issuing-offer-document-fees) - For platforms that charge fees other than a $0.10 fee when creating cards for users: - If you charge fees beyond Stripe’s fee of 0.10 USD, you might be required to create your own commercial financing disclosure to present to your connected accounts for creating virtual cards. You must report custom fees through Stripe’s [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835), and you must submit custom commercial financing disclosures to [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com). Both the custom fee and custom disclosure are subject to Stripe’s review and approval. To assess the applicability of commercial financing disclosures to your program, contact [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com). *Authorized User Agreements and Disclosures.* If you or your connected accounts create an `individual` type [Cardholder](https://docs.stripe.com/api/issuing/cardholders/object.md), also known as an “authorized user,” you must present to cardholders—typically during the card activation process—the following agreements: - [Stripe E-Sign Disclosure](https://stripe.com/issuing/e-sign-disclosure/legal) - Authorized User Terms - *Celtic Bank Users only:* [Authorized User Terms (Celtic Bank)](https://stripe.com/legal/issuing/celtic-authorized-user-terms) - *Cross River Bank Users only:* [Authorized User Terms (Cross River Bank)](https://stripe.com/legal/issuing/crb-authorized-user-terms) - *Fifth Third Bank Users only:* [Authorized User Terms (Fifth Third Bank)](https://stripe.com/legal/issuing/fifth-third-authorized-user-terms) ### Charge card users *Connected Account Agreements and Disclosures.* You must provide the following agreements to your connected accounts before they can start using the Issuing Charge Card Program: - [Stripe Connected Account Agreement](https://stripe.com/legal/connect-account) - [Stripe Issuing Accountholder Terms](https://stripe.com/legal/ssa-services-terms#stripe-issuing-accountholder-united-states) or Custom Platform Accountholder Terms - **Issuing Bank Terms** - *Celtic Bank Users only:* [Issuing Bank Terms - Charge Card (Celtic Bank)](https://stripe.com/legal/celtic-charge-card) - *Cross River Bank Users only:* [Issuing Bank Terms - Charge Card (Cross River Bank)](https://stripe.com/legal/issuing/crb-charge-card) - *Fifth Third Bank Users only:* [Issuing Bank Terms - Charge Card (Fifth Third Bank)](https://stripe.com/legal/issuing/fifth-third-bank-terms) - **Apple Pay Terms** (if enabled for your program) - [Apple Pay Accountholder Terms](https://stripe.com/issuing/celtic/apple-payment-platform-program-manager-customer-terms-and-conditions/legal#exhibit-c-pass-through-provisions) - **Card Program Terms**: These are your bespoke program terms that supplement the Issuing Bank Terms. At a minimum, consider including the following items in your terms. Consult your legal counsel about which items to define within your own Card Program Terms. - Repayment methods, including automatic withdrawal consents - Billing cycles, including due dates - Fees - Rewards - Credit limits - Account closure requirements In addition to the above agreements, you must provide the following disclosures to your connected accounts before they can start using the Issuing Spend Card Program: - **Electronic Signature Consent**: You must include text near the **Issuing Bank Terms** link stating that signing the Issuing Bank Terms signifies consent to electronic signatures and communications. For example, your message might read: “By clicking the submit application button, you agree to the Issuing Bank Terms, Stripe Connected Account Agreement, and Stripe Issuing Accountholder Terms; and you consent to electronic signatures as set forth in the Issuing Bank Terms.” - **Commercial Financing Disclosure**: For connected accounts with a business address in NY or UT, you must present your own custom commercial financing disclosure. You must report custom fees through Stripe’s [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835), and you must submit custom commercial financing disclosures to [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com). Both the custom fee and custom disclosure are subject to Stripe’s review and approval. Contact [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com) to assess the commercial financing disclosure requirements of your program. In the context of authorized user agreements and disclosures, if you or your connected accounts create an `individual` type [Cardholder](https://docs.stripe.com/api/issuing/cardholders/object.md), also known as an “authorized user,” you must present to cardholders—typically during the card activation process—the following agreements: - [Stripe E-Sign Disclosure](https://stripe.com/issuing/e-sign-disclosure/legal) - Authorized User Terms - *Celtic Bank Users only:* [Authorized User Terms (Celtic Bank)](https://stripe.com/legal/issuing/celtic-authorized-user-terms) - *Cross River Bank Users only:* [Authorized User Terms (Cross River Bank)](https://stripe.com/legal/issuing/crb-authorized-user-terms) - *Fifth Third Bank Users only:* [Authorized User Terms (Fifth Third Bank)](https://stripe.com/legal/issuing/fifth-third-authorized-user-terms) ### Commercial prepaid debit users You must provide the following agreements to your connected accounts before they can start using your Issuing Commercial Prepaid Debit Card Program: - [Stripe Connected Account Agreement](https://stripe.com/legal/ssa-services-terms#stripe-financial-accounts-for-platforms-formerly-stripe-treasury-connected-accounts) - [Stripe Issuing Accountholder Terms](https://stripe.com/legal/issuing-accountholder) - **Issuing Bank Terms** - *Sutton Bank users only*: [Issuing Bank Terms - Payout Card (Sutton Bank)](https://stripe.com/legal/issuing/sutton/payout-card-terms) - *Cross River Bank users only*: [Issuing Bank Terms - Commercial Prepaid Card (Cross River Bank)](https://stripe.com/legal/crb-commercial-prepaid-card) In the context of authorized user agreements and disclosures, if you or your connected accounts create an `individual` type [Cardholder](https://docs.stripe.com/api/issuing/cardholders/object.md), also known as an “authorized user,” you must present to cardholders—typically during the card activation process—the following agreements: - [Stripe E-Sign Disclosure](https://stripe.com/issuing/e-sign-disclosure/legal) - **Authorized User Terms** - *Sutton Bank users only*: [Sutton Bank Authorized User Terms](https://stripe.com/legal/issuing/sutton-authorized-user-terms) - *Cross River Bank users only*: [Cross River Bank Authorized User Terms](https://stripe.com/legal/issuing/crb-authorized-user-terms) ## Required agreements and disclosures for Financial Accounts for platforms You must provide the following terms of service to your connected accounts and record their agreement before they can start using your Financial Accounts for platforms Program: - [Stripe Services Agreement](https://stripe.com/legal/ssa) - [Financial Accounts for platforms Terms - Connected Accounts](https://stripe.com/legal/ssa-services-terms#stripe-issuing-accountholder-united-states) ## Required agreements and disclosures for fees, credits, and rewards programs In addition to the previous agreements, your terms of service and fee schedule must clearly outline the fees and terms that you implement as part of your Financial Accounts for platforms or Issuing program. You must report to Stripe the details of any fees, credits, and rewards programs that you plan to offer. That helps make sure your user interfaces and marketing materials are compliant with financial regulations regarding fees or offer credits, especially in the form of rewards programs. Use the [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835). ## Customer communications and documents To comply with applicable laws and regulations, you must send certain communications to both your applicants and accountholders upon certain trigger events. To learn about customer communication requirements when using Issuing and Financial Accounts for platforms together, see [Issuing regulated customer notices](https://docs.stripe.com/issuing/compliance-us/issuing-regulated-customer-notices.md). ### Statements Providing statements, while optional, is a best practice that allows your Financial Accounts for platforms or Issuing customers to periodically check their transaction history. If you send statements, make sure they contain the following information: - [Company] name and address. - Your company’s customer support contact number and website - Customer account number - Customer name and address - Required disclosures - Transaction history (including opening and closing balances for the statement period) - Fees and credits. - Information about how you resolve errors and complaints ### Receipts One of the most important ongoing obligations you have in overseeing your Financial Accounts for platforms or Issuing program is providing your customers with money transmissions receipts. Every regulated transaction your customers initiate generates a compliant money transmission receipt URL that you must share with your customer. You can provide these URL receipts in a few different ways, such as emailing them or making them available in your customer’s Dashboard. See the [Regulatory receipts guide](https://docs.stripe.com/financial-accounts/connect/moving-money/regulatory-receipts.md) for more information on how to access hosted receipts. If you plan to charge your connected account owners any fees, whether they’re transactional or monthly recurring, include a description of the fee on the receipt so that they can reconcile it to corresponding transactions or monthly statements. ## Going live and marketing The following information pertains to marketing and releasing your Financial Accounts for platforms or Issuing programs to the public. ### General requirements for marketing your account offerings Any message or communication you provide to the public for financial products or services they don’t currently use must be truthful and fair, and in the interest of your potential customers. ### UDAP and correct messaging Federal regulation prohibits unfair and deceptive acts or practices (UDAP). To avoid UDAP violations, you must think of the end user first when developing and deploying any marketing materials. Make sure that marketing materials use clear messaging that fully explains product features, costs, benefits, and limitations. Don’t leave out key terms or fees, and don’t advertise product uses or features that aren’t true. | Do | Don’t | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Only use statements about products that are true, accurate, and aligned with how users engage with the products. | Don’t leave out key information from marketing content. If the information is likely to affect whether someone uses the product, then it’s “key." | | If you make claims that require additional data to support them, or if an end user needs to know more details to know how a certain claim is true, you must: - Provide documented evidence - Disclose that information | Make exaggerated claims that are hard to prove. Don’t make absolute statements that are disproved by a single exception. For example, “number 1," “every," “only," “all," “never," “always." | | Clearly explain all qualifying limitations and requirements needed by end users to get the product or features that you’ve advertised. | Don’t advertise features or programs that only a few applicants actually qualify for. | | All disclosures must meet a “clear and conspicuous” standard: - Font size must be large enough to read. - Font color must visibly contrast with the background. - Dynamic or video ads must have the disclosure on screen long enough to be read. | Don’t make disclosures hard to read. | | Disclosures used to explain or modify a claim must be tied to the claim they’re explaining. - Use a hyperlink directly linking to the disclosure (or include the disclosure next to the claim in the copy itself) - Use reference text or symbols (an asterisk, for example) directly after the claim and before the disclosure language. | Don’t bury disclosures in other non-key disclosures or footnotes. | | Disclose all account fees, costs, benefits, and terms as part of onboarding before your end users take out a product. | Don’t advertise products as “free” if you’re charging fees. | | Make sure all images used are properly licensed and that you can document this fact. | Don’t use images, formatting, or copy that implies products are endorsed by, or affiliated with, government entities or celebrities. | ### Messaging guidelines Use the following suggested messaging guidelines to convey key aspects of Issuing, Financial Accounts for platforms, or both programs. Stripe or our banking partners have validated (proven as true) this content, so you can confidently use this messaging in user-facing materials. - [Issuing](https://docs.stripe.com/financial-accounts/connect/compliance.md#issuing-messaging-guidelines) - [Financial Accounts for platforms](https://docs.stripe.com/financial-accounts/connect/compliance.md#treasury-messaging-guidelines) The following tables include validated content you can provide in your marketing campaigns. You can make non-substantive changes (for example, changing the design or infusing your brand’s voice) to the suggested messaging as long as the key information remains the same. Any substantive deviations from these guidelines require you to submit marketing materials and get approval from Stripe and our bank partners. Approvals might take up to 10 business days to process. You’re responsible for training employees on these requirements if they engage in marketing or sales activities for your Financial Accounts for platforms or Issuing program. #### Issuing messaging guidelines The following table provides guidelines for you to follow when developing messaging around your Issuing program. | Topic category | Do | Don’t | | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Logo and name usage | Your card program name and your brand name must have equal status, as with plain text: Widget balance® + Stripe. When referencing registered brand products, you must adhere to their separate brand guidelines. You only need to use the ®, ™, SM, mark once per asset. | Don’t maintain unequal status between the card program name and your brand name: **Widget balance®** + Stripe | | Comparison value propositions | Use language promoting the benefits of the card: - Better than cash - Safer than carrying cash - Manage your money hassle free - Spend only what you load - Spend only what you have on your card | Don’t make disparaging remarks about other financial products or institutions: this includes debit, credit, bank accounts, banks, or other financial products used or issued by financial institutions. Don’t allude to prepaid card programs as superior to other card products with terms like: - Better than credit - Better than a bank account - No interest - No security deposit - No debt | | Currency and using the funds | Use phrases like: - Access your contractor earnings - All [card program] cards are USD denominated - [Card program] cards can be used anywhere that accepts Visa cards | Don’t use phrases like: - Access your wages - Get funds in any format you want - Can spend money across the world | | What you can use the card for and limitations | Use phrases like: - Use [card program] for business needs - Get [card program] for your commercial needs - [Card program] can only be used for commercial purposes, and can’t be used for personal, family, or household purposes - Spend only what you load - Spend only what you have on your card | Don’t use phrases like: - Use [card program] for anything you want - Spend funds to buy the things you love - Personal cards - Use these cards like a payday loan, title loan, or pawn shop loan | | Where to spend funds | Use phrases like: - [Card program] can only be used for commercial purposes, and can’t be used for personal, family, or household purposes - Spend funds easily on your business | Don’t use phrases like: - Can be used just like a personal account - Get consumer cards - Spend funds to buy the things you love | #### Issuing messaging specifics per product The following table provides guidelines for you to follow when developing messaging for specific cards in your Issuing program. | Card | Do | Don’t | | ------------------------------ | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Spend card only | Use phrases like: - …is a commercial credit program - A business credit card | Don’t use phrases like: - Debit card - Prepaid card - Better than a debit card | | Payout or prepaid account only | Use phrases like: - Money management account | Don’t use phrases like: - Bank account - Deposit account - Checking account - Savings account - Similar terms to the previous ones that connote a traditional bank account product | #### Financial Accounts for platforms messaging guidelines Don’t use words like “bank account,” “deposit account," “checking account,” “savings account,” or similar terms that imply a traditional bank account product because Stripe isn’t a bank. Pre-approved terms include the following: - Business account - Cash management account - Financial account - Money transfer account See [Marketing Financial Accounts for platforms-based services](https://docs.stripe.com/financial-accounts/connect/marketing-financial-accounts.md) for a full list of terms you can and can’t use to describe your accounts and to learn how to talk about FDIC pass-through insurance eligibility. If you’re planning to describe FDIC pass-through insurance at all, your content must include [Stripe’s required FDIC pass-through insurance disclosure language](https://docs.stripe.com/financial-accounts/connect/marketing-financial-accounts.md#how-to-talk-about-fdic-pass-through-insurance-eligibility). Inaccurately referring to financial accounts as “bank accounts” could result in regulatory action, including fines. | Category | Do | Don’t | | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Logo and name usage | When referencing registered/® brand products, you must adhere to their separate brand guidelines. You only need to reference the ®, ™, SM mark once per asset. | Don’t apply unequal status between the card program name and your brand name: **Widget balance®** + Stripe | | Description of account value propositions | Use the following terms: - Business account - Cash management account - Financial account - Money transfer account | Don’t use the following terms: - “Bank account” - “Deposit account” - “Checking account” - “Savings account” - Similar terms to the previous ones that imply a traditional bank account product, because Stripe isn’t a bank | | FDIC insurance | Use the following terms that incorporate the term “eligible”: - “Eligible for FDIC pass-through insurance” - “Eligible for FDIC pass-through insurance up to the standard maximum deposit insurance per depositor in the same category" - “Eligible for FDIC pass-through insurance up to $250K” | Don’t use the following terms: - “FDIC insured” - “FDIC insured accounts” - “FDIC pass-through insurance guaranteed” | ### CAN-SPAM The CAN-SPAM Act regulates marketing activity conducted by email. An email is deemed a commercial message, subject to the CAN-SPAM act, if the primary purpose of the email is to convey a commercial advertisement, or to promote a product or service. A transactional email is an email sent to a customer that has a primary purpose relating to a particular transaction or relationship between you and the customer, such as a payment reminder. The CAN-SPAM Act imposes more rigorous requirements on commercial email messages, as compared with transactional messages. Transactional messages aren’t subject to most of the requirements of the CAN-SPAM Act. If a message contains both transactional content and commercial content, the CAN-SPAM Act commercial email requirements might apply, if the primary purpose of the message can be considered commercial. To facilitate compliance with the CAN-SPAM Act, any employee or staff using or having access to your email systems and resources for marketing must adhere to the following guidelines: - Misleading header information. Any email message, whether commercial or transactional, must not contain: - False or misleading header information. - A “from” line that doesn’t accurately identify any person (individual or business) who initiated the message. - Inaccurate or misleading identification of a protected computer used to initiate the message for purposes of disguising its origin. - Deceptive subject headings. Any commercial email message must not contain deceptive subject headings. For example, a deceptive subject heading is one that likely misleads the recipient about a material fact regarding the message’s contents or subject matter. - Opt-out mechanism. You must provide your customers with the ability to opt-out of receiving future commercial messages, and you must honor customer requests to opt-out within 10 days. You can’t require a user to pay a fee or provide information other than an email address to opt-out. - Advertisement identification. Any commercial email message must contain clear and conspicuous identification that the message is an advertisement or solicitation. - Physical address disclosure. Any commercial email message must disclose a valid physical address of the sender. Failure to comply with CAN-SPAM could result in large fines for each violation. ### Testimonials If you’re using testimonials or endorsements in advertising Stripe products to your users, consider the following: - The person giving a testimonial must be a real person and a true, bona fide user of the service or product they’re talking about. - You must obtain and keep their permission in writing to use their quote. You must update that permission every 24 months. - Product benefits, costs, or features in any quotes must be verifiable and true to what most users can expect to get. - If you paid someone for their quote, or gave them anything of value, you must put a disclaimer near the quote stating this fact. This includes paid actors, if their scripting makes it sound like they’re giving a testimonial. ### Prohibited advertising You can’t advertise Issuing or Financial Accounts for platforms in print, radio, TV, on the internet, or in any other format in a manner that promotes any unlawful activity or that causes reputation concerns for Stripe or our bank partners. ### Prohibition on international marketing Financial Accounts for platforms isn’t available to users or merchants located outside the US, so limit all marketing for Financial Accounts for platforms to US domestic audiences. For Issuing, although you can ship cards to international addresses for US-domiciled cardholders, you must not market the Issuing program internationally or to persons outside of the United States. That includes advertising or promoting Issuing through marketing channels such as social media, email, and paid search results. As with all other aspects of the Issuing program, your marketing activities must comply with card network rules. ### Required marketing disclosures Your users must understand the role that Stripe’s bank partners play in offering and operating certain financial products—and in many cases, that they’re entering into a contractual relationship with these banks. Your users must also understand the material costs and fees associated with their use of each financial product. We require you to build the following disclosures into your marketing materials: #### Disclosures when marketing Issuing If you offer Issuing products, you must include the following information in an easily discoverable and accessible area on all marketing materials, account opening flows, and product interfaces: - The name for your card program (for example, Rocket Rides Corporate Card). - The relevant statement from the following table identifying the issuing bank. It can be in the footers section of your materials; however, the font must be a legible size and a contrasting color to the background. | Statement for Celtic Bank users | Statement for Sutton Bank users | Statement for Cross River Bank users (Charge Card) | Statement for Cross River Bank users (Commercial Prepaid) | Statement for Fifth Third Bank users | | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | [Card Program Name] Visa® Commercial cards are powered by Stripe and issued by Celtic Bank. | [Card Program Name] Visa® Prepaid Cards are issued by Sutton Bank®, Member FDIC, pursuant to a license from Visa USA Inc. | [Card Program Name] Charge Cards are issued by Cross River Bank, Member FDIC. | [Card Program Name] Debit Cards are issued by Cross River Bank, Member FDIC. | [Card Program Name] Charge Cards are issued by Fifth Third Bank, N.A., Member FDIC. | In addition to the disclosures above, if you offer an Issuing Spend Card, you must also include the following statement. You can place it in the footers section of your materials, but the font must be a legible size and have a contrasting color as the background | Statement for Issuing Spend Card users | | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Stripe Issuing balances are provided in the US by Stripe Payments Company, licensed money transmitter, with funds held at Stripe’s bank partners, Members FDIC. | In addition to the disclosures above, if you offer a Commercial Prepaid Debit Card, you must also include the following statement. You can place it in the footers section of your materials, but the font must be a legible size and have a contrasting color as the background. | Statement for Commercial Prepaid Debit Users | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Commercial Prepaid Account balances are provided in the US by Stripe Payments Company, licensed money transmitter, with funds held at Stripe’s bank partners, Members FDIC. | #### Disclosures when marketing Financial Accounts for platforms If you offer Financial Accounts for platforms products, you must include the following information in an easily discoverable and accessible area on all marketing materials, account opening flows, and product interfaces: - A statement that you’re neither a bank nor a money transmitter. - Statement of partnership with Stripe. - “Stripe Payments Company” must be hyperlinked and point to `https://stripe.com`. | Statement for Fifth Third bank users | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Company Name] partners with [Stripe Payments Company](https://stripe.com/) for money transmission services and account services with funds held at Fifth Third Bank N.A., Member FDIC. | #### Disclosures when marketing both Financial Accounts for platforms and Issuing If you offer both Financial Accounts for platforms and Issuing products, you must include the following information in an easily discoverable and accessible area on all marketing materials, account opening flows, and product interfaces: - A name for your card program (for example, Rocket Rides Corporate Card). - A combined statement identifying both the issuing and Financial Accounts banks and saying that you’re neither a bank nor a money transmitter. | Example combined statement | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Company Name] partners with [Stripe Payments Company](https://stripe.com/) for money transmission services and account services with funds held at Fifth Third Bank, N.A., Member FDIC. [Card Program Name] Visa® Prepaid Cards are issued by [Issuing bank], Member FDIC. | ### Materials submission Submit copies of your marketing materials and user interface mockups through our [Change Request Form](https://form.asana.com/?k=8K51UWmWhttehNFD5qBLdg&d=974470123217835) for review before you launch. If you make any changes to marketing materials, application flows, or user communications, Stripe’s compliance team must perform a review before going live. Our team of compliance specialists reviews them with our bank partners and responds within 10 business days. When submitting your materials: - Provide full screenshots of product pages that include headings and footers. - The preferable format for materials is PDF, however any format where all text is legible is acceptable. - Describe the types of marketing material you’re submitting (for example, web banners, emails, search engine marketing, and whether it’s only text or images and text). - You can send up to 5 attachments per submission. Send any additional questions to our team at [platform-compliance@stripe.com](mailto:platform-compliance@stripe.com). We might request that you change your marketing materials to comply with regulatory requirements. If we request a change, it’s your responsibility to update the materials and provide evidence of the change to Stripe. Failure to update materials at our request might result in Stripe disabling your Financial Accounts for platforms or Issuing capabilities. ## Recordkeeping You must demonstrate your adherence to the requirements listed in this guide. Keep thorough records of all marketing materials, customer data, account information, and other disclosures you make to customers for at least 5 years. The following is a list of all records to keep, with examples of record types. | Record type | Example form of records | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Product user experience | Screenshots of all deployed versions of the product user experience and their deployment dates. Include application flow, customer dashboard, support pages, and so on. | | Marketing | Inventory of all marketing copy deployed, email distribution lists used, and email solicitation opt-out lists, including timestamps of user opt-outs. | | Customer communications and complaints | Email interactions and documentation developed in the course of resolving complaints. | | Receipts | Receipts provided by Stripe and evidence that they’re uploaded to the customer’s Dashboard. | | Customer statements | Historical statements generated and made available to customers for download. | ## See also - [Regulatory receipts](https://docs.stripe.com/financial-accounts/connect/moving-money/regulatory-receipts.md) - [Handling complaints](https://docs.stripe.com/financial-accounts/connect/handling-complaints.md) - [Marketing Financial Accounts for platforms](https://docs.stripe.com/financial-accounts/connect/marketing-financial-accounts.md) --- # Source: https://docs.stripe.com/use-stripe-apps/woocommerce/configuration.md # Install and configure the Stripe Tax Extension Use the Stripe Tax Extension for WooCommerce to automatically calculate sales tax, VAT, and GST. Use the Stripe Tax Extension for WooCommerce to automatically calculate [sales tax, VAT, and GST](https://docs.stripe.com/tax/calculating.md) for all of your transactions. After you install the Stripe Tax Extension for WooCommerce, you can connect it to your Stripe account and configure your tax settings. If you previously configured these tax settings in the [Stripe Dashboard](https://dashboard.stripe.com/test/settings/tax), the values populate automatically in the Stripe Tax extension. When you edit the values in the extension, the changes automatically update in the Stripe Dashboard in live mode. The WooCommerce extension doesn’t support sandbox testing. You can conduct tests in live mode, but transactions incur fees according to the [Pay-as-you-go (PAYG) pricing plan](https://support.stripe.com/questions/understanding-stripe-tax-pricing#:~:text=Tax%20Basic%3A%20Pay%2Das%2Dyou%2Dgo). If your menu varies from the following steps, refer to the [WordPress instructions](https://wordpress.com/support/plugins/use-your-plugins/). ## Connect your Stripe account On your website’s dashboard, go to **WooCommerce** > **Settings**. On the **Stripe Tax** tab, click **Connect with Stripe** to log in to your Stripe account or create a new one. ## Install the extension 1. On the [Stripe Tax for WooCommerce](https://woocommerce.com/products/stripe-tax/) product page, click **Add to store**. 1. Complete the checkout form, then click **Place free order**. 1. After completing your order, click **Add to store**. 1. On the **Add your store** page, enter the URL of the store you want to add the extension to, then click **Add to store**. 1. After you receive confirmation of installation, you can configure the extension. ## Configure your sales tax settings On the **Stripe Tax** tab, under **Configure your sales tax settings**, complete the following: 1. Enter your head office address, which is your company’s legal address. 1. Choose your default [product tax code](https://docs.stripe.com/tax/tax-codes.md), which allows Stripe to calculate the tax rate for categories of products. 1. Click **Save changes**. On the **Tax** tab, you can decide if the prices you set for your products are inclusive or exclusive of tax. ## Manage tax registrations Tax isn’t applied [until you add registrations](https://docs.stripe.com/tax/zero-tax.md#situations-where-stripe-calculates-zero-tax) for jurisdictions where you need to collect tax. Our [monitoring tool](https://docs.stripe.com/tax/monitoring.md) can help you understand where you might be registered or need to register. If you’re already registered in certain jurisdictions and want to start collecting tax immediately, you can add those registrations to your configuration. You can only add tax registrations for [supported countries and registration types](https://docs.stripe.com/tax/supported-countries.md#supported-countries). Some jurisdictions might require additional information. ### Add tax registration On the **Stripe Tax** tab, under **Tax registrations**, click **Add new**. Choose the jurisdiction from the dropdown, then click **Save changes**. ### Delete tax registration To delete a registration, hover over the registration, then click **End immediately**. To delete multiple registrations, select them from the list, then click **End immediately** from the **Bulk actions** dropdown. ## Optional: Configure product tax codes and customer tax settings You can configure tax codes for your products or tax settings for your customers. ### Product tax codes Stripe Tax can calculate the tax for each of your products based on the product tax code that you assign to it. If you don’t set a code per product, Stripe Tax uses the default [product tax code](https://docs.stripe.com/tax/tax-codes.md) that you selected during setup. To set a tax code per product: 1. Go to **Products** and select a product from the list. 1. On the **Edit product** page, in the **Product data** section, select a **Stripe Tax - Product tax code** for the product. 1. Click **Update** to save your selection. ### Customer tax settings Stripe Tax can calculate the tax for each of your customers based on their tax status. To update a user’s taxability: 1. Go to **Users** and select a user from the list. 1. Under **Stripe Tax Exemptions**, select a **Tax Status** option for the user. 1. Click **Update user** to save your selection. Learn more about how the customer’s [tax status](https://docs.stripe.com/tax/zero-tax.md#exempt-customers) impacts tax calculation. ## Collect taxes To start collecting taxes: - On the **WooCommerce** > **General** tab, select **Enable tax rates and calculations**, then click **Save changes**. This setting enables rate configuration and tax calculation during the checkout process. - On the **WooCommerce** > **Stripe Tax** tab, select **Enable Stripe Tax**, then click **Save changes**. This setting enables automatic tax calculation and collection on all transactions. After selecting a product from your WooCommerce store, you can enter an address on the Checkout page to automatically calculate tax based on the address. Test the tax behavior using the addresses where you registered, as well as the store address. Certain product tax codes, such as [most services](https://docs.stripe.com/tax/tax-codes.md?type=services), are taxed at origin (your head office address). Scenarios also exist where [zero tax](https://docs.stripe.com/tax/zero-tax.md) is calculated. ## View tax reports After you start collecting taxes, the Stripe Tax extension sends the transactions to Stripe Tax. You can then access tax reports and exports in the [Stripe Dashboard](https://dashboard.stripe.com/tax/registrations). Learn more about the types of [tax reports](https://docs.stripe.com/tax/reports.md) available in Stripe Tax. ## Optional: Set up custom tax rates You can create [tax customizations](https://docs.stripe.com/tax/tax-customizations.md) to override the tax behavior that Stripe Tax applies to various products. ## Optional: Refund taxes The extension supports refunds, which you can initiate by following the guide for [refunding orders in WooCommerce](https://woocommerce.com/document/woocommerce-refunds/). Initiating a refund reduces the tax liability, and tools like the [tax obligations monitoring tool](https://docs.stripe.com/tax/monitoring.md#refunds-and-threshold-calculations) automatically update. Refunds don’t refund the Stripe Tax fees. ## See also - [Test and troubleshoot the extension](https://docs.stripe.com/use-stripe-apps/woocommerce/troubleshooting.md) --- # Source: https://docs.stripe.com/financial-connections/connect-payouts.md # Collect a bank account to enhance Connect payouts Collect your connected account's bank account and use account data to enhance payouts. Not sure about which Financial Connections integration to use? See our [overview of integration options](https://docs.stripe.com/financial-connections/use-cases.md). Financial Connections lets you instantly collect tokenized account and routing numbers for payouts to connected accounts where your platform is liable for negative balances, including Custom and Express accounts. Financial Connections helps you: - Increase onboarding conversion by eliminating the need for your connected accounts to leave your website or application to locate their account and routing numbers. - Reduce payout failure rates by eliminating errors that result from manual entry of account and routing numbers. - Stay secure by not storing sensitive data such as account and routing numbers on your server. - Save development time by eliminating your need to build bank account manual entry forms. - Enable your users to connect their accounts in fewer steps with Link, allowing them to save and quickly reuse their bank account details across Stripe merchants. Optionally, Stripe platforms in the US can request permission from your accounts to retrieve additional data on their [Financial Connections account](https://docs.stripe.com/api/financial_connections/accounts/object.md). Consider optimizing your onboarding process by accessing [balances](https://docs.stripe.com/financial-connections/balances.md), [transactions](https://docs.stripe.com/financial-connections/transactions.md), and [ownership](https://docs.stripe.com/financial-connections/ownership.md) information. Retrieving additional account data can help you: - Mitigate fraud when onboarding accounts by verifying the ownership details of their bank account, such as the name and address of the account holder. - Underwrite accounts for financial services that you might offer on your platform with balances and transactions data. ## Get started For accounts where your platform is liable for negative balances, such as Custom and Express accounts, enable Stripe Financial Connections either within the [Connect Onboarding](https://docs.stripe.com/connect/payouts-bank-accounts.md?bank-account-collection-method=financial-connections) web form or within your [own onboarding flow](https://docs.stripe.com/connect/payouts-bank-accounts.md?bank-account-collection-method=financial-connections&bank-account-collection-integration=direct-api). For accounts where your platform isn’t liable for negative balances, including Standard connected accounts, account onboarding always uses Financial Connections. The platform can’t access additional bank account data on those accounts. --- # Source: https://docs.stripe.com/revenue-recognition/connect.md # Source: https://docs.stripe.com/tax/connect.md # Source: https://docs.stripe.com/connect.md # Platforms and marketplaces with Stripe Connect Build a SaaS platform or marketplace with Connect. ## Get started Use Connect to build a platform, marketplace, or other business that manages payments and moves money between multiple parties. [Design your Connect integration](https://docs.stripe.com/connect/interactive-platform-guide.md) ## Build a SaaS platform or marketplace [Build a SaaS platform](https://docs.stripe.com/connect/saas.md): Provide platform services to businesses that collect payments from their own customers. [Build a marketplace](https://docs.stripe.com/connect/marketplace.md): Collect payments from customers and automatically pay out a portion to sellers or service providers on your marketplace. [Connect and the Accounts v2 API](https://docs.stripe.com/connect/accounts-v2.md): Create a unified identity to represent each of your platform’s connected accounts with one or more configurations, such as merchant or customer. ## Manage your connected accounts [Choose your onboarding configuration](https://docs.stripe.com/connect/onboarding.md): Learn about the different options for onboarding your connected accounts. [Enable account capabilities](https://docs.stripe.com/connect/account-capabilities.md): Enable capabilities for your connected accounts. [Collect verification information](https://docs.stripe.com/connect/required-verification-information.md): Learn what information you need to collect and verify for each connected account. ## Process payments [Create a charge](https://docs.stripe.com/connect/charges.md): Create a charge and split payments between your platform and your sellers or service providers. [Work with Connect account balances](https://docs.stripe.com/connect/account-balances.md): Learn about platform and connected account balances. [Pay out to connected accounts](https://docs.stripe.com/connect/payouts-connected-accounts.md): Manage payouts and external accounts for your connected accounts. ## Platform administration [Use the platform pricing tool](https://docs.stripe.com/connect/platform-pricing-tools.md): Set platform processing fees for your connected accounts. [Manage connected accounts with the Dashboard](https://docs.stripe.com/connect/dashboard.md): Review and take action on your connected accounts. ## More resources [Use Stripe Tax with Connect](https://docs.stripe.com/tax/connect.md): Calculate, collect, and report taxes for your platform or connected accounts. [Use Stripe Radar with Connect](https://docs.stripe.com/connect/radar.md): Learn how to use Stripe Radar to identify fraud in Connect account charges. [Use Connect embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md): Add connected account dashboard functionality to your website and mobile applications. --- # Source: https://docs.stripe.com/financial-accounts/connect/account-management/connected-accounts.md # Working with connected accounts Request the treasury capability and collect onboarding requirements for your connected accounts. > #### Accounts v2 API compatibility > > The Accounts v2 API doesn’t support Financial Accounts workflows. If you have accounts created with Accounts v2, you can use Accounts v1 to manage the `treasury` and `card_issuing` capabilities. For details, see [Use Accounts as customers](https://docs.stripe.com/connect/use-accounts-as-customers.md). To use Financial Accounts for platforms, your platform must have a Stripe *Connect* (Connect is Stripe's solution for multi-party businesses, such as marketplace or software platforms, to route payments between sellers, customers, and other recipients) integration. Stripe Connect enables a platform to provide connected accounts to sellers and service providers. For an overview of how connected accounts fit into the Financial Accounts for platforms account structure, see the [Financial Accounts for platforms accounts structure](https://docs.stripe.com/financial-accounts/connect/account-management/accounts-structure.md) guide. Financial Accounts for platforms only supports connected accounts that don’t use a Stripe-hosted dashboard and where your platform is responsible for requirements collection and loss liability, including Custom connected accounts. Learn how to [create connected accounts](https://docs.stripe.com/connect/interactive-platform-guide.md?connect-charge-type=direct&connect-loss-liability-owner=platform) that work with Financial Accounts for platforms. As a platform with connected accounts, you’re responsible for maintaining a minimum API version, communicating terms of service updates to your connected accounts, handling information requests from them, and providing them with support. Because your platform is ultimately responsible for the losses your connected accounts incur, you’re also responsible for vetting them for fraud. To learn more, read the [Financial Accounts for platforms fraud guide](https://docs.stripe.com/financial-accounts/connect/examples/fraud-guide.md). Connected accounts require specific capabilities enabled on the account to use features of Financial Accounts for platforms. Different features require different capabilities, which might require additional information about your connected account owners. The `treasury` capability, for example, is a requirement on connected accounts for Financial Accounts for platforms access. When you request `treasury` for an account, additional fields become required for that connected account before the account can use Financial Accounts for platforms. Before you create connected accounts in live mode for your Financial Accounts for platforms integration, we recommend you first create test connected accounts in a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment. Test connected accounts can’t receive or send real money and can’t be used in live mode, but are otherwise identical in configuration and functionality. ## Checking current connected account types If your platform already has a Connect integration with connected accounts but are unsure of their type, you can use the Dashboard or API to retrieve this information. #### Dashboard Navigate to the [Connected accounts page](https://dashboard.stripe.com/test/connect/accounts/overview) in the Dashboard. We list your connected accounts in a table format. To find the account features, select an account in the table to open the detailed view, then click **Profile** > **Account information**. #### API request Use `GET /v1/accounts` to retrieve a list of the accounts on your platform. ```json { "object": "list", "data": [ { "id": "acct_1KUbgB2E0Hr5XQiY", "object": "account", "controller": { "type": "application", "dashboard": { "type": "none" }, "losses": { "payments": "application" }, "requirement_collection": "application", "fees": { "payer": "application" }, }, ... } ] } ``` ## Create a new connected account with the treasury capability > This guide demonstrates how to create a new connected account using the Stripe API for Financial Accounts for platforms and isn’t exhaustive. For complete documentation on creating a connected account, including through hosted onboarding, see the [Connect integration guide](https://docs.stripe.com/connect/interactive-platform-guide.md?connect-charge-type=direct&connect-loss-liability-owner=platform). Use `POST /v1/accounts` to create a new connected account. Request the following capabilities for the account, which are required to use Financial Accounts for platforms: - `transfers` (required for all connected accounts) - `treasury` > You can update the account later to request these capabilities if you don’t do so when creating the account. If you want to issue cards with Stripe Issuing to your connected account, you must request the `card_issuing` capability, as well. See the [Working with Stripe Issuing cards](https://docs.stripe.com/financial-accounts/connect/account-management/issuing-cards.md) guide for more information. If you want to use ACH to transfer funds to or from an external account, you must also request the `us_bank_account_ach_payments` capability. With all the previous options included, the request resembles the following: ```javascript const account = await stripe.accounts.create({ country: 'US', email: email, capabilities: { transfers: {requested: true}, treasury: {requested: true}, card_issuing: {requested: true}, }, controller: { dashboard: {type: "none"}, losses: {payments: "application"}, requirement_collection: "application", fees: {payer: "application"} }, }); ``` If successful, the response you receive confirms the connected account and requested `capabilities`. ```json { "id": "acct_1234", "object": "account", "capabilities": { "card_issuing": "inactive", // Should be requested only for Stripe Issuing users. "treasury": "inactive", "us_bank_account_ach_payments": "inactive" }, ... } ``` To learn more about connected account capabilities, see the [Account capabilities](https://docs.stripe.com/connect/account-capabilities.md) guide for Connect. ## Update a connected account to include the treasury capability If you already have a connected account with `card_payments` enabled, use `POST /v1/accounts/{{CONNECTED_ACCOUNT_ID}}` to update the account with the associated ID with a request for the `treasury` capability. The following request updates a connected account with a request for the `treasury` capability, and includes the optional capabilities of `card_issuing` and `us_bank_account_ach_payments`: ```curl curl https://api.stripe.com/v1/accounts/{{CONNECTEDACCOUNT_ID}} \ -u "<>:" \ -d "capabilities[treasury][requested]"=true \ -d "capabilities[card_issuing][requested]"=true \ -d "capabilities[us_bank_account_ach_payments][requested]"=true ``` ```cli stripe accounts update {{CONNECTEDACCOUNT_ID}} \ -d "capabilities[treasury][requested]"=true \ -d "capabilities[card_issuing][requested]"=true \ -d "capabilities[us_bank_account_ach_payments][requested]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.accounts.update( '{{CONNECTEDACCOUNT_ID}}', { capabilities: { treasury: {requested: true}, card_issuing: {requested: true}, us_bank_account_ach_payments: {requested: true}, }, }, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.accounts.update( "{{CONNECTEDACCOUNT_ID}}", { "capabilities": { "treasury": {"requested": True}, "card_issuing": {"requested": True}, "us_bank_account_ach_payments": {"requested": True}, }, }, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->accounts->update( '{{CONNECTEDACCOUNT_ID}}', [ 'capabilities' => [ 'treasury' => ['requested' => true], 'card_issuing' => ['requested' => true], 'us_bank_account_ach_payments' => ['requested' => true], ], ] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountUpdateParams params = AccountUpdateParams.builder() .setCapabilities( AccountUpdateParams.Capabilities.builder() .setCardIssuing( AccountUpdateParams.Capabilities.CardIssuing.builder() .setRequested(true) .build() ) .setUsBankAccountAchPayments( AccountUpdateParams.Capabilities.UsBankAccountAchPayments.builder() .setRequested(true) .build() ) .build() ) .putExtraParam("capabilities[treasury][requested]", true) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().accounts().update("{{CONNECTEDACCOUNT_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.accounts.update( '{{CONNECTEDACCOUNT_ID}}', { capabilities: { treasury: { requested: true, }, card_issuing: { requested: true, }, us_bank_account_ach_payments: { requested: true, }, }, } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.AccountUpdateParams{ Capabilities: &stripe.AccountUpdateCapabilitiesParams{ CardIssuing: &stripe.AccountUpdateCapabilitiesCardIssuingParams{ Requested: stripe.Bool(true), }, USBankAccountACHPayments: &stripe.AccountUpdateCapabilitiesUSBankAccountACHPaymentsParams{ Requested: stripe.Bool(true), }, }, } params.AddExtra("capabilities[treasury][requested]", true) result, err := sc.V1Accounts.Update( context.TODO(), "{{CONNECTEDACCOUNT_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new AccountUpdateOptions { Capabilities = new AccountCapabilitiesOptions { CardIssuing = new AccountCapabilitiesCardIssuingOptions { Requested = true }, UsBankAccountAchPayments = new AccountCapabilitiesUsBankAccountAchPaymentsOptions { Requested = true, }, }, }; options.AddExtraParam("capabilities[treasury][requested]", true); var client = new StripeClient("<>"); var service = client.V1.Accounts; Account account = service.Update("{{CONNECTEDACCOUNT_ID}}", options); ``` Use `POST /v1/accounts/{{CONNECTED_ACCOUNT_ID}}` to update connected account capabilities for connected accounts that already have a `FinancialAccount` assigned. See [Working with financial accounts](https://docs.stripe.com/financial-accounts/connect/account-management/financial-accounts.md) or the [FinancialAccount object](https://docs.stripe.com/api/treasury/financial_accounts/object.md) API documentation for more information. ## Onboard the connected account After you create an account, you must onboard the seller or service provider to the account for ownership. The [Account](https://docs.stripe.com/api/accounts/object.md#account_object-requirements-currently_due) object that represents the connected account has a `requirements` hash that contains `currently_due` [identity verification](https://docs.stripe.com/connect/handling-api-verification.md) requirements. The seller or service provider on your platform must provide the details itemized in the `requirements` hash to enable charges and [payouts](https://docs.stripe.com/payouts.md) on their connected account and enable all requested features of their financial account. You have two options for onboarding connected account owners to Financial Accounts for platforms: [hosted onboarding](https://docs.stripe.com/financial-accounts/connect/account-management/connected-accounts.md#using-hosted-onboarding) and [custom onboarding](https://docs.stripe.com/financial-accounts/connect/account-management/connected-accounts.md#using-custom-onboarding). We recommend hosted onboarding. If you create a test `Account` object and want to bypass onboarding requirements to test functionality, use `POST /v1/accounts/{{CONNECTED_ACCOUNT_ID}}` to [provide test values](https://docs.stripe.com/connect/testing-verification.md) that fulfill all the requirements. The following request uses a previously created connected account to apply the required account details. ```curl curl https://api.stripe.com/v1/accounts/{{CONNECTED_ACCOUNT_ID}} \ -u "<>:" \ -d "tos_acceptance[date]"=1547923073 \ -d "tos_acceptance[ip]"="172.18.80.19" \ -d "settings[treasury][tos_acceptance][date]"=1547923073 \ -d "settings[treasury][tos_acceptance][ip]"="172.18.80.19" \ -d "business_profile[mcc]"=5045 \ --data-urlencode "business_profile[url]"="https://bestcookieco.com" \ -d "company[address][city]"=Schenectady \ -d "company[address][line1]"="123 State St" \ -d "company[address][postal_code]"=12345 \ -d "company[address][state]"=NY \ -d "company[tax_id]"=000000000 \ -d "company[name]"="The Best Cookie Co" \ -d "company[phone]"=8888675309 \ -d "individual[first_name]"=Jenny \ -d "individual[last_name]"=Rosen ``` ```cli stripe accounts update {{CONNECTED_ACCOUNT_ID}} \ -d "tos_acceptance[date]"=1547923073 \ -d "tos_acceptance[ip]"="172.18.80.19" \ -d "settings[treasury][tos_acceptance][date]"=1547923073 \ -d "settings[treasury][tos_acceptance][ip]"="172.18.80.19" \ -d "business_profile[mcc]"=5045 \ -d "business_profile[url]"="https://bestcookieco.com" \ -d "company[address][city]"=Schenectady \ -d "company[address][line1]"="123 State St" \ -d "company[address][postal_code]"=12345 \ -d "company[address][state]"=NY \ -d "company[tax_id]"=000000000 \ -d "company[name]"="The Best Cookie Co" \ -d "company[phone]"=8888675309 \ -d "individual[first_name]"=Jenny \ -d "individual[last_name]"=Rosen ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.accounts.update( '{{CONNECTED_ACCOUNT_ID}}', { tos_acceptance: { date: 1547923073, ip: '172.18.80.19', }, settings: { treasury: { tos_acceptance: { date: 1547923073, ip: '172.18.80.19', }, }, }, business_profile: { mcc: '5045', url: 'https://bestcookieco.com', }, company: { address: { city: 'Schenectady', line1: '123 State St', postal_code: '12345', state: 'NY', }, tax_id: '000000000', name: 'The Best Cookie Co', phone: '8888675309', }, individual: { first_name: 'Jenny', last_name: 'Rosen', }, }, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.accounts.update( "{{CONNECTED_ACCOUNT_ID}}", { "tos_acceptance": {"date": 1547923073, "ip": "172.18.80.19"}, "settings": { "treasury": {"tos_acceptance": {"date": 1547923073, "ip": "172.18.80.19"}}, }, "business_profile": {"mcc": "5045", "url": "https://bestcookieco.com"}, "company": { "address": { "city": "Schenectady", "line1": "123 State St", "postal_code": "12345", "state": "NY", }, "tax_id": "000000000", "name": "The Best Cookie Co", "phone": "8888675309", }, "individual": {"first_name": "Jenny", "last_name": "Rosen"}, }, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->accounts->update( '{{CONNECTED_ACCOUNT_ID}}', [ 'tos_acceptance' => [ 'date' => 1547923073, 'ip' => '172.18.80.19', ], 'settings' => [ 'treasury' => [ 'tos_acceptance' => [ 'date' => 1547923073, 'ip' => '172.18.80.19', ], ], ], 'business_profile' => [ 'mcc' => '5045', 'url' => 'https://bestcookieco.com', ], 'company' => [ 'address' => [ 'city' => 'Schenectady', 'line1' => '123 State St', 'postal_code' => '12345', 'state' => 'NY', ], 'tax_id' => '000000000', 'name' => 'The Best Cookie Co', 'phone' => '8888675309', ], 'individual' => [ 'first_name' => 'Jenny', 'last_name' => 'Rosen', ], ] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountUpdateParams params = AccountUpdateParams.builder() .setTosAcceptance( AccountUpdateParams.TosAcceptance.builder() .setDate(1547923073L) .setIp("172.18.80.19") .build() ) .setSettings( AccountUpdateParams.Settings.builder() .setTreasury( AccountUpdateParams.Settings.Treasury.builder() .setTosAcceptance( AccountUpdateParams.Settings.Treasury.TosAcceptance.builder() .setDate(1547923073L) .setIp("172.18.80.19") .build() ) .build() ) .build() ) .setBusinessProfile( AccountUpdateParams.BusinessProfile.builder() .setMcc("5045") .setUrl("https://bestcookieco.com") .build() ) .setCompany( AccountUpdateParams.Company.builder() .setAddress( AccountUpdateParams.Company.Address.builder() .setCity("Schenectady") .setLine1("123 State St") .setPostalCode("12345") .setState("NY") .build() ) .setTaxId("000000000") .setName("The Best Cookie Co") .setPhone("8888675309") .build() ) .setIndividual( AccountUpdateParams.Individual.builder() .setFirstName("Jenny") .setLastName("Rosen") .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().accounts().update("{{CONNECTED_ACCOUNT_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.accounts.update( '{{CONNECTED_ACCOUNT_ID}}', { tos_acceptance: { date: 1547923073, ip: '172.18.80.19', }, settings: { treasury: { tos_acceptance: { date: 1547923073, ip: '172.18.80.19', }, }, }, business_profile: { mcc: '5045', url: 'https://bestcookieco.com', }, company: { address: { city: 'Schenectady', line1: '123 State St', postal_code: '12345', state: 'NY', }, tax_id: '000000000', name: 'The Best Cookie Co', phone: '8888675309', }, individual: { first_name: 'Jenny', last_name: 'Rosen', }, } ); ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new AccountUpdateOptions { TosAcceptance = new AccountTosAcceptanceOptions { Date = DateTimeOffset.FromUnixTimeSeconds(1547923073).UtcDateTime, Ip = "172.18.80.19", }, Settings = new AccountSettingsOptions { Treasury = new AccountSettingsTreasuryOptions { TosAcceptance = new AccountSettingsTreasuryTosAcceptanceOptions { Date = DateTimeOffset.FromUnixTimeSeconds(1547923073).UtcDateTime, Ip = "172.18.80.19", }, }, }, BusinessProfile = new AccountBusinessProfileOptions { Mcc = "5045", Url = "https://bestcookieco.com", }, Company = new AccountCompanyOptions { Address = new AddressOptions { City = "Schenectady", Line1 = "123 State St", PostalCode = "12345", State = "NY", }, TaxId = "000000000", Name = "The Best Cookie Co", Phone = "8888675309", }, Individual = new AccountIndividualOptions { FirstName = "Jenny", LastName = "Rosen" }, }; var client = new StripeClient("<>"); var service = client.V1.Accounts; Account account = service.Update("{{CONNECTED_ACCOUNT_ID}}", options); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" params := &stripe.AccountParams{ TOSAcceptance: &stripe.AccountTOSAcceptanceParams{ Date: stripe.Int64(1547923073), IP: stripe.String("172.18.80.19"), }, Settings: &stripe.Settings{ Treasury: &stripe.Settings.Treasury{ TOSAcceptance: &stripe.Settings.Treasury.TOSAcceptance{ Date: stripe.Int64(1547923073), IP: stripe.String("172.18.80.19"), } } }, BusinessProfile: &stripe.AccountBusinessProfileParams{ MCC: stripe.String("5045"), URL: stripe.String("https://bestcookieco.com"), }, Company: &stripe.AccountCompanyParams{ Address: &stripe.AccountCompanyAddressParams{ City: stripe.String("Schenectady"), Line1: stripe.String("123 State St"), PostalCode: stripe.String("12345"), State: stripe.String("NY"), }, TaxID: stripe.String("000000000"), Name: stripe.String("The Best Cookie Co"), Phone: stripe.String("8888675309"), }, Individual: &stripe.AccountIndividualParams{ FirstName: stripe.String("Jenny"), LastName: stripe.String("Rosen"), }, }; result, _ := account.Update("{{CONNECTED_ACCOUNT_ID}}", params); ``` ### Using hosted onboarding Use Connect Onboarding to efficiently collect required information. That offloads the verification complexity from your platform to Stripe and collects the terms of the service agreement. Alternatively, you can write your own API requests for initial integration, but must monitor for changes to compliance requirements to keep your onboarding workflow current. Learn how to [create connected accounts](https://docs.stripe.com/connect/interactive-platform-guide.md?connect-charge-type=direct&connect-loss-liability-owner=platform) that work with Financial Accounts for platforms. Before you can use Connect Onboarding, you must provide the name, color, and icon of your brand in the **Branding** section of your [Connect settings page](https://dashboard.stripe.com/test/settings/connect). Doing so customizes the visual appearance of the form that sellers and service providers interact with when onboarding to your platform. To take advantage of Connect Onboarding, use `POST /v1/account_links` to create an `AccountLink` to provide to the seller or service provider who’s going to take ownership of the connected account: > For security, don’t email, text, or otherwise send account link URLs directly to your user. Instead, redirect the authenticated user to the account link URL from within your platform’s application. ```curl curl https://api.stripe.com/v1/account_links \ -u "<>:" \ -d account="{{CONNECTEDACCOUNT_ID}}" \ --data-urlencode refresh_url="https://example.com/reauth" \ --data-urlencode return_url="https://example.com/return" \ -d type=account_onboarding ``` ```cli stripe account_links create \ --account="{{CONNECTEDACCOUNT_ID}}" \ --refresh-url="https://example.com/reauth" \ --return-url="https://example.com/return" \ --type=account_onboarding ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account_link = client.v1.account_links.create({ account: '{{CONNECTEDACCOUNT_ID}}', refresh_url: 'https://example.com/reauth', return_url: 'https://example.com/return', type: 'account_onboarding', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account_link = client.v1.account_links.create({ "account": "{{CONNECTEDACCOUNT_ID}}", "refresh_url": "https://example.com/reauth", "return_url": "https://example.com/return", "type": "account_onboarding", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $accountLink = $stripe->accountLinks->create([ 'account' => '{{CONNECTEDACCOUNT_ID}}', 'refresh_url' => 'https://example.com/reauth', 'return_url' => 'https://example.com/return', 'type' => 'account_onboarding', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountLinkCreateParams params = AccountLinkCreateParams.builder() .setAccount("{{CONNECTEDACCOUNT_ID}}") .setRefreshUrl("https://example.com/reauth") .setReturnUrl("https://example.com/return") .setType(AccountLinkCreateParams.Type.ACCOUNT_ONBOARDING) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. AccountLink accountLink = client.v1().accountLinks().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const accountLink = await stripe.accountLinks.create({ account: '{{CONNECTEDACCOUNT_ID}}', refresh_url: 'https://example.com/reauth', return_url: 'https://example.com/return', type: 'account_onboarding', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.AccountLinkCreateParams{ Account: stripe.String("{{CONNECTEDACCOUNT_ID}}"), RefreshURL: stripe.String("https://example.com/reauth"), ReturnURL: stripe.String("https://example.com/return"), Type: stripe.String("account_onboarding"), } result, err := sc.V1AccountLinks.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new AccountLinkCreateOptions { Account = "{{CONNECTEDACCOUNT_ID}}", RefreshUrl = "https://example.com/reauth", ReturnUrl = "https://example.com/return", Type = "account_onboarding", }; var client = new StripeClient("<>"); var service = client.V1.AccountLinks; AccountLink accountLink = service.Create(options); ``` The response you receive includes the URL to provide to your user. ```json { "object": "account_link", "created": 1612927106, "expires_at": 1612927406, "url": "https://connect.stripe.com/setup/s/iCtLfmYb2tEU" } ``` ### Using embedded onboarding Embedded onboarding is a themeable onboarding UI with limited Stripe branding. It gives you more UX control than Stripe’s hosted onboarding solution. With embedded onboarding, you get a customized onboarding flow without the complexity and maintenance associated with updating your onboarding integration as compliance requirements change. Your platform embeds the [Account onboarding component](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md) in your application, and your connected accounts interact with the embedded component without leaving your application. Embedded onboarding uses the [Accounts API](https://docs.stripe.com/api/accounts.md) to read the requirements and generate an onboarding form with robust data validation that’s localized for all Stripe-supported countries. ### Using custom onboarding If you prefer to build custom onboarding for your users, use `POST /v1/accounts/{{CONNECTED_ACCOUNT_ID}}` and `POST /v1/accounts/{{CONNECTED_ACCOUNT_ID}}/persons/{{PERSON_ID}}` to update the relevant `Account` and `Person` objects with the required information. You must also confirm that the connected account owner has read and agreed to the [Financial Accounts for platforms Agreement](https://stripe.com/treasury-connect-account/legal). See [Handling verification with the API](https://docs.stripe.com/connect/handling-api-verification.md) for additional details on fulfilling onboarding requirements. ```curl curl https://api.stripe.com/v1/accounts/{{CONNECTEDACCOUNT_ID}} \ -u "<>:" \ -d "company[name]"=Homebox \ -d "company[address][line1]"="123 Market St." \ -d "company[address][city]"="San Francisco" \ -d "company[address][state]"=CA \ -d "company[address][postal_code]"=94107 \ -d "company[address][country]"=US ``` ```cli stripe accounts update {{CONNECTEDACCOUNT_ID}} \ -d "company[name]"=Homebox \ -d "company[address][line1]"="123 Market St." \ -d "company[address][city]"="San Francisco" \ -d "company[address][state]"=CA \ -d "company[address][postal_code]"=94107 \ -d "company[address][country]"=US ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.accounts.update( '{{CONNECTEDACCOUNT_ID}}', { company: { name: 'Homebox', address: { line1: '123 Market St.', city: 'San Francisco', state: 'CA', postal_code: '94107', country: 'US', }, }, }, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.accounts.update( "{{CONNECTEDACCOUNT_ID}}", { "company": { "name": "Homebox", "address": { "line1": "123 Market St.", "city": "San Francisco", "state": "CA", "postal_code": "94107", "country": "US", }, }, }, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->accounts->update( '{{CONNECTEDACCOUNT_ID}}', [ 'company' => [ 'name' => 'Homebox', 'address' => [ 'line1' => '123 Market St.', 'city' => 'San Francisco', 'state' => 'CA', 'postal_code' => '94107', 'country' => 'US', ], ], ] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountUpdateParams params = AccountUpdateParams.builder() .setCompany( AccountUpdateParams.Company.builder() .setName("Homebox") .setAddress( AccountUpdateParams.Company.Address.builder() .setLine1("123 Market St.") .setCity("San Francisco") .setState("CA") .setPostalCode("94107") .setCountry("US") .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().accounts().update("{{CONNECTEDACCOUNT_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.accounts.update( '{{CONNECTEDACCOUNT_ID}}', { company: { name: 'Homebox', address: { line1: '123 Market St.', city: 'San Francisco', state: 'CA', postal_code: '94107', country: 'US', }, }, } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.AccountUpdateParams{ Company: &stripe.AccountUpdateCompanyParams{ Name: stripe.String("Homebox"), Address: &stripe.AccountUpdateCompanyAddressParams{ Line1: stripe.String("123 Market St."), City: stripe.String("San Francisco"), State: stripe.String("CA"), PostalCode: stripe.String("94107"), Country: stripe.String("US"), }, }, } result, err := sc.V1Accounts.Update( context.TODO(), "{{CONNECTEDACCOUNT_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new AccountUpdateOptions { Company = new AccountCompanyOptions { Name = "Homebox", Address = new AddressOptions { Line1 = "123 Market St.", City = "San Francisco", State = "CA", PostalCode = "94107", Country = "US", }, }, }; var client = new StripeClient("<>"); var service = client.V1.Accounts; Account account = service.Update("{{CONNECTEDACCOUNT_ID}}", options); ``` ### Requirements The fields in the following table are required for Financial Accounts for platforms users. | Entity type | At onboarding | | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Individual, Sole proprietorship | Entity details: - Business names (customer facing and legal) - Legal entity type - Business address - Business phone number - Product or service description - Industry or Merchant category code - Tax ID Number (SSN, ITIN, or EIN) - Financial Accounts for platforms TOS acceptance - Stripe TOS acceptance Owner details: - Legal name - Date of birth - Email address - Residential address - Full SSN, or ID document scan for non-US persons or if SSN can’t be verified - Title - Phone number | | Companies (LLCs, corporations, non-profits, partnerships, and so on) | Entity details: - Business names (customer facing and legal) - Legal entity type - Business address - Business phone number - Product or service description - Industry or Merchant category code - Tax ID Number (EIN) - Financial Accounts for platforms TOS acceptance - Stripe TOS acceptance Owner/representative details: - Legal name - Date of birth - Email address - Residential address - Phone number - Title - Percent ownership of company - Full SSN, or ID document scan for non-US persons or if SSN can’t be verified | ### Completion The connected account onboarding process is complete when you receive an `account.updated` [webhook](https://docs.stripe.com/webhooks.md) confirming the following fields on your connected account: ``` { "object": { "object": "account", "id": "acct_1234", "capabilities": { "treasury": "active", "card_issuing": "active", // Only appears if requesting the `card_issuing` capability. "us_bank_account_ach_payments": "active", // Only appears if requesting the `us_bank_account_ach_payments` capability. }, ... } } ``` Account onboarding latency when your platform’s bank partner is Evolve Bank & Trust is less than 5 minutes. ### Updates to requirements To adapt to changes in financial regulations, Stripe must occasionally update information collection requirements for Financial Accounts for platforms. The `requirements.eventually_due` array on the `Account` object captures the updated information required by these regulation changes. Learn more about the [requirements](https://docs.stripe.com/api/accounts/object.md#account_object-requirements) hash. --- # Source: https://docs.stripe.com/payments/payment-element/control-billing-details-collection.md # Control billing details collection Customize the billing details you collect within the Payment Element. You can collect billing details several ways with the Payment Element: - `never`: Don’t collect any billing details in the Payment Element. You can set this for all [fields](https://docs.stripe.com/js/elements_object/create_payment_element#payment_element_create-options-fields) or on specific fields subcomponents, like `name`, `email`, and `address`. - `if_required`: Collect only the address fields required for each payment method to complete the payment. - `auto` (default): Stripe determines which billing fields to collect based on customer friction and authorization success rate for each payment method. You don’t need to pass in additional billing details at confirm time for this mode. By default, all fields are set to `auto`. This balances minimizing customer friction and maintaining optimal authorization rates. ## Hide billing details If you’re collecting billing details elsewhere outside of the Payment Element, you can use `never` to avoid collecting billing details entirely or to skip specific billing fields. Fields that are set to `never` are hidden for all the payment methods. Here’s an example: ```javascript const paymentElement = elements.create('payment', { fields: { billingDetails: { // No address field will be collected in any of the payment method forms address: 'never', } } }); ``` When `never` is set, you must manually pass in the omitted billing fields at the confirmation time: ```javascript stripe.confirmPayment({ //...Other values payment_method: { billing_details: { address: { line1: '123 Main Street', city: 'Anytown', country: 'US', postal_code: '12345' }, } } }); ``` ## Collect minimal billing details Specify `if_required` to collect only the billing address fields needed to complete payment for each payment method. This option helps reduce customer friction but might come with certain trade-offs, such as higher network fees, for users on a network cost plus pricing plan, and potential impacts on authorization rates. ```javascript const paymentElement = elements.create('payment', { fields: { billingDetails: { address: 'if_required', } } }); ``` ## Advanced: using Address Element in billing mode If your business requires collecting the full billing address, you can use the [Address Element](https://docs.stripe.com/elements/address-element.md) billing mode in combination with the Payment Element. The billing details gathered in Address Element are automatically attached at the confirmation time. --- # Source: https://docs.stripe.com/billing/subscriptions/coupons.md # Coupons and promotion codes Add discounts to subscriptions and subscription items using coupons and promotion codes. If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. Redeem coupons to apply discounts to the subscriptions you offer. You can also use coupons to create promotion codes to share with your customers. Customers can redeem these promotion codes to apply discounts to their subscriptions. - [Coupons](https://docs.stripe.com/billing/subscriptions/coupons.md#coupons): You create and manage coupons to define discounts, such as a percentage or amount off from the subscription price. - [Promotion codes](https://docs.stripe.com/billing/subscriptions/coupons.md#promotion-codes): You create customer-facing codes that map to your coupons. For example, FALLPROMO and SPRINGPROMO can both map to a single 25% off coupon. You can share promotion codes directly with your customers, who can enter and redeem the codes at checkout. You can use coupons and promotion codes to: - Apply one or more discounts to an invoice, subscription, or subscription item - Apply one or more discounts for a certain duration of time - Reduce invoice amounts by a percentage or a flat amount You can also define a coupon that a customer must redeem by a certain date, or that’s limited to a set number of redemptions across all of your customers. To use discounts for one-time payments, see [Add discounts for one-time payments](https://docs.stripe.com/payments/checkout/discounts.md). ## Coupons To apply discounts to a customer or a customer’s charges, redeem coupons into discounts. Learn how to create and manage coupons in the following sections. ### Create a coupon Create coupons in the Dashboard or with the [API](https://docs.stripe.com/api/coupons/create.md): #### Dashboard 1. In the Dashboard, open the [Products](https://dashboard.stripe.com/test/products?active=true) page. 1. Click **Coupons**. 1. Click **+New**. 1. In the **Create a coupon** dialog, enter the coupon’s parameters. 1. Click **Create coupon**. The following are all the settings for coupons. The name is the only setting you can edit after you create the coupon. | Setting | Description | | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Name** | The name of the coupon that appears on receipts and invoices. | | **ID** (optional) | A unique identifier for the coupon in the API. If you leave this field blank, Stripe generates an ID for you. | | **Type** | Determines whether a coupon discounts a subscription by a fixed amount or by a percentage. | | **Percentage off** or **Discount amount** | Indicates how much the coupon actually discounts. If you sell in multiple currencies, a single coupon can define different discount amounts for different currencies. Multi-currency coupons follow the same rules as [multi-currency prices](https://docs.stripe.com/products-prices/how-products-and-prices-work.md#multiple-currencies). | | **Apply to specific products** (optional) | Limits the type of items that the coupon can apply to. | | **Duration** | Indicates how long the coupon is valid for. | | **Redemption limits** (optional) | Allows you to limit when a customer can redeem the coupon and the number of times a coupon can be redeemed. | | **Codes** (optional) | Allows you to create [promotion codes](https://docs.stripe.com/billing/subscriptions/coupons.md#promotion-codes--promotion-codes) for the coupon. | #### API ```curl curl https://api.stripe.com/v1/coupons \ -u "<>:" \ -d duration=once \ -d id=free-period \ -d percent_off=100 ``` ```cli stripe coupons create \ --duration=once \ --id=free-period \ --percent-off=100 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") coupon = client.v1.coupons.create({ duration: 'once', id: 'free-period', percent_off: 100, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. coupon = client.v1.coupons.create({ "duration": "once", "id": "free-period", "percent_off": 100, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $coupon = $stripe->coupons->create([ 'duration' => 'once', 'id' => 'free-period', 'percent_off' => 100, ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CouponCreateParams params = CouponCreateParams.builder() .setDuration(CouponCreateParams.Duration.ONCE) .setId("free-period") .setPercentOff(new BigDecimal(100)) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Coupon coupon = client.v1().coupons().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const coupon = await stripe.coupons.create({ duration: 'once', id: 'free-period', percent_off: 100, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CouponCreateParams{ Duration: stripe.String(stripe.CouponDurationOnce), ID: stripe.String("free-period"), PercentOff: stripe.Float64(100), } result, err := sc.V1Coupons.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CouponCreateOptions { Duration = "once", Id = "free-period", PercentOff = 100M, }; var client = new StripeClient("<>"); var service = client.V1.Coupons; Coupon coupon = service.Create(options); ``` The following table contains coupon parameters. | Setting | Description | | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | A unique identifier for the coupon. | | `percent_off` or `amount_off` | The amount that is taken off the subtotal for the duration of the coupon. | | `currency` (if `amount_off` is set) | The three-letter ISO code for the currency of the amount to take off. | | `currency_options` (if `amount_off` is set) (optional) | If you sell in multiple currencies, amounts to take off the subtotal for different currencies. Multi-currency coupons follow the same rules as [multi-currency prices](https://docs.stripe.com/products-prices/how-products-and-prices-work.md#multiple-currencies). | | `duration` | Indicates how long the coupon is valid for. Values include **once**, **forever**, or **repeating**. | | `max_redemptions` (optional) | Maximum number of times a coupon can be redeemed across all customers. | | `redeem_by` (optional) | The latest date at which you can apply this coupon to customers. | | `applies_to` (optional) | Limits the items in an invoice that the coupon can apply to. | ### Set eligible products #### Dashboard To set the products that are eligible for discounts, add the relevant product in the **Apply to specific product** field. Any promotion codes that are associated with the coupon are also restricted to this list of eligible products. If you configure a coupon to apply to specific products and a subscription doesn’t have any applicable products, no discount is applied when you add the coupon to the subscription. #### API To set the products eligible for discounts, add the relevant product IDs to the `applies_to` hash in the coupon. This list of eligible products also applies to promotion codes associated with the coupon. If you configure a coupon to apply to specific products and a subscription doesn’t have any applicable products, no discount is applied when you add the coupon to the subscription. When you [make changes](https://docs.stripe.com/billing/subscriptions/change.md) to a subscription, Stripe calculates the proration and applies any existing discounts. You can’t discount proration line items further on the invoice that’s generated. ### Apply coupons to subscriptions After you’ve created coupons, create a discount by applying them to a subscription. You can apply the coupon when you create the subscription or by [updating a customer’s existing subscription](https://docs.stripe.com/api.md#update_subscription). #### Dashboard 1. In the Dashboard, open the [Subscriptions](https://dashboard.stripe.com/test/subscriptions?status=active) page. 1. Click the relevant subscription. 1. Click **Actions**. 1. Click **Update subscription**. 1. Click **Add coupon**. 1. Select one or more coupons from the dropdown menus and click **Submit**. #### API ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "items[0][price]"="{{PRICE_ID}}" \ -d "discounts[0][coupon]"=free-period ``` ```cli stripe subscriptions create \ --customer="{{CUSTOMER_ID}}" \ -d "items[0][price]"="{{PRICE_ID}}" \ -d "discounts[0][coupon]"=free-period ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.create({ customer: '{{CUSTOMER_ID}}', items: [{price: '{{PRICE_ID}}'}], discounts: [{coupon: 'free-period'}], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.create({ "customer": "{{CUSTOMER_ID}}", "items": [{"price": "{{PRICE_ID}}"}], "discounts": [{"coupon": "free-period"}], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->create([ 'customer' => '{{CUSTOMER_ID}}', 'items' => [['price' => '{{PRICE_ID}}']], 'discounts' => [['coupon' => 'free-period']], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionCreateParams params = SubscriptionCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .addItem( SubscriptionCreateParams.Item.builder().setPrice("{{PRICE_ID}}").build() ) .addDiscount( SubscriptionCreateParams.Discount.builder().setCoupon("free-period").build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.create({ customer: '{{CUSTOMER_ID}}', items: [ { price: '{{PRICE_ID}}', }, ], discounts: [ { coupon: 'free-period', }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), Items: []*stripe.SubscriptionCreateItemParams{ &stripe.SubscriptionCreateItemParams{Price: stripe.String("{{PRICE_ID}}")}, }, Discounts: []*stripe.SubscriptionCreateDiscountParams{ &stripe.SubscriptionCreateDiscountParams{Coupon: stripe.String("free-period")}, }, } result, err := sc.V1Subscriptions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionCreateOptions { Customer = "{{CUSTOMER_ID}}", Items = new List { new SubscriptionItemOptions { Price = "{{PRICE_ID}}" }, }, Discounts = new List { new SubscriptionDiscountOptions { Coupon = "free-period" }, }, }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Create(options); ``` You can still create a subscription when a customer doesn’t have a stored payment method if [no immediate payment](https://docs.stripe.com/billing/subscriptions/deferred-payment.md) is required after you apply coupons to it. ### Apply coupons to Checkout Apply coupons to subscriptions in a Checkout Session by setting the `discounts` parameter in the [API](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-discounts). To create a session with an applied discount, pass the coupon ID in the `coupon` parameter of the `discounts` array. #### curl ```bash curl https://api.stripe.com/v1/checkout/sessions \ -u <>: \ -d "payment_method_types[]"=card \ -d "line_items[][price]"="{{PRICE_ID}}" \ -d "line_items[][quantity]"=1 \ -d mode=subscription \-d "discounts[][coupon]"="{{COUPON_ID}}" \ -d success_url="https://example.com/success" \ ``` #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' session = Stripe::Checkout::Session.create({ payment_method_types: ['card'], line_items: [{ price: '{{PRICE_ID}}', quantity: 1 }], mode: 'subscription', discounts: [{coupon: '{{COUPON_ID}}', }], success_url: 'https://example.com/success' }) ``` #### Python ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' session = stripe.checkout.Session.create( payment_method_types=['card'], line_items=[{ 'price': '{{PRICE_ID}}', 'quantity': 1 }], mode='subscription', discounts=[{'coupon': '{{COUPON_ID}}', }], success_url='https://example.com/success', ) ``` #### PHP ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('<>'); $session = \Stripe\Checkout\Session::create([ 'payment_method_types' => ['card'], 'line_items' => [[ 'price' => '{{PRICE_ID}}', 'quantity' => 1 ]], 'mode' => 'subscription', 'discounts' => [['coupon' => '{{COUPON_ID}}', ]], 'success_url' => 'https://example.com/success' ]); ``` #### Java ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; SessionCreateParams params = SessionCreateParams.builder() .addPaymentMethodType(SessionCreateParams.PaymentMethodType.CARD) .addLineItem( SessionCreateParams.LineItem.builder() .setPrice(""{{PRICE_ID}}"") .setQuantity(1L) .build()) .setMode(SessionCreateParams.Mode.SUBSCRIPTION) .addDiscount( SessionCreateParams.Discount.builder().setCoupon("{{COUPON_ID}}") .build()) .setSuccessUrl("https://example.com/success") .build(); Session session = Session.create(params); ``` #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ payment_method_types: ['card'], line_items: [{ price: '{{PRICE_ID}}', quantity: 1 }], mode: 'subscription', discounts: [{coupon: '{{COUPON_ID}}', }], success_url: 'https://example.com/success' }); ``` #### Go ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" params := &stripe.CheckoutSessionParams{ PaymentMethodTypes: stripe.StringSlice([]string{ "card" }), LineItems: []*stripe.CheckoutSessionLineItemParams{ &stripe.CheckoutSessionLineItemParams{ Price: stripe.String(""{{PRICE_ID}}""), Quantity: stripe.Int64(1) } }, Mode: stripe.String("subscription"), Discounts: []*stripe.CheckoutSessionDiscountParams{ &stripe.CheckoutSessionDiscountParams{Coupon: stripe.String("{{COUPON_ID}}"), } }, SuccessURL: stripe.String("https://example.com/success"), } session, _ := session.New(params) ``` #### .NET ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; var options = new SessionCreateOptions { PaymentMethodTypes = new List { "card" }, LineItems = new List { new SessionLineItemOptions { Price = ""{{PRICE_ID}}"", Quantity = 1 } }, Mode = "subscription", Discounts = new List { new SessionDiscountOptions {Coupon = "{{COUPON_ID}}", } }, SuccessUrl = "https://example.com/success", }; var service = new SessionService(); var session = service.Create(options); ``` ### Delete coupons You can delete coupons with the Dashboard or the [API](https://docs.stripe.com/api/coupons/delete.md). Deleting a coupon prevents it from being applied to future subscriptions or invoices, but it doesn’t remove the discount from any subscription or invoice that already has it. #### Dashboard 1. In the Dashboard, open the [Products](https://dashboard.stripe.com/test/products?active=true) page. 1. Click **Coupons** 1. Click the relevant coupon. 1. Click the overflow menu (⋯). 1. Click **Delete coupon**. #### API ```curl curl -X DELETE https://api.stripe.com/v1/coupons/free-period \ -u "<>:" ``` ```cli stripe coupons delete free-period ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") deleted = client.v1.coupons.delete('free-period') ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. deleted = client.v1.coupons.delete("free-period") ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $deleted = $stripe->coupons->delete('free-period', []); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Coupon coupon = client.v1().coupons().delete("free-period"); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const deleted = await stripe.coupons.del('free-period'); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CouponDeleteParams{} result, err := sc.V1Coupons.Delete(context.TODO(), "free-period", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.Coupons; Coupon deleted = service.Delete("free-period"); ``` ### Coupon duration A coupon’s duration indicates how long the redeemed [discount](https://docs.stripe.com/api/.md#discounts) is valid for. For example, a coupon for 50% off with a duration of 4 months applies to all invoices in the 4 month period starting when the coupon is first applied. If a customer applies this coupon to a yearly subscription during the coupon’s 4 month period, the 50% discount applies to the entire yearly subscription. In a monthly subscription, the coupon applies to the first 4 months. For a weekly subscription, a 4 month coupon applies to every invoice in the first 4 months. If you’re configuring a coupon’s duration in the API, when you use the value `repeating` you must specify `duration_in_months` as the number of months that the coupon repeatedly applies to. If you set the duration to `once`, the coupon applies only to the first invoice. If you set the duration to `forever`, the coupon applies to all invoices indefinitely. ### Redemption limits Redemption limits apply to the coupon across every customer. For example, if you limit the number of times a coupon can be redeemed to 50, you can apply it to your customers only 50 times. This can be one time each for 50 different customers, one customer 50 times, or multiple customers multiple times until the max of 50 times. If you set a coupon to last forever when a customer uses it but the coupon has an expiration date, any customer given that coupon will have that coupon’s discount forever. No new customers can apply the coupon after the expiration date. ## Promotion codes Promotion codes are customer-facing codes that you create for coupons. For example, FALLPROMO and SPRINGPROMO can both point to a single 25% off coupon. You can share promotion codes directly with your customers to use at checkout. If you’ve implemented the *customer portal* (The customer portal is a secure, Stripe-hosted page that lets your customers manage their subscriptions and billing details) and turned on promotion codes, customers can apply a discount when upgrading or downgrading their existing subscriptions in the portal. > Subscriptions apply promotion code and price updates separately, which might cause unexpected updates. For example, a payment failure can cause a price upgrade to fail, but the promotion code included with the price upgrade succeeds. > The customer portal displays promotion codes that have been applied to a subscription. If you don’t want to allow customers to apply the promotion code themselves or potentially share it with others, you should either [set limits on the promotion code](https://docs.stripe.com/billing/subscriptions/coupons.md#promo-code-config) or [apply a coupon](https://docs.stripe.com/billing/subscriptions/coupons.md#discount-subscriptions) directly. Customize controls and limits on promotion codes by specifying eligible customers, first time orders, minimum order values, expiration dates, and redemption limits. ### Restrictions There are some restrictions to promotion codes. - You can’t apply a promotion code with amount restrictions on: - [Subscription Item objects](https://docs.stripe.com/api/subscription_items/object.md) - [Invoice Item objects](https://docs.stripe.com/api/invoiceitems/object.md) - [Subscriptions objects](https://docs.stripe.com/api/subscriptions/object.md) when you make an update - Future phases on [Subscription Schedule objects](https://docs.stripe.com/api/subscription_schedules/object.md) ### Create promotion codes #### Dashboard You can create a promotion code in the Dashboard when you [create a coupon](https://docs.stripe.com/billing/subscriptions/coupons.md#create-coupons--create-coupons). The **Code** is case-insensitive and unique across active promotion codes for any customer. For example: - You can create multiple customer-restricted promotion codes with the same **Code**, but you can’t reuse that **Code** for a promotion code that any customer can redeem. - If you create a promotion code that is redeemable by any customer, you can’t create another active promotion code with the same **code**. - You can create a promotion code with one **Code**, [inactivate](https://docs.stripe.com/billing/subscriptions/coupons.md#inactive-promotions--inactivate) it, and then create a new promotion code with the same **Code**. 1. In the Dashboard on the [Create a coupon](https://dashboard.stripe.com/test/coupons/create) page, click the **Use customer-facing coupon codes** button. 1. Enter a code. This is the code that a customer enters at checkout to redeem the discount. If you don’t set a code, Stripe generates one for you. 1. Select requirements for the promotion code. For example, you can restrict the coupon to only being valid on first-time orders. #### API The `code` is case-insensitive and unique across active promotion codes for any customer. For example: - You can create multiple customer-restricted promotion codes with the same `code`, but you can’t reuse that `code` for a promotion code that any customer can redeem. - If you create a promotion code that is redeemable by any customer, you can’t create another active promotion code with the same `code`. - You can create a promotion code with `code: NEWUSER`, inactivate it by passing `active: false`, and then create a new promotion code with `code: NEWUSER`. To create a [promotion code](https://docs.stripe.com/api/promotion_codes.md), specify an existing `coupon` and any restrictions (for example, limiting to a specific `customer`). If you have a specific code that you want to give to your customer (for example, `FALL25OFF`), set the `code`. If you leave this field blank, Stripe generates a random `code` for you. ```curl curl https://api.stripe.com/v1/promotion_codes \ -u "<>:" \ -d coupon=ZQO00CcH \ -d code=ALICE20 \ -d customer="{{CUSTOMER_ID}}" ``` When you create a promotion code, it inherits the configuration of the associated coupon. ### Promotion code configurations By configuring the promotion code settings, you can customize the following: - Which customers are eligible to use a promotion code - How many times a customer can redeem a promotion code - When a promotion code expires - Set a minimum amount a promotion code can apply to ### Limit by customer #### Dashboard To limit a promotion code to a particular customer, complete these steps: 1. On the [Create a coupon](https://dashboard.stripe.com/test/coupons/create) page, select **Limit to a specific customer**. 1. Select the relevant customer. If you don’t specify a customer, any customer can redeem the promotion code. #### API To limit a promotion code to a particular customer, specify a `customer` when you create the promotion code. If you don’t specify a customer, any customer can redeem the promotion code. ### Limit by first time order Restricts the coupon to customers who have no prior transaction history on your platform. This setting prevents customers from using the coupon if they: - Initiated a PaymentIntent, even if the payment never completed. - Subscribed to a trial period, even if it subsequently canceled. #### Dashboard To limit a promotion code to first-time customers, on the [Create a coupon](https://dashboard.stripe.com/test/coupons/create) page, select **Eligible for first-time order only**. #### API Limit the promotion code to first time customers by setting the `first_time_transaction` parameter of the `restrictions` attribute. ### Set a minimum amount #### Dashboard To set an minimum amount that is eligible for a promotion code, on the [Create a coupon](https://dashboard.stripe.com/test/coupons/create) page, select **Require minimum order value** and enter the minimum value. Because promotion code restrictions are checked at redemption time, the minimum transaction amount only applies to the initial payment for a subscription. If the coupon supports multiple currencies, the minimum amount can be different per-currency. #### API With promotion codes, you can set a minimum transaction amount for eligible discount by configuring the `minimum_amount` and the `minimum_amount_currency` properties. Since promotion code restrictions are checked at redemption time, the minimum transaction amount only applies to the initial payment for a subscription. If you sell in multiple currencies, set the minimum transaction amount for different currencies by configuring the `currency_options` property. ### Customize expirations #### Dashboard To set an expiration date for a promotion code, on the [Create a coupon](https://dashboard.stripe.com/test/coupons/create) page, select **Add an expiration date** and the date and time at which the promotion code expires. If the underlying coupon already has an expiration date set, then the promotion code’s expiration date can’t be later than the coupon’s. For example, you might have plans to support a coupon for a year, but you only want it to be redeemable for one week after a customer receives it. To do this, set the coupon’s expiration date to one year from now, and set each the promotion code’s expiration date to one week after it is created. #### API Set an expiration date on the promotion code using `expires_at`. If the underlying coupon already has `redeem_by` set, then the promotion code’s expiration date can’t be later than the coupon’s. If `promotion_code[expires_at]` isn’t specified, the coupon’s `redeem_by` automatically populates `expires_at`. - For example, you might have plans to support a coupon for a year, but you only want it to be redeemable for one week after a customer receives it. You would set `coupon[redeem_by]` to one year from now, and set each `promotion_code[expires_at]` to one week after it is created. ### Limit redemptions #### Dashboard To set the total number of times the promotion code can be redeemed by your customers, select **Limit the number of times this code can be redeemed** on the [Create a coupon](https://dashboard.stripe.com/test/coupons/create) page and enter the number. See [Redemption limits](https://docs.stripe.com/billing/subscriptions/coupons.md#redemption-limits) for details. If the underlying coupon already has a maximum number of times set, then the promotion code’s maximum redemptions can’t be greater than the coupon’s. #### API Limit the total number of times a promotion code can be redeemed by your customers using `max_redemptions`, which works similarly to coupons. If the underlying coupon already has `max_redemptions` set, then the promotion code’s `max_redemptions` can’t be greater than the coupon’s. See [Redemption limits](https://docs.stripe.com/billing/subscriptions/coupons.md#redemption-limits) for details. ### Deactivate promotion codes #### Dashboard To deactivate a promotion code, doing the following steps: 1. In the Dashboard, open the [Products](https://dashboard.stripe.com/test/products?active=true) page. 1. Click **Coupons**. 1. Click the coupon whose promotion code you want to deactivate. 1. In the relevant promotion code row, click the overflow menu (⋯). 1. Click **Archive promotion code**. However, if the underlying coupon for a promotion code becomes invalid, all of its promotion codes become permanently inactive. Similarly, if a promotion code reaches its maximum redemption limit or its expiration date, it becomes permanently inactive. These promotion codes can’t be reactivated. #### API Set whether a promotion code is currently redeemable by using the `active` parameter. However, if the underlying coupon for a promotion code becomes invalid, all of its promotion codes become permanently inactive. Similarly, if a promotion code reaches its `max_redemptions` or `expires_at`, it becomes permanently inactive. These promotion codes can’t be reactivated. ### Apply promotion codes to subscriptions After you create a promotion code, redeem a discount by applying the promotion code to a subscription. You can apply promotion codes two ways: - When you [create a subscription](https://docs.stripe.com/api.md#create_subscription) - When you [update a customer’s existing subscription](https://docs.stripe.com/api.md#update_subscription) #### Dashboard 1. In the Dashboard, go to **Billing** > **Subscriptions**. 1. Click the relevant subscription. 1. Click **Actions** > **Update subscription** > **Add coupon**. 1. Click a promotion code from the dropdown menu and click **Submit**. #### API 1. [List](https://docs.stripe.com/api/promotion_codes/list.md) the promotion codes and use the [code](https://docs.stripe.com/api/promotion_codes/list.md#list_promotion_code-code) from your Customer as a filter to [retrieve](https://docs.stripe.com/api/promotion_codes/retrieve.md) the [promotion code ID](https://docs.stripe.com/api/promotion_codes/object.md#promotion_code_object-id). 1. To apply the promotion code, use the promotion code ID in the following API call: ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "items[0][price]"="{{PRICE_ID}}" \ -d "discounts[0][promotion_code]"="{{PROMOTIONCODE_ID}}" ``` ```cli stripe subscriptions create \ --customer="{{CUSTOMER_ID}}" \ -d "items[0][price]"="{{PRICE_ID}}" \ -d "discounts[0][promotion_code]"="{{PROMOTIONCODE_ID}}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.create({ customer: '{{CUSTOMER_ID}}', items: [{price: '{{PRICE_ID}}'}], discounts: [{promotion_code: '{{PROMOTIONCODE_ID}}'}], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.create({ "customer": "{{CUSTOMER_ID}}", "items": [{"price": "{{PRICE_ID}}"}], "discounts": [{"promotion_code": "{{PROMOTIONCODE_ID}}"}], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->create([ 'customer' => '{{CUSTOMER_ID}}', 'items' => [['price' => '{{PRICE_ID}}']], 'discounts' => [['promotion_code' => '{{PROMOTIONCODE_ID}}']], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionCreateParams params = SubscriptionCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .addItem( SubscriptionCreateParams.Item.builder().setPrice("{{PRICE_ID}}").build() ) .addDiscount( SubscriptionCreateParams.Discount.builder() .setPromotionCode("{{PROMOTIONCODE_ID}}") .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.create({ customer: '{{CUSTOMER_ID}}', items: [ { price: '{{PRICE_ID}}', }, ], discounts: [ { promotion_code: '{{PROMOTIONCODE_ID}}', }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), Items: []*stripe.SubscriptionCreateItemParams{ &stripe.SubscriptionCreateItemParams{Price: stripe.String("{{PRICE_ID}}")}, }, Discounts: []*stripe.SubscriptionCreateDiscountParams{ &stripe.SubscriptionCreateDiscountParams{ PromotionCode: stripe.String("{{PROMOTIONCODE_ID}}"), }, }, } result, err := sc.V1Subscriptions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionCreateOptions { Customer = "{{CUSTOMER_ID}}", Items = new List { new SubscriptionItemOptions { Price = "{{PRICE_ID}}" }, }, Discounts = new List { new SubscriptionDiscountOptions { PromotionCode = "{{PROMOTIONCODE_ID}}" }, }, }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Create(options); ``` ### Add promotion codes to Checkout Enable promotion codes with the API by setting the [allow_promotion_codes](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-allow_promotion_codes) parameter in Checkout Sessions. When `allow_promotion_codes` is enabled on a Checkout Session, Checkout includes a promotion code redemption box for your customers to use. ![Promotion code field at checkout](https://b.stripecdn.com/docs-statics-srv/assets/promo_code_checkout.c07ef6d4f0b1b3f9a8a7e4bbba83d56f.png) Promotion code field at checkout ## Stackable coupons and promotion codes You can add multiple coupons, promotion codes, or redeemed [discounts](https://docs.stripe.com/api/.md#discounts) to a customer’s list of charges. You can do this when [creating a subscription](https://docs.stripe.com/api.md#create_subscription) or by [updating a customer’s existing subscription](https://docs.stripe.com/api.md#update_subscription). We support multiple discounts on both subscriptions and subscription items. When you create a subscription with stackable discounts, each discount applies to all items on the subscription. The order of the discounts is important if you use both `amount_off` and `percent_off`. For example, the following stacked discounts apply differently: - 20% off *then* $5 off - $5 off *then* 20% off #### Dashboard 1. In the Dashboard, go to **Billing** > **Subscriptions**. 1. Click the relevant subscription. 1. Click **Actions** > **Update subscription** > **Add coupon**. 1. Click coupons from the dropdown menus and click **Submit**. 1. Click the relevant product. 1. Click **Add coupons**. 1. Click coupons from the dropdown menus and click **Submit**. #### API ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "items[0][price]"="{{PRICE_ID}}" \ -d "items[0][discounts][0][coupon]"=item-coupon \ -d "items[0][discounts][1][promotion_code]"=item-promo \ -d "discounts[0][coupon]"=sub-coupon \ -d "discounts[1][promotion_code]"=sub-promo ``` ```cli stripe subscriptions create \ --customer="{{CUSTOMER_ID}}" \ -d "items[0][price]"="{{PRICE_ID}}" \ -d "items[0][discounts][0][coupon]"=item-coupon \ -d "items[0][discounts][1][promotion_code]"=item-promo \ -d "discounts[0][coupon]"=sub-coupon \ -d "discounts[1][promotion_code]"=sub-promo ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") subscription = client.v1.subscriptions.create({ customer: '{{CUSTOMER_ID}}', items: [ { price: '{{PRICE_ID}}', discounts: [{coupon: 'item-coupon'}, {promotion_code: 'item-promo'}], }, ], discounts: [{coupon: 'sub-coupon'}, {promotion_code: 'sub-promo'}], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.create({ "customer": "{{CUSTOMER_ID}}", "items": [ { "price": "{{PRICE_ID}}", "discounts": [{"coupon": "item-coupon"}, {"promotion_code": "item-promo"}], }, ], "discounts": [{"coupon": "sub-coupon"}, {"promotion_code": "sub-promo"}], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->create([ 'customer' => '{{CUSTOMER_ID}}', 'items' => [ [ 'price' => '{{PRICE_ID}}', 'discounts' => [['coupon' => 'item-coupon'], ['promotion_code' => 'item-promo']], ], ], 'discounts' => [['coupon' => 'sub-coupon'], ['promotion_code' => 'sub-promo']], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SubscriptionCreateParams params = SubscriptionCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .addItem( SubscriptionCreateParams.Item.builder() .setPrice("{{PRICE_ID}}") .addDiscount( SubscriptionCreateParams.Item.Discount.builder() .setCoupon("item-coupon") .build() ) .addDiscount( SubscriptionCreateParams.Item.Discount.builder() .setPromotionCode("item-promo") .build() ) .build() ) .addDiscount( SubscriptionCreateParams.Discount.builder().setCoupon("sub-coupon").build() ) .addDiscount( SubscriptionCreateParams.Discount.builder().setPromotionCode("sub-promo").build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Subscription subscription = client.v1().subscriptions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.create({ customer: '{{CUSTOMER_ID}}', items: [ { price: '{{PRICE_ID}}', discounts: [ { coupon: 'item-coupon', }, { promotion_code: 'item-promo', }, ], }, ], discounts: [ { coupon: 'sub-coupon', }, { promotion_code: 'sub-promo', }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.SubscriptionCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), Items: []*stripe.SubscriptionCreateItemParams{ &stripe.SubscriptionCreateItemParams{ Price: stripe.String("{{PRICE_ID}}"), Discounts: []*stripe.SubscriptionCreateItemDiscountParams{ &stripe.SubscriptionCreateItemDiscountParams{ Coupon: stripe.String("item-coupon"), }, &stripe.SubscriptionCreateItemDiscountParams{ PromotionCode: stripe.String("item-promo"), }, }, }, }, Discounts: []*stripe.SubscriptionCreateDiscountParams{ &stripe.SubscriptionCreateDiscountParams{Coupon: stripe.String("sub-coupon")}, &stripe.SubscriptionCreateDiscountParams{PromotionCode: stripe.String("sub-promo")}, }, } result, err := sc.V1Subscriptions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new SubscriptionCreateOptions { Customer = "{{CUSTOMER_ID}}", Items = new List { new SubscriptionItemOptions { Price = "{{PRICE_ID}}", Discounts = new List { new SubscriptionItemDiscountOptions { Coupon = "item-coupon" }, new SubscriptionItemDiscountOptions { PromotionCode = "item-promo" }, }, }, }, Discounts = new List { new SubscriptionDiscountOptions { Coupon = "sub-coupon" }, new SubscriptionDiscountOptions { PromotionCode = "sub-promo" }, }, }; var client = new StripeClient("<>"); var service = client.V1.Subscriptions; Subscription subscription = service.Create(options); ``` ### Restrictions There are some restrictions to using multiple discounts. - You can set up to 20 entries in the `discounts` parameter. - Each entry in `discounts` has to be unique. - You can not pass in a coupon and a promotion code created from the same coupon. - You can not pass in a coupon and a discount that is generated from the same coupon. - Redeemed discounts must already be attached to the customer or subscription that you’re updating. ### Update a subscription You don’t need to set `discounts` if you don’t intend to make changes to existing discounts. When updating `discounts`, you need to pass in any previously set `coupon`, `promotion_code` or `discount` you want to keep on the subscription. Pass `discounts = ""` to clear all discounts from the subscription. When a subscription has no discounts, the customer-level discount, if any, applies to invoices. If you have already set more than one discount on a subscription with the new `discounts` parameter, you can not update the subscription with the deprecated `coupon` or `promotion_code` parameter. Similarly, you can not update a schedule’s phases with the deprecated `coupon` or `promotion_code` parameter if you have set more than one discount on a prior phase. Updating `discounts` doesn’t incur prorations or generate an invoice on its own. The new discounts are applied the next time the subscription creates an invoice. ## Alternative discount methods Although coupons are the most common way to discount a subscription, you can also do the following: - Add a negative [customer balance](https://docs.stripe.com/api.md#customer_object-balance) to the customer. - Add negative [invoice items](https://docs.stripe.com/billing/invoices/subscription.md#adding-draft-invoice-items). - Add a [second price](https://docs.stripe.com/products-prices/manage-prices.md#create-price) that is a cheaper version of a product’s usual price. Of these methods, negative invoice items provide more detailed information as to what discount was created, when, and why. ## See also - [Changing subscriptions](https://docs.stripe.com/billing/subscriptions/change.md) - [Working with invoices](https://docs.stripe.com/billing/invoices/subscription.md) - [Coupons API](https://docs.stripe.com/api.md#coupons) - [Promotion codes API](https://docs.stripe.com/api.md#promotion_codes) --- # Source: https://docs.stripe.com/issuing/cards/physical/create-design.md # Create a design Create and name your bundle design. To create and name your design in the Issuing Dashboard or API before issuing cards to your cardholders, go directly to the [Designs](https://dashboard.stripe.com/test/issuing/personalization-designs) tab and click on **New design**. The standard option is always available, while the custom option becomes available after you order a custom bundle. # Dashboard > This is a Dashboard for when testing-method is without-code. View the full page at https://docs.stripe.com/issuing/cards/physical/create-design?testing-method=without-code. ## Use a standard bundle 1. Visit the [Designs tab](https://dashboard.stripe.com/test/issuing/personalization-designs) in the Issuing Dashboard. ![Personalization designs](https://b.stripecdn.com/docs-statics-srv/assets/card-issuing-designs-tab.8005cf6843cfad8a17067f2cb7eef4e3.png) 1. Click **New design** on the upper right and select the **Standard** physical bundle type. 1. Select a white or black card. ![Choose a physical bundle](https://b.stripecdn.com/docs-statics-srv/assets/choose-physical-bundle.b72ce7b9da304477e2c8ef84993a5599.png) 1. Upload your card logo. The logo must be in .PNG format, with a legible size of 1000px by 200px. It must be a binary image containing a black logo on a white background with no grayscale. 1. Set your carrier text. ![Custom carrier letter](https://b.stripecdn.com/docs-statics-srv/assets/customize-carrier-letter.de2468a680e90b169109fd1c95e1db8d.png) 1. Review the design summary and set a name used to specify the physical bundle when [issuing cards](https://docs.stripe.com/issuing/cards/physical/issue-cards.md) to your cardholders. 1. Click **Submit** to send your [design for review](https://docs.stripe.com/issuing/cards/physical/create-design.md#design-review). ## Use a custom bundle 1. Visit the [Designs tab](https://dashboard.stripe.com/test/issuing/personalization-designs) in the Issuing Dashboard. ![Personalization designs](https://b.stripecdn.com/docs-statics-srv/assets/card-issuing-designs-tab.8005cf6843cfad8a17067f2cb7eef4e3.png) 1. Click **New design** on the upper right and select the **Custom** physical bundle type. 1. Select the custom bundle from the drop-down list. Stripe enables visibility of the bundle in the Dashboard after the order has been manufactured and made live. See [Order a custom bundle](https://docs.stripe.com/issuing/cards/physical/order-custom-bundle.md) for more details. 1. If you’ve chosen to add an additional logo during [personalization](https://docs.stripe.com/issuing/cards/choose-bundle.md#manufacturing-personalization), you’re prompted to upload your card logo next. Ensure the logo is in .PNG format, with a legible size of 1000px by 200px. It must be a binary image containing a black logo on a white background with no grayscale. 1. If you’ve chosen the standard carrier, you’re prompted to upload your carrier text next. ![Custom physical bundle](https://b.stripecdn.com/docs-statics-srv/assets/custom-physical-bundle.a5d0bb3b3206c19d3aba48e3d18f859f.png) 1. Review design summary and set a personalization design name. The personalization design name is used to specify the physical bundle when [issuing cards](https://docs.stripe.com/issuing/cards/physical/issue-cards.md) to your cardholders. ![Custom design summary](https://b.stripecdn.com/docs-statics-srv/assets/custom-design-summary.feda6552ffa73fc575d217cf45b03008.png) 1. Click **Submit** to send your design for review. This is only applicable when an additional logo is added on the card or text is added on the standard carriers. # API > This is a API for when testing-method is with-code. View the full page at https://docs.stripe.com/issuing/cards/physical/create-design?testing-method=with-code. ## Use a bundle While we recommend using the Dashboard for managing personalization designs, you can also handle them with the [Personalization Design API](https://docs.stripe.com/api/issuing/personalization_designs.md). Here’s how to create a personalization design using the API: 1. List the physical bundles available to you using the [Physical Bundles API](https://docs.stripe.com/api/issuing/physical_bundles/retrieve.md): ```curl curl https://api.stripe.com/v1/issuing/physical_bundles \ -u "<>:" ``` ```cli stripe issuing physical_bundles list ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") physical_bundles = client.v1.issuing.physical_bundles.list() ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. physical_bundles = client.v1.issuing.physical_bundles.list() ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $physicalBundles = $stripe->issuing->physicalBundles->all([]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PhysicalBundleListParams params = PhysicalBundleListParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. StripeCollection stripeCollection = client.v1().issuing().physicalBundles().list(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const physicalBundles = await stripe.issuing.physicalBundles.list(); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.IssuingPhysicalBundleListParams{} result := sc.V1IssuingPhysicalBundles.List(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.Issuing.PhysicalBundles; StripeList physicalBundles = service.List(); ``` ```json "data": [ { id: "ics_Kc3MX9PPsUFFMp", object: "issuing.physical_bundle", livemode: true, name: "US Visa Credit White", type: "standard", status: "active" }, ... ] ``` 1. Choose a physical bundle from the response and note its `id`. The bundle determines the card’s color. 1. Upload a .PNG file of your card logo using the [Files API](https://docs.stripe.com/api/files/create.md), and specify the purpose as `issuing_logo`: ```bash curl https://files.stripe.com/v1/files \ -u <>: \ -F "file"="@/path/to/a/file.jpg" \ -F "purpose"="issuing_logo" ``` 1. [Create a personalization design](https://docs.stripe.com/api/issuing/personalization_designs/create.md) with the physical bundle ID and the file ID from the previous steps. You can also supply carrier text here. ```curl curl https://api.stripe.com/v1/issuing/personalization_designs \ -u "<>:" \ -d physical_bundle=ics_Kc3MX9PPsUFFMp \ -d card_logo="{{FILE_ID}}" \ -d "carrier_text[header_title]"=Hello ``` ```cli stripe issuing personalization_designs create \ --physical-bundle=ics_Kc3MX9PPsUFFMp \ --card-logo="{{FILE_ID}}" \ -d "carrier_text[header_title]"=Hello ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") personalization_design = client.v1.issuing.personalization_designs.create({ physical_bundle: 'ics_Kc3MX9PPsUFFMp', card_logo: '{{FILE_ID}}', carrier_text: {header_title: 'Hello'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. personalization_design = client.v1.issuing.personalization_designs.create({ "physical_bundle": "ics_Kc3MX9PPsUFFMp", "card_logo": "{{FILE_ID}}", "carrier_text": {"header_title": "Hello"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $personalizationDesign = $stripe->issuing->personalizationDesigns->create([ 'physical_bundle' => 'ics_Kc3MX9PPsUFFMp', 'card_logo' => '{{FILE_ID}}', 'carrier_text' => ['header_title' => 'Hello'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PersonalizationDesignCreateParams params = PersonalizationDesignCreateParams.builder() .setPhysicalBundle("ics_Kc3MX9PPsUFFMp") .setCardLogo("{{FILE_ID}}") .setCarrierText( PersonalizationDesignCreateParams.CarrierText.builder() .setHeaderTitle("Hello") .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PersonalizationDesign personalizationDesign = client.v1().issuing().personalizationDesigns().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const personalizationDesign = await stripe.issuing.personalizationDesigns.create({ physical_bundle: 'ics_Kc3MX9PPsUFFMp', card_logo: '{{FILE_ID}}', carrier_text: { header_title: 'Hello', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.IssuingPersonalizationDesignCreateParams{ PhysicalBundle: stripe.String("ics_Kc3MX9PPsUFFMp"), CardLogo: stripe.String("{{FILE_ID}}"), CarrierText: &stripe.IssuingPersonalizationDesignCreateCarrierTextParams{ HeaderTitle: stripe.String("Hello"), }, } result, err := sc.V1IssuingPersonalizationDesigns.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Issuing.PersonalizationDesignCreateOptions { PhysicalBundle = "ics_Kc3MX9PPsUFFMp", CardLogo = "{{FILE_ID}}", CarrierText = new Stripe.Issuing.PersonalizationDesignCarrierTextOptions { HeaderTitle = "Hello", }, }; var client = new StripeClient("<>"); var service = client.V1.Issuing.PersonalizationDesigns; Stripe.Issuing.PersonalizationDesign personalizationDesign = service.Create(options); ``` 1. After creating your personalization design, it’s sent for review. ## Design review Stripe reviews all logos and carrier text to make sure they comply with the guidelines set by our partner networks. We approve almost all designs, but we might reject yours if it contains: - The name of another legal entity. - A reference to a different network (for example, Mastercard if you’re issuing on Visa). - The name of a geographic location. - A reference to non-fiat currency (for example, cryptocurrency). - Advertising or promotional language. - Inappropriate text or imagery. ## Design rejection If Stripe rejects your design, we notify you by email within 2 business days and ask you to resubmit an updated design. When Stripe approves your design, we submit any cards that you issued using the design to the vendor. To issue cards with your newly created personalization design, see [Issue cards](https://docs.stripe.com/issuing/cards/physical/issue-cards.md). --- # Source: https://docs.stripe.com/api/subscriptions/create.md # Source: https://docs.stripe.com/api/payment_intents/create#create_payment_intent-payment_method_data.md # Source: https://docs.stripe.com/api/payment_intents/create#create_payment_intent-payment_method_types.md # Source: https://docs.stripe.com/api/charges/create.md # Source: https://docs.stripe.com/api/payment_methods/create.md # Source: https://docs.stripe.com/api/payment_intents/create.md # Source: https://docs.stripe.com/api/checkout/sessions/create.md # Create a Checkout Session Creates a Checkout Session object. ## Returns Returns a Checkout Session object. ## Parameters - `adaptive_pricing` (object, optional) Settings for price localization with [Adaptive Pricing](https://docs.stripe.com/payments/checkout/adaptive-pricing.md). - `adaptive_pricing.enabled` (boolean, optional) If set to `true`, Adaptive Pricing is available on [eligible sessions](https://docs.stripe.com/payments/currencies/localize-prices/adaptive-pricing.md?payment-ui=stripe-hosted#restrictions). Defaults to your [dashboard setting](https://dashboard.stripe.com/settings/adaptive-pricing). - `after_expiration` (object, optional) Configure actions after a Checkout Session has expired. You can’t set this parameter if `ui_mode` is `custom`. - `after_expiration.recovery` (object, optional) Configure a Checkout Session that can be used to recover an expired session. - `after_expiration.recovery.enabled` (boolean, required) If `true`, a recovery URL will be generated to recover this Checkout Session if it expires before a successful transaction is completed. It will be attached to the Checkout Session object upon expiration. - `after_expiration.recovery.allow_promotion_codes` (boolean, optional) Enables user redeemable promotion codes on the recovered Checkout Sessions. Defaults to `false` - `allow_promotion_codes` (boolean, optional) Enables user redeemable promotion codes. - `automatic_tax` (object, optional) Settings for automatic tax lookup for this session and resulting payments, invoices, and subscriptions. - `automatic_tax.enabled` (boolean, required) Set to `true` to [calculate tax automatically](https://docs.stripe.com/tax.md) using the customer’s location. Enabling this parameter causes Checkout to collect any billing address information necessary for tax calculation. - `automatic_tax.liability` (object, optional) The account that’s liable for tax. If set, the business address and tax registrations required to perform the tax calculation are loaded from this account. The tax transaction is returned in the report of the connected account. - `automatic_tax.liability.type` (enum, required) Type of the account referenced in the request. Possible enum values: - `account` Indicates that the account being referenced is a connected account which is different from the account making the API request but related to it. - `self` Indicates that the account being referenced is the account making the API request. - `automatic_tax.liability.account` (string, required only if type is account) The connected account being referenced when `type` is `account`. - `billing_address_collection` (enum, optional) Specify whether Checkout should collect the customer’s billing address. Defaults to `auto`. Possible enum values: - `auto` Checkout will only collect the billing address when necessary. When using [automatic_tax](https://docs.stripe.com/docs/api/checkout/sessions/object.md#checkout_session_object-automatic_tax-enabled), Checkout will collect the minimum number of fields required for tax calculation. - `required` Checkout will always collect the customer’s billing address. - `branding_settings` (object, optional) The branding settings for the Checkout Session. This parameter is not allowed if ui_mode is `custom`. - `branding_settings.background_color` (string, optional) A hex color value starting with `#` representing the background color for the Checkout Session. - `branding_settings.border_style` (enum, optional) The border style for the Checkout Session. Possible enum values: - `pill` Uses pill-shaped corners on the Checkout Session. - `rectangular` Uses rectangular corners on the Checkout Session. - `rounded` Uses rounded corners on the Checkout Session. - `branding_settings.button_color` (string, optional) A hex color value starting with `#` representing the button color for the Checkout Session. - `branding_settings.display_name` (string, optional) A string to override the business name shown on the Checkout Session. This only shows at the top of the Checkout page, and your business name still appears in terms, receipts, and other places. - `branding_settings.font_family` (enum, optional) The font family for the Checkout Session corresponding to one of the [supported font families](https://docs.stripe.com/payments/checkout/customization/appearance.md?payment-ui=stripe-hosted#font-compatibility). Possible enum values: - `be_vietnam_pro` The `Be Vietnam Pro` font family. - `bitter` The `Bitter` font family. - `chakra_petch` The `Chakra Petch` font family. - `default` The `default` font family. - `hahmlet` The `Hahmlet` font family. - `inconsolata` The `Inconsolata` font family. - `inter` The `Inter` font family. - `lato` The `Lato` font family. - `lora` The `Lora` font family. - `m_plus_1_code` The `M PLUS 1 Code` font family. - `montserrat` The `Montserrat` font family. - `noto_sans` The `Noto Sans` font family. - `noto_sans_jp` The `Noto Sans JP` font family. - `noto_serif` The `Noto Serif` font family. - `nunito` The `Nunito` font family. - `open_sans` The `Open Sans` font family. - `pridi` The `Pridi` font family. - `pt_sans` The `PT Sans` font family. - `pt_serif` The `PT Serif` font family. - `raleway` The `Raleway` font family. - `roboto` The `Roboto` font family. - `roboto_slab` The `Roboto Slab` font family. - `source_sans_pro` The `Source Sans Pro` font family. - `titillium_web` The `Titillium Web` font family. - `ubuntu_mono` The `Ubuntu Mono` font family. - `zen_maru_gothic` The `Zen Maru Gothic` font family. - `branding_settings.icon` (object, optional) The icon for the Checkout Session. For best results, use a square image. - `branding_settings.icon.type` (enum, required) The type of image for the icon. Must be one of `file` or `url`. - `branding_settings.icon.file` (string, optional) The ID of a [File upload](https://stripe.com/docs/api/files) representing the icon. Purpose must be `business_icon`. Required if `type` is `file` and disallowed otherwise. - `branding_settings.icon.url` (string, optional) The URL of the image. Required if `type` is `url` and disallowed otherwise. - `branding_settings.logo` (object, optional) The logo for the Checkout Session. - `branding_settings.logo.type` (enum, required) The type of image for the logo. Must be one of `file` or `url`. - `branding_settings.logo.file` (string, optional) The ID of a [File upload](https://stripe.com/docs/api/files) representing the logo. Purpose must be `business_logo`. Required if `type` is `file` and disallowed otherwise. - `branding_settings.logo.url` (string, optional) The URL of the image. Required if `type` is `url` and disallowed otherwise. - `cancel_url` (string, optional) If set, Checkout displays a back button and customers will be directed to this URL if they decide to cancel payment and return to your website. This parameter is not allowed if ui_mode is `embedded` or `custom`. - `client_reference_id` (string, optional) A unique string to reference the Checkout Session. This can be a customer ID, a cart ID, or similar, and can be used to reconcile the session with your internal systems. The maximum length is 200 characters. - `consent_collection` (object, optional) Configure fields for the Checkout Session to gather active consent from customers. - `consent_collection.payment_method_reuse_agreement` (object, optional) Determines the display of payment method reuse agreement text in the UI. If set to `hidden`, it will hide legal text related to the reuse of a payment method. - `consent_collection.payment_method_reuse_agreement.position` (enum, required) Determines the position and visibility of the payment method reuse agreement in the UI. When set to `auto`, Stripe’s defaults will be used. When set to `hidden`, the payment method reuse agreement text will always be hidden in the UI. Possible enum values: - `auto` Uses Stripe defaults to determine the visibility and position of the payment method reuse agreement. - `hidden` Hides the payment method reuse agreement. - `consent_collection.promotions` (enum, optional) If set to `auto`, enables the collection of customer consent for promotional communications. The Checkout Session will determine whether to display an option to opt into promotional communication from the merchant depending on the customer’s locale. Only available to US merchants. Possible enum values: - `auto` Enable the collection of customer consent for promotional communications. The Checkout Session will determine whether to display an option to opt into promotional communication from the merchant depending on if a customer is provided, and if that customer has consented to receiving promotional communications from the merchant in the past. - `none` Checkout will not collect customer consent for promotional communications. - `consent_collection.terms_of_service` (enum, optional) If set to `required`, it requires customers to check a terms of service checkbox before being able to pay. There must be a valid terms of service URL set in your [Dashboard settings](https://dashboard.stripe.com/settings/public). Possible enum values: - `none` Does not display checkbox for the terms of service agreement. - `required` Displays a checkbox for the terms of service agreement which requires customer to check before being able to pay. - `currency` (enum, required conditionally) 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). Required in `setup` mode when `payment_method_types` is not set. - `custom_fields` (array of objects, optional) Collect additional information from your customer using custom fields. Up to 3 fields are supported. You can’t set this parameter if `ui_mode` is `custom`. - `custom_fields.key` (string, required) String of your choice that your integration can use to reconcile this field. Must be unique to this field, alphanumeric, and up to 200 characters. The maximum length is 200 characters. - `custom_fields.label` (object, required) The label for the field, displayed to the customer. - `custom_fields.label.custom` (string, required) Custom text for the label, displayed to the customer. Up to 50 characters. The maximum length is 50 characters. - `custom_fields.label.type` (enum, required) The type of the label. Possible enum values: - `custom` Set a custom label for the field. - `custom_fields.type` (enum, required) The type of the field. Possible enum values: - `dropdown` Provide a list of options for your customer to select. - `numeric` Collect a numbers-only field from your customer. - `text` Collect a string field from your customer. - `custom_fields.dropdown` (object, optional) Configuration for `type=dropdown` fields. - `custom_fields.dropdown.options` (array of objects, required) The options available for the customer to select. Up to 200 options allowed. - `custom_fields.dropdown.options.label` (string, required) The label for the option, displayed to the customer. Up to 100 characters. The maximum length is 100 characters. - `custom_fields.dropdown.options.value` (string, required) The value for this option, not displayed to the customer, used by your integration to reconcile the option selected by the customer. Must be unique to this option, alphanumeric, and up to 100 characters. The maximum length is 100 characters. - `custom_fields.dropdown.default_value` (string, optional) The value that will pre-fill the field on the payment page.Must match a `value` in the `options` array. The maximum length is 100 characters. - `custom_fields.numeric` (object, optional) Configuration for `type=numeric` fields. - `custom_fields.numeric.default_value` (string, optional) The value that will pre-fill the field on the payment page. The maximum length is 255 characters. - `custom_fields.numeric.maximum_length` (integer, optional) The maximum character length constraint for the customer’s input. - `custom_fields.numeric.minimum_length` (integer, optional) The minimum character length requirement for the customer’s input. - `custom_fields.optional` (boolean, optional) Whether the customer is required to complete the field before completing the Checkout Session. Defaults to `false`. - `custom_fields.text` (object, optional) Configuration for `type=text` fields. - `custom_fields.text.default_value` (string, optional) The value that will pre-fill the field on the payment page. The maximum length is 255 characters. - `custom_fields.text.maximum_length` (integer, optional) The maximum character length constraint for the customer’s input. - `custom_fields.text.minimum_length` (integer, optional) The minimum character length requirement for the customer’s input. - `custom_text` (object, optional) Display additional text for your customers using custom text. You can’t set this parameter if `ui_mode` is `custom`. - `custom_text.after_submit` (object, optional) Custom text that should be displayed after the payment confirmation button. - `custom_text.after_submit.message` (string, required) Text may be up to 1200 characters in length. - `custom_text.shipping_address` (object, optional) Custom text that should be displayed alongside shipping address collection. - `custom_text.shipping_address.message` (string, required) Text may be up to 1200 characters in length. - `custom_text.submit` (object, optional) Custom text that should be displayed alongside the payment confirmation button. - `custom_text.submit.message` (string, required) Text may be up to 1200 characters in length. - `custom_text.terms_of_service_acceptance` (object, optional) Custom text that should be displayed in place of the default terms of service agreement text. - `custom_text.terms_of_service_acceptance.message` (string, required) Text may be up to 1200 characters in length. - `customer` (string, optional) ID of an existing Customer, if one exists. In `payment` mode, the customer’s most recently saved card payment method will be used to prefill the email, name, card details, and billing address on the Checkout page. In `subscription` mode, the customer’s [default payment method](https://docs.stripe.com/docs/api/customers/update.md#update_customer-invoice_settings-default_payment_method) will be used if it’s a card, otherwise the most recently saved card will be used. A valid billing address, billing name and billing email are required on the payment method for Checkout to prefill the customer’s card details. If the Customer already has a valid [email](https://docs.stripe.com/docs/api/customers/object.md#customer_object-email) set, the email will be prefilled and not editable in Checkout. If the Customer does not have a valid `email`, Checkout will set the email entered during the session on the Customer. If blank for Checkout Sessions in `subscription` mode or with `customer_creation` set as `always` in `payment` mode, Checkout will create a new Customer object based on information provided during the payment flow. You can set [`payment_intent_data.setup_future_usage`](https://docs.stripe.com/docs/api/checkout/sessions/create.md#create_checkout_session-payment_intent_data-setup_future_usage) to have Checkout automatically attach the payment method to the Customer you pass in for future reuse. - `customer_account` (string, optional) ID of an existing Account, if one exists. Has the same behavior as `customer`. - `customer_creation` (enum, optional) Configure whether a Checkout Session creates a [Customer](https://docs.stripe.com/docs/api/customers.md) during Session confirmation. When a Customer is not created, you can still retrieve email, address, and other customer data entered in Checkout with [customer_details](https://docs.stripe.com/docs/api/checkout/sessions/object.md#checkout_session_object-customer_details). Sessions that don’t create Customers instead are grouped by [guest customers](https://docs.stripe.com/docs/payments/checkout/guest-customers.md) in the Dashboard. Promotion codes limited to first time customers will return invalid for these Sessions. Can only be set in `payment` and `setup` mode. Possible enum values: - `always` The Checkout Session will always create a [Customer](https://docs.stripe.com/docs/api/customers.md) when a Session confirmation is attempted. - `if_required` The Checkout Session will only create a [Customer](https://docs.stripe.com/docs/api/customers.md) if it is required for Session confirmation. Currently, only `subscription` mode Sessions and `payment` mode Sessions with [post-purchase invoices enabled](https://docs.stripe.com/docs/receipts.md?payment-ui=checkout#paid-invoices) require a Customer. - `customer_email` (string, optional) If provided, this value will be used when the Customer object is created. If not provided, customers will be asked to enter their email address. Use this parameter to prefill customer data if you already have an email on file. To access information about the customer once a session is complete, use the `customer` field. The maximum length is 800 characters. - `customer_update` (object, optional) Controls what fields on Customer can be updated by the Checkout Session. Can only be provided when `customer` is provided. - `customer_update.address` (enum, optional) Describes whether Checkout saves the billing address onto `customer.address`. To always collect a full billing address, use `billing_address_collection`. Defaults to `never`. Possible enum values: - `auto` Checkout will automatically determine whether to update the provided Customer object using details from the session. - `never` Checkout will never update the provided Customer object. - `customer_update.name` (enum, optional) Describes whether Checkout saves the name onto `customer.name`. Defaults to `never`. Possible enum values: - `auto` Checkout will automatically determine whether to update the provided Customer object using details from the session. - `never` Checkout will never update the provided Customer object. - `customer_update.shipping` (enum, optional) Describes whether Checkout saves shipping information onto `customer.shipping`. To collect shipping information, use `shipping_address_collection`. Defaults to `never`. Possible enum values: - `auto` Checkout will automatically determine whether to update the provided Customer object using details from the session. - `never` Checkout will never update the provided Customer object. - `discounts` (array of objects, optional) The coupon or promotion code to apply to this Session. Currently, only up to one may be specified. - `discounts.coupon` (string, optional) The ID of the coupon to apply to this Session. - `discounts.promotion_code` (string, optional) The ID of a promotion code to apply to this Session. - `excluded_payment_method_types` (array of enums, optional) A list of the types of payment methods (e.g., `card`) that should be excluded from this Checkout Session. This should only be used when payment methods for this Checkout Session are managed through the [Stripe Dashboard](https://dashboard.stripe.com/settings/payment_methods). - `expires_at` (timestamp, optional) The Epoch time in seconds at which the Checkout Session will expire. It can be anywhere from 30 minutes to 24 hours after Checkout Session creation. By default, this value is 24 hours from creation. - `invoice_creation` (object, optional) Generate a post-purchase Invoice for one-time payments. - `invoice_creation.enabled` (boolean, required) Set to `true` to enable invoice creation. - `invoice_creation.invoice_data` (object, optional) Parameters passed when creating invoices for payment-mode Checkout Sessions. - `invoice_creation.invoice_data.account_tax_ids` (array of strings, optional) The account tax IDs associated with the invoice. - `invoice_creation.invoice_data.custom_fields` (array of objects, optional) Default custom fields to be displayed on invoices for this customer. - `invoice_creation.invoice_data.custom_fields.name` (string, required) The name of the custom field. This may be up to 40 characters. The maximum length is 40 characters. - `invoice_creation.invoice_data.custom_fields.value` (string, required) The value of the custom field. This may be up to 140 characters. The maximum length is 140 characters. - `invoice_creation.invoice_data.description` (string, optional) An arbitrary string attached to the object. Often useful for displaying to users. - `invoice_creation.invoice_data.footer` (string, optional) Default footer to be displayed on invoices for this customer. - `invoice_creation.invoice_data.issuer` (object, optional) The connected account that issues the invoice. The invoice is presented with the branding and support information of the specified account. - `invoice_creation.invoice_data.issuer.type` (enum, required) Type of the account referenced in the request. Possible enum values: - `account` Indicates that the account being referenced is a connected account which is different from the account making the API request but related to it. - `self` Indicates that the account being referenced is the account making the API request. - `invoice_creation.invoice_data.issuer.account` (string, required only if type is account) The connected account being referenced when `type` is `account`. - `invoice_creation.invoice_data.metadata` (object, optional) Set of [key-value pairs](https://docs.stripe.com/docs/api/metadata.md) that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - `invoice_creation.invoice_data.rendering_options` (object, optional) Default options for invoice PDF rendering for this customer. - `invoice_creation.invoice_data.rendering_options.amount_tax_display` (enum, optional) How line-item prices and amounts will be displayed with respect to tax on invoice PDFs. One of `exclude_tax` or `include_inclusive_tax`. `include_inclusive_tax` will include inclusive tax (and exclude exclusive tax) in invoice PDF amounts. `exclude_tax` will exclude all tax (inclusive and exclusive alike) from invoice PDF amounts. Possible enum values: - `exclude_tax` - `include_inclusive_tax` - `invoice_creation.invoice_data.rendering_options.template` (string, optional) ID of the invoice rendering template to use for this invoice. - `line_items` (array of objects, required conditionally) A list of items the customer is purchasing. Use this parameter to pass one-time or recurring [Prices](https://docs.stripe.com/docs/api/prices.md). The parameter is required for `payment` and `subscription` mode. For `payment` mode, there is a maximum of 100 line items, however it is recommended to consolidate line items if there are more than a few dozen. For `subscription` mode, there is a maximum of 20 line items with recurring Prices and 20 line items with one-time Prices. Line items with one-time Prices will be on the initial invoice only. - `line_items.adjustable_quantity` (object, optional) When set, provides configuration for this item’s quantity to be adjusted by the customer during Checkout. - `line_items.adjustable_quantity.enabled` (boolean, required) Set to true if the quantity can be adjusted to any non-negative integer. - `line_items.adjustable_quantity.maximum` (integer, optional) The maximum quantity the customer can purchase for the Checkout Session. By default this value is 99. You can specify a value up to 999999. - `line_items.adjustable_quantity.minimum` (integer, optional) The minimum quantity the customer must purchase for the Checkout Session. By default this value is 0. - `line_items.dynamic_tax_rates` (array of strings, optional) The [tax rates](https://docs.stripe.com/docs/api/tax_rates.md) that will be applied to this line item depending on the customer’s billing/shipping address. We currently support the following countries: US, GB, AU, and all countries in the EU. You can’t set this parameter if `ui_mode` is `custom`. - `line_items.metadata` (object, optional) Set of [key-value pairs](https://docs.stripe.com/docs/api/metadata.md) that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - `line_items.price` (string, required conditionally) The ID of the [Price](https://docs.stripe.com/docs/api/prices.md) or [Plan](https://docs.stripe.com/docs/api/plans.md) object. One of `price` or `price_data` is required. - `line_items.price_data` (object, required conditionally) Data used to generate a new [Price](https://docs.stripe.com/docs/api/prices.md) object inline. One of `price` or `price_data` is required. - `line_items.price_data.currency` (enum, required) 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). - `line_items.price_data.product` (string, required conditionally) The ID of the [Product](https://docs.stripe.com/api/products.md) that this [Price](https://docs.stripe.com/api/prices.md) will belong to. One of `product` or `product_data` is required. - `line_items.price_data.product_data` (object, required conditionally) Data used to generate a new [Product](https://docs.stripe.com/api/products.md) object inline. One of `product` or `product_data` is required. - `line_items.price_data.product_data.name` (string, required) The product’s name, meant to be displayable to the customer. - `line_items.price_data.product_data.description` (string, optional) The product’s description, meant to be displayable to the customer. Use this field to optionally store a long form explanation of the product being sold for your own rendering purposes. - `line_items.price_data.product_data.images` (array of strings, optional) A list of up to 8 URLs of images for this product, meant to be displayable to the customer. - `line_items.price_data.product_data.metadata` (object, optional) Set of [key-value pairs](https://docs.stripe.com/docs/api/metadata.md) that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - `line_items.price_data.product_data.tax_code` (string, recommended if calculating taxes) A [tax code](https://docs.stripe.com/docs/tax/tax-categories.md) ID. - `line_items.price_data.product_data.unit_label` (string, optional) A label that represents units of this product. When set, this will be included in customers’ receipts, invoices, Checkout, and the customer portal. The maximum length is 12 characters. - `line_items.price_data.recurring` (object, optional) The recurring components of a price such as `interval` and `interval_count`. - `line_items.price_data.recurring.interval` (enum, required) Specifies billing frequency. Either `day`, `week`, `month` or `year`. Possible enum values: - `day` - `month` - `week` - `year` - `line_items.price_data.recurring.interval_count` (integer, optional) The number of intervals between subscription billings. For example, `interval=month` and `interval_count=3` bills every 3 months. Maximum of three years interval allowed (3 years, 36 months, or 156 weeks). - `line_items.price_data.tax_behavior` (enum, recommended if calculating taxes) Only required if a [default tax behavior](https://docs.stripe.com/docs/tax/products-prices-tax-categories-tax-behavior.md#setting-a-default-tax-behavior-\(recommended\)) was not provided in the Stripe Tax settings. Specifies whether the price is considered inclusive of taxes or exclusive of taxes. One of `inclusive`, `exclusive`, or `unspecified`. Once specified as either `inclusive` or `exclusive`, it cannot be changed. Possible enum values: - `exclusive` - `inclusive` - `unspecified` - `line_items.price_data.unit_amount` (integer, required conditionally) A non-negative integer in cents representing how much to charge. One of `unit_amount` or `unit_amount_decimal` is required. - `line_items.price_data.unit_amount_decimal` (string, required conditionally) Same as `unit_amount`, but accepts a decimal value in cents with at most 12 decimal places. Only one of `unit_amount` and `unit_amount_decimal` can be set. - `line_items.quantity` (integer, required conditionally) The quantity of the line item being purchased. Quantity should not be defined when `recurring.usage_type=metered`. - `line_items.tax_rates` (array of strings, optional) The [tax rates](https://docs.stripe.com/docs/api/tax_rates.md) which apply to this line item. - `locale` (enum, optional) The IETF language tag of the locale Checkout is displayed in. If blank or `auto`, the browser’s locale is used. Possible enum values: - `auto` - `bg` - `cs` - `da` - `de` - `el` - `en` - `en-GB` - `es` - `es-419` - `et` - `fi` - `fil` - `fr` - `fr-CA` - `hr` - `hu` - `id` - `it` - `ja` - `ko` - `lt` - `lv` - `ms` - `mt` - `nb` - `nl` - `pl` - `pt` - `pt-BR` - `ro` - `ru` - `sk` - `sl` - `sv` - `th` - `tr` - `vi` - `zh` - `zh-HK` - `zh-TW` - `metadata` (object, optional) Set of [key-value pairs](https://docs.stripe.com/docs/api/metadata.md) that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - `mode` (enum, required) The mode of the Checkout Session. Pass `subscription` if the Checkout Session includes at least one recurring item. Possible enum values: - `payment` Accept one-time payments for cards, iDEAL, and more. - `setup` Save payment details to charge your customers later. - `subscription` Use Stripe Billing to set up fixed-price subscriptions. - `name_collection` (object, optional) Controls name collection settings for the session. You can configure Checkout to collect your customers’ business names, individual names, or both. Each name field can be either required or optional. If a [Customer](https://docs.stripe.com/docs/api/customers.md) is created or provided, the names can be saved to the Customer object as well. You can’t set this parameter if `ui_mode` is `custom`. - `name_collection.business` (object, optional) Controls settings applied for collecting the customer’s business name on the session. - `name_collection.business.enabled` (boolean, required) Enable business name collection on the Checkout Session. Defaults to `false`. - `name_collection.business.optional` (boolean, optional) Whether the customer is required to provide a business name before completing the Checkout Session. Defaults to `false`. - `name_collection.individual` (object, optional) Controls settings applied for collecting the customer’s individual name on the session. - `name_collection.individual.enabled` (boolean, required) Enable individual name collection on the Checkout Session. Defaults to `false`. - `name_collection.individual.optional` (boolean, optional) Whether the customer is required to provide their name before completing the Checkout Session. Defaults to `false`. - `optional_items` (array of objects, optional) A list of optional items the customer can add to their order at checkout. Use this parameter to pass one-time or recurring [Prices](https://docs.stripe.com/docs/api/prices.md). There is a maximum of 10 optional items allowed on a Checkout Session, and the existing limits on the number of line items allowed on a Checkout Session apply to the combined number of line items and optional items. For `payment` mode, there is a maximum of 100 combined line items and optional items, however it is recommended to consolidate items if there are more than a few dozen. For `subscription` mode, there is a maximum of 20 line items and optional items with recurring Prices and 20 line items and optional items with one-time Prices. You can’t set this parameter if `ui_mode` is `custom`. - `optional_items.price` (string, required) The ID of the [Price](https://docs.stripe.com/docs/api/prices.md) or [Plan](https://docs.stripe.com/docs/api/plans.md) object. - `optional_items.quantity` (integer, required) The initial quantity of the line item created when a customer chooses to add this optional item to their order. - `optional_items.adjustable_quantity` (object, optional) When set, provides configuration for the customer to adjust the quantity of the line item created when a customer chooses to add this optional item to their order. - `optional_items.adjustable_quantity.enabled` (boolean, required) Set to true if the quantity can be adjusted to any non-negative integer. - `optional_items.adjustable_quantity.maximum` (integer, optional) The maximum quantity of this item the customer can purchase. By default this value is 99. You can specify a value up to 999999. - `optional_items.adjustable_quantity.minimum` (integer, optional) The minimum quantity of this item the customer must purchase, if they choose to purchase it. Because this item is optional, the customer will always be able to remove it from their order, even if the `minimum` configured here is greater than 0. By default this value is 0. - `origin_context` (enum, optional) Where the user is coming from. This informs the optimizations that are applied to the session. You can’t set this parameter if `ui_mode` is `custom`. Possible enum values: - `mobile_app` The Checkout Session originates from a mobile app. - `web` The Checkout Session originates from a web page. - `payment_intent_data` (object, optional) A subset of parameters to be passed to PaymentIntent creation for Checkout Sessions in `payment` mode. - `payment_intent_data.application_fee_amount` (integer, optional) The amount of the application fee (if any) that will be requested to be applied to the payment and transferred to the application owner’s Stripe account. The amount of the application fee collected will be capped at the total amount captured. For more information, see the PaymentIntents [use case for connected accounts](https://docs.stripe.com/docs/payments/connected-accounts.md). - `payment_intent_data.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `automatic` Stripe automatically captures funds when the customer authorizes the payment. - `automatic_async` (Default) Stripe asynchronously captures funds when the customer authorizes the payment. Recommended over `capture_method=automatic` due to improved latency. Read the [integration guide](https://docs.stripe.com/docs/payments/payment-intents/asynchronous-capture.md) for more information. - `manual` Place a hold on the funds when the customer authorizes the payment, but [don’t capture the funds until later](https://docs.stripe.com/docs/payments/capture-later.md). (Not all payment methods support this.) - `payment_intent_data.description` (string, optional) An arbitrary string attached to the object. Often useful for displaying to users. - `payment_intent_data.metadata` (object, optional) Set of [key-value pairs](https://docs.stripe.com/docs/api/metadata.md) that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - `payment_intent_data.on_behalf_of` (string, optional) The Stripe account ID for which these funds are intended. For details, see the PaymentIntents [use case for connected accounts](https://docs.stripe.com/docs/payments/connected-accounts.md). - `payment_intent_data.receipt_email` (string, optional) Email address that the receipt for the resulting payment will be sent to. If `receipt_email` is specified for a payment in live mode, a receipt will be sent regardless of your [email settings](https://dashboard.stripe.com/account/emails). - `payment_intent_data.setup_future_usage` (enum, optional) Indicates that you intend to [make future payments](https://docs.stripe.com/docs/payments/payment-intents.md#future-usage) with the payment method collected by this Checkout Session. When setting this to `on_session`, Checkout will show a notice to the customer that their payment details will be saved. When setting this to `off_session`, Checkout will show a notice to the customer that their payment details will be saved and used for future payments. If a Customer has been provided or Checkout creates a new Customer, Checkout will attach the payment method to the Customer. If Checkout does not create a Customer, the payment method is not attached to a Customer. To reuse the payment method, you can retrieve it from the Checkout Session’s PaymentIntent. When processing card payments, Checkout also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. Possible enum values: - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `on_session` Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. - `payment_intent_data.shipping` (object, optional) Shipping information for this payment. - `payment_intent_data.shipping.address` (object, required) Shipping address. - `payment_intent_data.shipping.address.line1` (string, required) Address line 1, such as the street, PO Box, or company name. - `payment_intent_data.shipping.address.city` (string, optional) City, district, suburb, town, or village. - `payment_intent_data.shipping.address.country` (string, optional) Two-letter country code ([ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)). - `payment_intent_data.shipping.address.line2` (string, optional) Address line 2, such as the apartment, suite, unit, or building. - `payment_intent_data.shipping.address.postal_code` (string, optional) ZIP or postal code. - `payment_intent_data.shipping.address.state` (string, optional) State, county, province, or region ([ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-2)). - `payment_intent_data.shipping.name` (string, required) Recipient name. - `payment_intent_data.shipping.carrier` (string, optional) The delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. - `payment_intent_data.shipping.phone` (string, optional) Recipient phone (including extension). - `payment_intent_data.shipping.tracking_number` (string, optional) The tracking number for a physical product, obtained from the delivery service. If multiple tracking numbers were generated for this purchase, please separate them with commas. - `payment_intent_data.statement_descriptor` (string, optional) Text that appears on the customer’s statement as the statement descriptor for a non-card charge. This value overrides the account’s default statement descriptor. For information about requirements, including the 22-character limit, see [the Statement Descriptor docs](https://docs.stripe.com/get-started/account/statement-descriptors.md). Setting this value for a card charge returns an error. For card charges, set the [statement_descriptor_suffix](https://docs.stripe.com/get-started/account/statement-descriptors.md#dynamic) instead. - `payment_intent_data.statement_descriptor_suffix` (string, optional) Provides information about a card charge. Concatenated to the account’s [statement descriptor prefix](https://docs.stripe.com/get-started/account/statement-descriptors.md#static) to form the complete statement descriptor that appears on the customer’s statement. - `payment_intent_data.transfer_data` (object, optional) The parameters used to automatically create a Transfer when the payment succeeds. For more information, see the PaymentIntents [use case for connected accounts](https://docs.stripe.com/docs/payments/connected-accounts.md). - `payment_intent_data.transfer_data.destination` (string, required) If specified, successful charges will be attributed to the destination account for tax reporting, and the funds from charges will be transferred to the destination account. The ID of the resulting transfer will be returned on the successful charge’s `transfer` field. - `payment_intent_data.transfer_data.amount` (integer, optional) The amount that will be transferred automatically when a charge succeeds. - `payment_intent_data.transfer_group` (string, optional) A string that identifies the resulting payment as part of a group. See the PaymentIntents [use case for connected accounts](https://docs.stripe.com/docs/connect/separate-charges-and-transfers.md) for details. - `payment_method_collection` (enum, optional) Specify whether Checkout should collect a payment method. When set to `if_required`, Checkout will not collect a payment method when the total due for the session is 0. This may occur if the Checkout Session includes a free trial or a discount. Can only be set in `subscription` mode. Defaults to `always`. If you’d like information on how to collect a payment method outside of Checkout, read the guide on configuring [subscriptions with a free trial](https://docs.stripe.com/docs/payments/checkout/free-trials.md). Possible enum values: - `always` The Checkout Session will always collect a PaymentMethod. - `if_required` The Checkout Session will only collect a PaymentMethod if there is an amount due. - `payment_method_configuration` (string, optional) The ID of the payment method configuration to use with this Checkout session. The maximum length is 100 characters. - `payment_method_data` (object, optional) This parameter allows you to set some attributes on the payment method created during a Checkout session. - `payment_method_data.allow_redisplay` (enum, optional) Allow redisplay will be set on the payment method on confirmation and indicates whether this payment method can be shown again to the customer in a checkout flow. Only set this field if you wish to override the allow_redisplay value determined by Checkout. Possible enum values: - `always` Use `always` to indicate that this payment method can always be shown to a customer in a checkout flow. - `limited` Use `limited` to indicate that this payment method can’t always be shown to a customer in a checkout flow. For example, it can only be shown in the context of a specific subscription. - `unspecified` This is the default value for payment methods where `allow_redisplay` wasn’t set. - `payment_method_options` (object, optional) Payment-method-specific configuration. - `payment_method_options.acss_debit` (object, optional) contains details about the ACSS Debit payment method options. You can’t set this parameter if `ui_mode` is `custom`. - `payment_method_options.acss_debit.currency` (enum, optional) 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). This is only accepted for Checkout Sessions in `setup` mode. Possible enum values: - `cad` Canadian dollars - `usd` US dollars - `payment_method_options.acss_debit.mandate_options` (object, optional) Additional fields for Mandate creation - `payment_method_options.acss_debit.mandate_options.custom_mandate_url` (string, optional) A URL for custom mandate text to render during confirmation step. The URL will be rendered with additional GET parameters `payment_intent` and `payment_intent_client_secret` when confirming a Payment Intent, or `setup_intent` and `setup_intent_client_secret` when confirming a Setup Intent. - `payment_method_options.acss_debit.mandate_options.default_for` (array of enums, optional) List of Stripe products where this mandate can be selected automatically. Only usable in `setup` mode. Possible enum values: - `invoice` Enables payments for Stripe Invoices. ‘subscription’ must also be provided. - `subscription` Enables payments for Stripe Subscriptions. ‘invoice’ must also be provided. - `payment_method_options.acss_debit.mandate_options.interval_description` (string, optional) Description of the mandate interval. Only required if ‘payment_schedule’ parameter is ‘interval’ or ‘combined’. The maximum length is 500 characters. - `payment_method_options.acss_debit.mandate_options.payment_schedule` (enum, optional) Payment schedule for the mandate. Possible enum values: - `combined` Payments can be initiated at a pre-defined interval or sporadically - `interval` Payments are initiated at a regular pre-defined interval - `sporadic` Payments are initiated sporadically - `payment_method_options.acss_debit.mandate_options.transaction_type` (enum, optional) Transaction type of the mandate. Possible enum values: - `business` Transactions are made for business reasons - `personal` Transactions are made for personal reasons - `payment_method_options.acss_debit.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `on_session` Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. - `payment_method_options.acss_debit.target_date` (string, optional) Controls when Stripe will attempt to debit the funds from the customer’s account. The date must be a string in YYYY-MM-DD format. The date must be in the future and between 3 and 15 calendar days from now. - `payment_method_options.acss_debit.verification_method` (enum, optional) Verification method for the intent Possible enum values: - `automatic` Instant verification with fallback to microdeposits. - `instant` Instant verification. - `microdeposits` Verification using microdeposits. - `payment_method_options.affirm` (object, optional) contains details about the Affirm payment method options. - `payment_method_options.affirm.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.affirm.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.afterpay_clearpay` (object, optional) contains details about the Afterpay Clearpay payment method options. - `payment_method_options.afterpay_clearpay.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.afterpay_clearpay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.alipay` (object, optional) contains details about the Alipay payment method options. - `payment_method_options.alipay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.alma` (object, optional) contains details about the Alma payment method options. - `payment_method_options.alma.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.amazon_pay` (object, optional) contains details about the AmazonPay payment method options. - `payment_method_options.amazon_pay.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.amazon_pay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `payment_method_options.au_becs_debit` (object, optional) contains details about the AU Becs Debit payment method options. - `payment_method_options.au_becs_debit.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.au_becs_debit.target_date` (string, optional) Controls when Stripe will attempt to debit the funds from the customer’s account. The date must be a string in YYYY-MM-DD format. The date must be in the future and between 3 and 15 calendar days from now. - `payment_method_options.bacs_debit` (object, optional) contains details about the Bacs Debit payment method options. - `payment_method_options.bacs_debit.mandate_options` (object, optional) Additional fields for Mandate creation - `payment_method_options.bacs_debit.mandate_options.reference_prefix` (string, optional) Prefix used to generate the Mandate reference. Must be at most 12 characters long. Must consist of only uppercase letters, numbers, spaces, or the following special characters: ‘/’, ‘_’, ‘-’, ‘&’, ‘.’. Cannot begin with ‘DDIC’ or ‘STRIPE’. The maximum length is 12 characters. - `payment_method_options.bacs_debit.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `on_session` Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. - `payment_method_options.bacs_debit.target_date` (string, optional) Controls when Stripe will attempt to debit the funds from the customer’s account. The date must be a string in YYYY-MM-DD format. The date must be in the future and between 3 and 15 calendar days from now. - `payment_method_options.bancontact` (object, optional) contains details about the Bancontact payment method options. - `payment_method_options.bancontact.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.billie` (object, optional) contains details about the Billie payment method options. - `payment_method_options.billie.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.boleto` (object, optional) contains details about the Boleto payment method options. - `payment_method_options.boleto.expires_after_days` (integer, optional) The number of calendar days before a Boleto voucher expires. For example, if you create a Boleto voucher on Monday and you set expires_after_days to 2, the Boleto invoice will expire on Wednesday at 23:59 America/Sao_Paulo time. - `payment_method_options.boleto.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `on_session` Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. - `payment_method_options.card` (object, optional) contains details about the Card payment method options. - `payment_method_options.card.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.card.installments` (object, optional) Installment options for card payments - `payment_method_options.card.installments.enabled` (boolean, optional) Setting to true enables installments for this Checkout Session. Setting to false will prevent any installment plan from applying to a payment. - `payment_method_options.card.request_extended_authorization` (enum, optional) Request ability to [capture beyond the standard authorization validity window](https://docs.stripe.com/payments/extended-authorization.md) for this CheckoutSession. Possible enum values: - `if_available` Use `if_available` if you want to extend the capture window when eligible for extended authorization. - `never` Use `never` if you don’t want to extend the capture window. - `payment_method_options.card.request_incremental_authorization` (enum, optional) Request ability to [increment the authorization](https://docs.stripe.com/payments/incremental-authorization.md) for this CheckoutSession. Possible enum values: - `if_available` Use `if_available` if you want to increment the authorization on the PaymentIntent when eligible. - `never` Use `never` if you don’t want to increment the authorization on the PaymentIntent. - `payment_method_options.card.request_multicapture` (enum, optional) Request ability to make [multiple captures](https://docs.stripe.com/payments/multicapture.md) for this CheckoutSession. Possible enum values: - `if_available` Use `if_available` if you want to use multicapture when eligible. - `never` Use `never` if you don’t want to use multicapture. - `payment_method_options.card.request_overcapture` (enum, optional) Request ability to [overcapture](https://docs.stripe.com/payments/overcapture.md) for this CheckoutSession. Possible enum values: - `if_available` Use `if_available` if you want to overcapture the payment when eligible. - `never` Use `never` if you don’t want to overcapture the payment. - `payment_method_options.card.request_three_d_secure` (enum, optional) We strongly recommend that you rely on our SCA Engine to automatically prompt your customers for authentication based on risk level and [other requirements](https://docs.stripe.com/docs/strong-customer-authentication.md). However, if you wish to request 3D Secure based on logic from your own fraud engine, provide this option. If not provided, this value defaults to `automatic`. Read our guide on [manually requesting 3D Secure](https://docs.stripe.com/docs/payments/3d-secure/authentication-flow.md#manual-three-ds) for more information on how this configuration interacts with Radar and our SCA Engine. Possible enum values: - `any` Use `any` to manually request 3DS with a preference for a `frictionless` flow, increasing the likelihood of the authentication being completed without any additional input from the customer. 3DS will always be attempted if it is supported for the card, but Stripe can’t guarantee your preference because the issuer determines the ultimate authentication flow. To learn more about 3DS flows, read our [guide](https://stripe.com/guides/3d-secure-2#frictionless-authentication). - `automatic` (Default) Our SCA Engine automatically prompts your customers for authentication based on risk level and other requirements. - `challenge` Use `challenge` to request 3DS with a preference for a `challenge` flow, where the customer must respond to a prompt for active authentication. Stripe can’t guarantee your preference because the issuer determines the ultimate authentication flow. To learn more about 3DS flows, read our [guide](https://stripe.com/guides/3d-secure-2#frictionless-authentication). - `payment_method_options.card.restrictions` (object, optional) Restrictions to apply to the card payment method. For example, you can block specific card brands. You can’t set this parameter if `ui_mode` is `custom`. - `payment_method_options.card.restrictions.brands_blocked` (array of enums, optional) Specify the card brands to block in the Checkout Session. If a customer enters or selects a card belonging to a blocked brand, they can’t complete the Session. Possible enum values: - `american_express` Include `american_express` to block American Express cards. - `discover_global_network` Include `discover_global_network` to block all cards within the Discover Global Network. This encompasses the following card brands: - Discover - Diners Club - JCB - UnionPay - Elo - `mastercard` Include `mastercard` to block Mastercard cards. - `visa` Include `visa` to block Visa cards. - `payment_method_options.card.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `on_session` Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. - `payment_method_options.card.statement_descriptor_suffix_kana` (string, optional) Provides information about a card payment that customers see on their statements. Concatenated with the Kana prefix (shortened Kana descriptor) or Kana statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters. On card statements, the *concatenation* of both prefix and suffix (including separators) will appear truncated to 22 characters. - `payment_method_options.card.statement_descriptor_suffix_kanji` (string, optional) Provides information about a card payment that customers see on their statements. Concatenated with the Kanji prefix (shortened Kanji descriptor) or Kanji statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 17 characters. On card statements, the *concatenation* of both prefix and suffix (including separators) will appear truncated to 17 characters. - `payment_method_options.cashapp` (object, optional) contains details about the Cashapp Pay payment method options. - `payment_method_options.cashapp.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.cashapp.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `on_session` Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. - `payment_method_options.customer_balance` (object, optional) contains details about the Customer Balance payment method options. - `payment_method_options.customer_balance.bank_transfer` (object, optional) Configuration for the bank transfer funding type, if the `funding_type` is set to `bank_transfer`. - `payment_method_options.customer_balance.bank_transfer.type` (enum, required) The list of bank transfer types that this PaymentIntent is allowed to use for funding. Possible enum values: - `eu_bank_transfer` eu_bank_transfer bank transfer type - `gb_bank_transfer` gb_bank_transfer bank transfer type - `jp_bank_transfer` jp_bank_transfer bank transfer type - `mx_bank_transfer` mx_bank_transfer bank transfer type - `us_bank_transfer` us_bank_transfer bank transfer type - `payment_method_options.customer_balance.bank_transfer.eu_bank_transfer` (object, optional) Configuration for eu_bank_transfer funding type. - `payment_method_options.customer_balance.bank_transfer.eu_bank_transfer.country` (string, required) The desired country code of the bank account information. Permitted values include: `BE`, `DE`, `ES`, `FR`, `IE`, or `NL`. - `payment_method_options.customer_balance.bank_transfer.requested_address_types` (array of enums, optional) List of address types that should be returned in the financial_addresses response. If not specified, all valid types will be returned. Permitted values include: `sort_code`, `zengin`, `iban`, or `spei`. Possible enum values: - `aba` aba bank account address type - `iban` iban bank account address type - `sepa` sepa bank account address type - `sort_code` sort_code bank account address type - `spei` spei bank account address type - `swift` swift bank account address type - `zengin` zengin bank account address type - `payment_method_options.customer_balance.funding_type` (enum, optional) The funding method type to be used when there are not enough funds in the customer balance. Permitted values include: `bank_transfer`. Possible enum values: - `bank_transfer` - `payment_method_options.customer_balance.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.demo_pay` (object, optional) contains details about the DemoPay payment method options. - `payment_method_options.demo_pay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `payment_method_options.eps` (object, optional) contains details about the EPS payment method options. - `payment_method_options.eps.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.fpx` (object, optional) contains details about the FPX payment method options. - `payment_method_options.fpx.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.giropay` (object, optional) contains details about the Giropay payment method options. - `payment_method_options.giropay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.grabpay` (object, optional) contains details about the Grabpay payment method options. - `payment_method_options.grabpay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.ideal` (object, optional) contains details about the Ideal payment method options. - `payment_method_options.ideal.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.kakao_pay` (object, optional) contains details about the Kakao Pay payment method options. - `payment_method_options.kakao_pay.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.kakao_pay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `payment_method_options.klarna` (object, optional) contains details about the Klarna payment method options. - `payment_method_options.klarna.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.klarna.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.klarna.subscriptions` (array of objects, optional) Subscription details if the Checkout Session sets up a future subscription. - `payment_method_options.klarna.subscriptions.interval` (enum, required) Unit of time between subscription charges. - `payment_method_options.klarna.subscriptions.next_billing` (object, required) Describes the upcoming charge for this subscription. - `payment_method_options.klarna.subscriptions.next_billing.amount` (integer, required) The amount of the next charge for the subscription. - `payment_method_options.klarna.subscriptions.next_billing.date` (string, required) The date of the next charge for the subscription in YYYY-MM-DD format. - `payment_method_options.klarna.subscriptions.reference` (string, required) A non-customer-facing reference to correlate subscription charges in the Klarna app. Use a value that persists across subscription charges. The maximum length is 255 characters. - `payment_method_options.klarna.subscriptions.interval_count` (integer, optional) The number of intervals (specified in the `interval` attribute) between subscription charges. For example, `interval=month` and `interval_count=3` charges every 3 months. - `payment_method_options.klarna.subscriptions.name` (string, optional) Name for subscription. The maximum length is 255 characters. - `payment_method_options.konbini` (object, optional) contains details about the Konbini payment method options. - `payment_method_options.konbini.expires_after_days` (integer, optional) The number of calendar days (between 1 and 60) after which Konbini payment instructions will expire. For example, if a PaymentIntent is confirmed with Konbini and `expires_after_days` set to 2 on Monday JST, the instructions will expire on Wednesday 23:59:59 JST. Defaults to 3 days. - `payment_method_options.konbini.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.kr_card` (object, optional) contains details about the Korean card payment method options. - `payment_method_options.kr_card.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.kr_card.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `payment_method_options.link` (object, optional) contains details about the Link payment method options. - `payment_method_options.link.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.link.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `payment_method_options.mobilepay` (object, optional) contains details about the Mobilepay payment method options. - `payment_method_options.mobilepay.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.mobilepay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.multibanco` (object, optional) contains details about the Multibanco payment method options. - `payment_method_options.multibanco.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.naver_pay` (object, optional) contains details about the Naver Pay payment method options. - `payment_method_options.naver_pay.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.naver_pay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `payment_method_options.oxxo` (object, optional) contains details about the OXXO payment method options. - `payment_method_options.oxxo.expires_after_days` (integer, optional) The number of calendar days before an OXXO voucher expires. For example, if you create an OXXO voucher on Monday and you set expires_after_days to 2, the OXXO invoice will expire on Wednesday at 23:59 America/Mexico_City time. - `payment_method_options.oxxo.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.p24` (object, optional) contains details about the P24 payment method options. - `payment_method_options.p24.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.p24.tos_shown_and_accepted` (boolean, optional) Confirm that the payer has accepted the P24 terms and conditions. - `payment_method_options.pay_by_bank` (object, optional) contains details about the Pay By Bank payment method options. - `payment_method_options.payco` (object, optional) contains details about the PAYCO payment method options. - `payment_method_options.payco.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.paynow` (object, optional) contains details about the PayNow payment method options. - `payment_method_options.paynow.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.paypal` (object, optional) contains details about the PayPal payment method options. - `payment_method_options.paypal.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.paypal.preferred_locale` (enum, optional) [Preferred locale](https://docs.stripe.com/docs/payments/paypal/supported-locales.md) of the PayPal checkout page that the customer is redirected to. Possible enum values: - `cs-CZ` Czech - The Czech Republic - `da-DK` Danish - Denmark - `de-AT` German - Austria - `de-DE` German - Germany - `de-LU` German - Luxembourg - `el-GR` Greek - Greece - `en-GB` English - United Kingdom - `en-US` English - United States of America - `es-ES` Spanish - Spain - `fi-FI` Finnish - Finland - `fr-BE` French - Belgium - `fr-FR` French - France - `fr-LU` French - Luxembourg - `hu-HU` Hungarian - Hungary - `it-IT` Italian - Italy - `nl-BE` Dutch - Belgium - `nl-NL` Dutch - Netherlands - `pl-PL` Polish - Poland - `pt-PT` Portuguese - Portugal - `sk-SK` Slovak - Slovakia - `sv-SE` Swedish - Sweden - `payment_method_options.paypal.reference` (string, optional) A reference of the PayPal transaction visible to customer which is mapped to PayPal’s invoice ID. This must be a globally unique ID if you have configured in your PayPal settings to block multiple payments per invoice ID. The maximum length is 127 characters. - `payment_method_options.paypal.risk_correlation_id` (string, optional) The risk correlation ID for an on-session payment using a saved PayPal payment method. The maximum length is 32 characters. - `payment_method_options.paypal.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). If you’ve already set `setup_future_usage` and you’re performing a request using a publishable key, you can only update the value from `on_session` to `off_session`. Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `payment_method_options.payto` (object, optional) contains details about the PayTo payment method options. - `payment_method_options.payto.mandate_options` (object, optional) Additional fields for Mandate creation - `payment_method_options.payto.mandate_options.amount` (integer, optional) Amount that will be collected. It is required when `amount_type` is `fixed`. - `payment_method_options.payto.mandate_options.amount_type` (enum, optional) The type of amount that will be collected. The amount charged must be exact or up to the value of `amount` param for `fixed` or `maximum` type respectively. Defaults to `maximum`. Possible enum values: - `fixed` The amount is the exact amount that will be charged. - `maximum` The amount is the maximum amount that can be charged. - `payment_method_options.payto.mandate_options.end_date` (string, optional) Date, in YYYY-MM-DD format, after which payments will not be collected. Defaults to no end date. - `payment_method_options.payto.mandate_options.payment_schedule` (enum, optional) The periodicity at which payments will be collected. Defaults to `adhoc`. Possible enum values: - `adhoc` Payments will be made ad hoc - `annual` Payments will be made annually - `daily` Payments will be made daily - `fortnightly` Payments will be made fortnightly - `monthly` Payments will be made monthly - `quarterly` Payments will be made quarterly - `semi_annual` Payments will be made semi-annually - `weekly` Payments will be made weekly - `payment_method_options.payto.mandate_options.payments_per_period` (integer, optional) The number of payments that will be made during a payment period. Defaults to 1 except for when `payment_schedule` is `adhoc`. In that case, it defaults to no limit. - `payment_method_options.payto.mandate_options.purpose` (enum, optional) The purpose for which payments are made. Has a default value based on your merchant category code. Possible enum values: - `dependant_support` Transactions are made for dependant support reasons - `government` Transactions are made for government reasons - `loan` Transactions are made for loan reasons - `mortgage` Transactions are made for mortgage reasons - `other` Transactions are made for other reasons - `pension` Transactions are made for pension reasons - `personal` Transactions are made for personal reasons - `retail` Transactions are made for retail reasons - `salary` Transactions are made for salary reasons - `tax` Transactions are made for tax reasons - `utility` Transactions are made for utility reasons - `payment_method_options.payto.mandate_options.start_date` (string, optional) Date, in YYYY-MM-DD format, from which payments will be collected. Defaults to confirmation time. - `payment_method_options.payto.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `payment_method_options.pix` (object, optional) contains details about the Pix payment method options. - `payment_method_options.pix.amount_includes_iof` (enum, optional) Determines if the amount includes the IOF tax. Defaults to `never`. Possible enum values: - `always` The IOF tax is included in the amount. - `never` The IOF tax is not included in the amount. - `payment_method_options.pix.expires_after_seconds` (integer, optional) The number of seconds (between 10 and 1209600) after which Pix payment will expire. Defaults to 86400 seconds. - `payment_method_options.pix.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.revolut_pay` (object, optional) contains details about the RevolutPay payment method options. - `payment_method_options.revolut_pay.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.revolut_pay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `payment_method_options.samsung_pay` (object, optional) contains details about the Samsung Pay payment method options. - `payment_method_options.samsung_pay.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.satispay` (object, optional) contains details about the Satispay payment method options. - `payment_method_options.satispay.capture_method` (enum, optional) Controls when the funds will be captured from the customer’s account. Possible enum values: - `manual` Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. - `payment_method_options.sepa_debit` (object, optional) contains details about the Sepa Debit payment method options. - `payment_method_options.sepa_debit.mandate_options` (object, optional) Additional fields for Mandate creation - `payment_method_options.sepa_debit.mandate_options.reference_prefix` (string, optional) Prefix used to generate the Mandate reference. Must be at most 12 characters long. Must consist of only uppercase letters, numbers, spaces, or the following special characters: ‘/’, ‘_’, ‘-’, ‘&’, ‘.’. Cannot begin with ‘STRIPE’. The maximum length is 12 characters. - `payment_method_options.sepa_debit.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `on_session` Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. - `payment_method_options.sepa_debit.target_date` (string, optional) Controls when Stripe will attempt to debit the funds from the customer’s account. The date must be a string in YYYY-MM-DD format. The date must be in the future and between 3 and 15 calendar days from now. - `payment_method_options.sofort` (object, optional) contains details about the Sofort payment method options. - `payment_method_options.sofort.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.swish` (object, optional) contains details about the Swish payment method options. - `payment_method_options.swish.reference` (string, optional) The order reference that will be displayed to customers in the Swish application. Defaults to the `id` of the Payment Intent. - `payment_method_options.twint` (object, optional) contains details about the TWINT payment method options. - `payment_method_options.twint.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_options.us_bank_account` (object, optional) contains details about the Us Bank Account payment method options. - `payment_method_options.us_bank_account.financial_connections` (object, optional) Additional fields for Financial Connections Session creation - `payment_method_options.us_bank_account.financial_connections.permissions` (array of strings, optional) The list of permissions to request. If this parameter is passed, the `payment_method` permission must be included. Valid permissions include: `balances`, `ownership`, `payment_method`, and `transactions`. - `payment_method_options.us_bank_account.financial_connections.prefetch` (array of enums, optional) List of data features that you would like to retrieve upon account creation. Possible enum values: - `balances` Requests to prefetch balance data on accounts collected in this session. - `ownership` Requests to prefetch ownership data on accounts collected in this session. - `transactions` Requests to prefetch transaction data on accounts collected in this session. - `payment_method_options.us_bank_account.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `off_session` Use `off_session` if your customer may or may not be present in your checkout flow. - `on_session` Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. - `payment_method_options.us_bank_account.target_date` (string, optional) Controls when Stripe will attempt to debit the funds from the customer’s account. The date must be a string in YYYY-MM-DD format. The date must be in the future and between 3 and 15 calendar days from now. - `payment_method_options.us_bank_account.verification_method` (enum, optional) Verification method for the intent Possible enum values: - `automatic` Instant verification with fallback to microdeposits. - `instant` Instant verification only. - `payment_method_options.wechat_pay` (object, optional) contains details about the WeChat Pay payment method options. - `payment_method_options.wechat_pay.client` (enum, required) The client type that the end customer will pay from Possible enum values: - `android` The end customer will pay from an Android app - `ios` The end customer will pay from an iOS app - `web` The end customer will pay from web browser - `payment_method_options.wechat_pay.app_id` (string, optional) The app ID registered with WeChat Pay. Only required when client is ios or android. - `payment_method_options.wechat_pay.setup_future_usage` (enum, optional) Indicates that you intend to make future payments with this PaymentIntent’s payment method. If you provide a Customer with the PaymentIntent, you can use this parameter to [attach the payment method](https://docs.stripe.com/payments/save-during-payment.md) to the Customer after the PaymentIntent is confirmed and the customer completes any required actions. If you don’t provide a Customer, you can still [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a Customer after the transaction completes. If the payment method is `card_present` and isn’t a digital wallet, Stripe creates and attaches a [generated_card](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-generated_card) payment method representing the card to the Customer instead. When processing card payments, Stripe uses `setup_future_usage` to help you comply with regional legislation and network rules, such as [SCA](https://docs.stripe.com/strong-customer-authentication.md). Possible enum values: - `none` Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. - `payment_method_types` (array of enums, optional) A list of the types of payment methods (e.g., `card`) this Checkout Session can accept. You can omit this attribute to manage your payment methods from the [Stripe Dashboard](https://dashboard.stripe.com/settings/payment_methods). See [Dynamic Payment Methods](https://docs.stripe.com/docs/payments/payment-methods/integration-options.md#using-dynamic-payment-methods) for more details. Read more about the supported payment methods and their requirements in our [payment method details guide](https://docs.stripe.com/docs/payments/checkout/payment-methods.md). If multiple payment methods are passed, Checkout will dynamically reorder them to prioritize the most relevant payment methods based on the customer’s location and other characteristics. - `permissions` (object, optional) This property is used to set up permissions for various actions (e.g., update) on the CheckoutSession object. Can only be set when creating `embedded` or `custom` sessions. For specific permissions, please refer to their dedicated subsections, such as `permissions.update_shipping_details`. - `permissions.update_shipping_details` (enum, optional) Determines which entity is allowed to update the shipping details. Default is `client_only`. Stripe Checkout client will automatically update the shipping details. If set to `server_only`, only your server is allowed to update the shipping details. When set to `server_only`, you must add the onShippingDetailsChange event handler when initializing the Stripe Checkout client and manually update the shipping details from your server using the Stripe API. Possible enum values: - `client_only` The field of the CheckoutSession can only be updated by the client via the publishable key. - `server_only` The field of the CheckoutSession can only be updated by the server via the secret key. - `phone_number_collection` (object, optional) Controls phone number collection settings for the session. We recommend that you review your privacy policy and check with your legal contacts before using this feature. Learn more about [collecting phone numbers with Checkout](https://docs.stripe.com/docs/payments/checkout/phone-numbers.md). - `phone_number_collection.enabled` (boolean, required) Set to `true` to enable phone number collection. Can only be set in `payment` and `subscription` mode. - `redirect_on_completion` (enum, optional) This parameter applies to `ui_mode: embedded`. Learn more about the [redirect behavior](https://docs.stripe.com/docs/payments/checkout/custom-success-page.md?payment-ui=embedded-form) of embedded sessions. Defaults to `always`. Possible enum values: - `always` The Session will always redirect to the `return_url` after successful confirmation. - `if_required` The Session will only redirect to the `return_url` after a redirect-based payment method is used. - `never` The Session will never redirect to the `return_url`, and redirect-based payment methods will be disabled. - `return_url` (string, required conditionally) The URL to redirect your customer back to after they authenticate or cancel their payment on the payment method’s app or site. This parameter is required if `ui_mode` is `embedded` or `custom` and redirect-based payment methods are enabled on the session. - `saved_payment_method_options` (object, optional) Controls saved payment method settings for the session. Only available in `payment` and `subscription` mode. - `saved_payment_method_options.allow_redisplay_filters` (array of enums, optional) Uses the `allow_redisplay` value of each saved payment method to filter the set presented to a returning customer. By default, only saved payment methods with ’allow_redisplay: ‘always’ are shown in Checkout. Possible enum values: - `always` Use `always` to indicate that this payment method can always be shown to a customer in a checkout flow. - `limited` Use `limited` to indicate that this payment method can’t always be shown to a customer in a checkout flow. For example, it can only be shown in the context of a specific subscription. - `unspecified` This is the default value for payment methods where `allow_redisplay` wasn’t set. - `saved_payment_method_options.payment_method_remove` (enum, optional) Enable customers to choose if they wish to remove their saved payment methods. Disabled by default. Possible enum values: - `disabled` Removing payment methods will be disabled for this Checkout Session. This is the default option. - `enabled` Removing payment methods will be enabled for this Checkout Session. - `saved_payment_method_options.payment_method_save` (enum, optional) Enable customers to choose if they wish to save their payment method for future use. Disabled by default. Possible enum values: - `disabled` Saving payment methods will be disabled for this Checkout Session. This is the default option. - `enabled` Saving payment methods will be enabled for this Checkout Session. - `setup_intent_data` (object, optional) A subset of parameters to be passed to SetupIntent creation for Checkout Sessions in `setup` mode. - `setup_intent_data.description` (string, optional) An arbitrary string attached to the object. Often useful for displaying to users. - `setup_intent_data.metadata` (object, optional) Set of [key-value pairs](https://docs.stripe.com/docs/api/metadata.md) that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - `setup_intent_data.on_behalf_of` (string, optional) The Stripe account for which the setup is intended. - `shipping_address_collection` (object, optional) When set, provides configuration for Checkout to collect a shipping address from a customer. - `shipping_address_collection.allowed_countries` (array of enums, required) An array of two-letter ISO country codes representing which countries Checkout should provide as options for shipping locations. Possible enum values: - `AC` - `AD` - `AE` - `AF` - `AG` - `AI` - `AL` - `AM` - `AO` - `AQ` - `AR` - `AT` - `AU` - `AW` - `AX` - `AZ` - `BA` - `BB` - `BD` - `BE` - `BF` - `BG` - `BH` - `BI` - `BJ` - `BL` - `BM` - `BN` - `BO` - `BQ` - `BR` - `BS` - `BT` - `BV` - `BW` - `BY` - `BZ` - `CA` - `CD` - `CF` - `CG` - `CH` - `CI` - `CK` - `CL` - `CM` - `CN` - `CO` - `CR` - `CV` - `CW` - `CY` - `CZ` - `DE` - `DJ` - `DK` - `DM` - `DO` - `DZ` - `EC` - `EE` - `EG` - `EH` - `ER` - `ES` - `ET` - `FI` - `FJ` - `FK` - `FO` - `FR` - `GA` - `GB` - `GD` - `GE` - `GF` - `GG` - `GH` - `GI` - `GL` - `GM` - `GN` - `GP` - `GQ` - `GR` - `GS` - `GT` - `GU` - `GW` - `GY` - `HK` - `HN` - `HR` - `HT` - `HU` - `ID` - `IE` - `IL` - `IM` - `IN` - `IO` - `IQ` - `IS` - `IT` - `JE` - `JM` - `JO` - `JP` - `KE` - `KG` - `KH` - `KI` - `KM` - `KN` - `KR` - `KW` - `KY` - `KZ` - `LA` - `LB` - `LC` - `LI` - `LK` - `LR` - `LS` - `LT` - `LU` - `LV` - `LY` - `MA` - `MC` - `MD` - `ME` - `MF` - `MG` - `MK` - `ML` - `MM` - `MN` - `MO` - `MQ` - `MR` - `MS` - `MT` - `MU` - `MV` - `MW` - `MX` - `MY` - `MZ` - `NA` - `NC` - `NE` - `NG` - `NI` - `NL` - `NO` - `NP` - `NR` - `NU` - `NZ` - `OM` - `PA` - `PE` - `PF` - `PG` - `PH` - `PK` - `PL` - `PM` - `PN` - `PR` - `PS` - `PT` - `PY` - `QA` - `RE` - `RO` - `RS` - `RU` - `RW` - `SA` - `SB` - `SC` - `SD` - `SE` - `SG` - `SH` - `SI` - `SJ` - `SK` - `SL` - `SM` - `SN` - `SO` - `SR` - `SS` - `ST` - `SV` - `SX` - `SZ` - `TA` - `TC` - `TD` - `TF` - `TG` - `TH` - `TJ` - `TK` - `TL` - `TM` - `TN` - `TO` - `TR` - `TT` - `TV` - `TW` - `TZ` - `UA` - `UG` - `US` - `UY` - `UZ` - `VA` - `VC` - `VE` - `VG` - `VN` - `VU` - `WF` - `WS` - `XK` - `YE` - `YT` - `ZA` - `ZM` - `ZW` - `ZZ` - `shipping_options` (array of objects, optional) The shipping rate options to apply to this Session. Up to a maximum of 5. - `shipping_options.shipping_rate` (string, required unless shipping_rate_data is provided) The ID of the Shipping Rate to use for this shipping option. - `shipping_options.shipping_rate_data` (object, required unless shipping_rate is provided) Parameters to be passed to Shipping Rate creation for this shipping option. - `shipping_options.shipping_rate_data.display_name` (string, required) The name of the shipping rate, meant to be displayable to the customer. This will appear on CheckoutSessions. The maximum length is 100 characters. - `shipping_options.shipping_rate_data.delivery_estimate` (object, optional) The estimated range for how long shipping will take, meant to be displayable to the customer. This will appear on CheckoutSessions. - `shipping_options.shipping_rate_data.delivery_estimate.maximum` (object, optional) The upper bound of the estimated range. If empty, represents no upper bound i.e., infinite. - `shipping_options.shipping_rate_data.delivery_estimate.maximum.unit` (enum, required) A unit of time. Possible enum values: - `business_day` The delivery estimate is in business days. - `day` The delivery estimate is in days. - `hour` The delivery estimate is in hours. - `month` The delivery estimate is in months. - `week` The delivery estimate is in weeks. - `shipping_options.shipping_rate_data.delivery_estimate.maximum.value` (integer, required) Must be greater than 0. - `shipping_options.shipping_rate_data.delivery_estimate.minimum` (object, optional) The lower bound of the estimated range. If empty, represents no lower bound. - `shipping_options.shipping_rate_data.delivery_estimate.minimum.unit` (enum, required) A unit of time. Possible enum values: - `business_day` The delivery estimate is in business days. - `day` The delivery estimate is in days. - `hour` The delivery estimate is in hours. - `month` The delivery estimate is in months. - `week` The delivery estimate is in weeks. - `shipping_options.shipping_rate_data.delivery_estimate.minimum.value` (integer, required) Must be greater than 0. - `shipping_options.shipping_rate_data.fixed_amount` (object, optional) Describes a fixed amount to charge for shipping. Must be present if type is `fixed_amount`. - `shipping_options.shipping_rate_data.fixed_amount.amount` (integer, required) A non-negative integer in cents representing how much to charge. - `shipping_options.shipping_rate_data.fixed_amount.currency` (enum, required) 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). - `shipping_options.shipping_rate_data.fixed_amount.currency_options` (object, optional) Shipping rates defined in each available currency option. Each key must be a three-letter [ISO currency code](https://www.iso.org/iso-4217-currency-codes.html) and a [supported currency](https://stripe.com/docs/currencies). - `shipping_options.shipping_rate_data.fixed_amount.currency_options..amount` (integer, required) A non-negative integer in cents representing how much to charge. - `shipping_options.shipping_rate_data.fixed_amount.currency_options..tax_behavior` (enum, recommended if calculating taxes) Specifies whether the rate is considered inclusive of taxes or exclusive of taxes. One of `inclusive`, `exclusive`, or `unspecified`. Possible enum values: - `exclusive` - `inclusive` - `unspecified` - `shipping_options.shipping_rate_data.metadata` (object, optional) Set of [key-value pairs](https://docs.stripe.com/docs/api/metadata.md) that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - `shipping_options.shipping_rate_data.tax_behavior` (enum, recommended if calculating taxes) Specifies whether the rate is considered inclusive of taxes or exclusive of taxes. One of `inclusive`, `exclusive`, or `unspecified`. Possible enum values: - `exclusive` - `inclusive` - `unspecified` - `shipping_options.shipping_rate_data.tax_code` (string, recommended if calculating taxes) A [tax code](https://docs.stripe.com/docs/tax/tax-categories.md) ID. The Shipping tax code is `txcd_92010001`. - `shipping_options.shipping_rate_data.type` (enum, required) The type of calculation to use on the shipping rate. Possible enum values: - `fixed_amount` The shipping rate is a fixed amount. - `submit_type` (enum, optional) Describes the type of transaction being performed by Checkout in order to customize relevant text on the page, such as the submit button. `submit_type` can only be specified on Checkout Sessions in `payment` or `subscription` mode. If blank or `auto`, `pay` is used. You can’t set this parameter if `ui_mode` is `custom`. Possible enum values: - `auto` `pay` will used for `payment` mode sessions and `subscribe` will be used for `subscription` mode sessions - `book` Recommended when offering bookings. Submit button includes a ‘Book’ label - `donate` Recommended when accepting donations. Submit button includes a ‘Donate’ label - `pay` Submit button includes a ‘Buy’ label - `subscribe` Submit button includes a ‘Subscribe’ label - `subscription_data` (object, optional) A subset of parameters to be passed to subscription creation for Checkout Sessions in `subscription` mode. - `subscription_data.application_fee_percent` (float, optional) A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice total that will be transferred to the application owner’s Stripe account. To use an application fee percent, the request must be made on behalf of another account, using the `Stripe-Account` header or an OAuth key. For more information, see the application fees [documentation](https://stripe.com/docs/connect/subscriptions#collecting-fees-on-subscriptions). - `subscription_data.billing_cycle_anchor` (timestamp, optional) A future timestamp to anchor the subscription’s billing cycle for new subscriptions. You can’t set this parameter if `ui_mode` is `custom`. - `subscription_data.billing_mode` (object, optional) Controls how prorations and invoices for subscriptions are calculated and orchestrated. - `subscription_data.billing_mode.type` (enum, required) Controls the calculation and orchestration of prorations and invoices for subscriptions. If no value is passed, the default is `flexible`. Possible enum values: - `classic` Calculations for subscriptions and invoices are based on legacy defaults. - `flexible` Supports more flexible calculation and orchestration options for subscriptions and invoices. - `subscription_data.billing_mode.flexible` (object, optional) Configure behavior for flexible billing mode. - `subscription_data.billing_mode.flexible.proration_discounts` (enum, optional) Controls how invoices and invoice items display proration amounts and discount amounts. Possible enum values: - `included` Amounts are net of discounts, and discount amounts are zero. - `itemized` Amounts are gross of discounts, and discount amounts are accurate. - `subscription_data.default_tax_rates` (array of strings, optional) The tax rates that will apply to any subscription item that does not have `tax_rates` set. Invoices created will have their `default_tax_rates` populated from the subscription. - `subscription_data.description` (string, optional) The subscription’s description, meant to be displayable to the customer. Use this field to optionally store an explanation of the subscription for rendering in the [customer portal](https://docs.stripe.com/docs/customer-management.md). The maximum length is 500 characters. - `subscription_data.invoice_settings` (object, optional) All invoices will be billed using the specified settings. - `subscription_data.invoice_settings.issuer` (object, optional) The connected account that issues the invoice. The invoice is presented with the branding and support information of the specified account. - `subscription_data.invoice_settings.issuer.type` (enum, required) Type of the account referenced in the request. Possible enum values: - `account` Indicates that the account being referenced is a connected account which is different from the account making the API request but related to it. - `self` Indicates that the account being referenced is the account making the API request. - `subscription_data.invoice_settings.issuer.account` (string, required only if type is account) The connected account being referenced when `type` is `account`. - `subscription_data.metadata` (object, optional) Set of [key-value pairs](https://docs.stripe.com/docs/api/metadata.md) that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - `subscription_data.on_behalf_of` (string, optional) The account on behalf of which to charge, for each of the subscription’s invoices. - `subscription_data.proration_behavior` (enum, optional) Determines how to handle prorations resulting from the `billing_cycle_anchor`. If no value is passed, the default is `create_prorations`. Possible enum values: - `create_prorations` Will cause proration invoice items to be created when applicable. - `none` Disable creating prorations in current Checkout Session - `subscription_data.transfer_data` (object, optional) If specified, the funds from the subscription’s invoices will be transferred to the destination and the ID of the resulting transfers will be found on the resulting charges. - `subscription_data.transfer_data.destination` (string, required) ID of an existing, connected Stripe account. - `subscription_data.transfer_data.amount_percent` (float, optional) A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice total that will be transferred to the destination account. By default, the entire amount is transferred to the destination. - `subscription_data.trial_end` (integer, optional) Unix timestamp representing the end of the trial period the customer will get before being charged for the first time. Has to be at least 48 hours in the future. - `subscription_data.trial_period_days` (integer, optional) Integer representing the number of trial period days before the customer is charged for the first time. Has to be at least 1. - `subscription_data.trial_settings` (object, optional) Settings related to subscription trials. - `subscription_data.trial_settings.end_behavior` (object, required) Defines how the subscription should behave when the user’s free trial ends. - `subscription_data.trial_settings.end_behavior.missing_payment_method` (enum, required) Indicates how the subscription should change when the trial ends if the user did not provide a payment method. Possible enum values: - `cancel` Cancel the subscription if a payment method is not attached when the trial ends. - `create_invoice` Create an invoice when the trial ends, even if the user did not set up a payment method. - `pause` Pause the subscription if a payment method is not attached when the trial ends. - `success_url` (string, required conditionally) The URL to which Stripe should send customers when payment or setup is complete. This parameter is not allowed if ui_mode is `embedded` or `custom`. If you’d like to use information from the successful Checkout Session on your page, read the guide on [customizing your success page](https://docs.stripe.com/docs/payments/checkout/custom-success-page.md). - `tax_id_collection` (object, optional) Controls tax ID collection during checkout. - `tax_id_collection.enabled` (boolean, required) Enable tax ID collection during checkout. Defaults to `false`. - `tax_id_collection.required` (enum, optional) Describes whether a tax ID is required during checkout. Defaults to `never`. You can’t set this parameter if `ui_mode` is `custom`. Possible enum values: - `if_supported` A tax ID will be required if collection is [supported](https://docs.stripe.com/tax/checkout/tax-ids.md#supported-types) for the selected billing address country. - `never` Tax ID collection is never required. - `ui_mode` (enum, optional) The UI mode of the Session. Defaults to `hosted`. Possible enum values: - `custom` The Checkout Session will be displayed using [embedded components](https://docs.stripe.com/checkout/custom/quickstart.md) on your website - `embedded` The Checkout Session will be displayed as an embedded form on your website. - `hosted` The Checkout Session will be displayed on a hosted page that customers will be redirected to. - `wallet_options` (object, optional) Wallet-specific configuration. - `wallet_options.link` (object, optional) contains details about the Link wallet options. - `wallet_options.link.display` (enum, optional) Specifies whether Checkout should display Link as a payment option. By default, Checkout will display all the supported wallets that the Checkout Session was created with. This is the `auto` behavior, and it is the default choice. Possible enum values: - `auto` The Checkout Session will automatically determine if Link is a supported payment option and display accordingly. - `never` The Checkout Session will not display Link as a payment option. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>" \ --data-urlencode success_url="https://example.com/success" \ -d "line_items[0][price]"=price_1MotwRLkdIwHu7ixYcPLm5uZ \ -d "line_items[0][quantity]"=2 \ -d mode=payment ``` ```cli stripe checkout sessions create \ --success-url="https://example.com/success" \ -d "line_items[0][price]"=price_1MotwRLkdIwHu7ixYcPLm5uZ \ -d "line_items[0][quantity]"=2 \ --mode=payment ``` ```ruby client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ success_url: 'https://example.com/success', line_items: [ { price: 'price_1MotwRLkdIwHu7ixYcPLm5uZ', quantity: 2, }, ], mode: 'payment', }) ``` ```python client = StripeClient("<>") session = client.v1.checkout.sessions.create({ "success_url": "https://example.com/success", "line_items": [{"price": "price_1MotwRLkdIwHu7ixYcPLm5uZ", "quantity": 2}], "mode": "payment", }) ``` ```php $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'success_url' => 'https://example.com/success', 'line_items' => [ [ 'price' => 'price_1MotwRLkdIwHu7ixYcPLm5uZ', 'quantity' => 2, ], ], 'mode' => 'payment', ]); ``` ```java StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setSuccessUrl("https://example.com/success") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("price_1MotwRLkdIwHu7ixYcPLm5uZ") .setQuantity(2L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .build(); Session session = client.v1().checkout().sessions().create(params); ``` ```node const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ success_url: 'https://example.com/success', line_items: [ { price: 'price_1MotwRLkdIwHu7ixYcPLm5uZ', quantity: 2, }, ], mode: 'payment', }); ``` ```go sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ SuccessURL: stripe.String("https://example.com/success"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("price_1MotwRLkdIwHu7ixYcPLm5uZ"), Quantity: stripe.Int64(2), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet var options = new Stripe.Checkout.SessionCreateOptions { SuccessUrl = "https://example.com/success", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "price_1MotwRLkdIwHu7ixYcPLm5uZ", Quantity = 2, }, }, Mode = "payment", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ### Response ```json { "id": "cs_test_a11YYufWQzNY63zpQ6QSNRQhkUpVph4WRmzW0zWJO2znZKdVujZ0N0S22u", "object": "checkout.session", "after_expiration": null, "allow_promotion_codes": null, "amount_subtotal": 2198, "amount_total": 2198, "automatic_tax": { "enabled": false, "liability": null, "status": null }, "billing_address_collection": null, "cancel_url": null, "client_reference_id": null, "consent": null, "consent_collection": null, "created": 1679600215, "currency": "usd", "custom_fields": [], "custom_text": { "shipping_address": null, "submit": null }, "customer": null, "customer_creation": "if_required", "customer_details": null, "customer_email": null, "expires_at": 1679686615, "invoice": null, "invoice_creation": { "enabled": false, "invoice_data": { "account_tax_ids": null, "custom_fields": null, "description": null, "footer": null, "issuer": null, "metadata": {}, "rendering_options": null } }, "livemode": false, "locale": null, "metadata": {}, "mode": "payment", "payment_intent": null, "payment_link": null, "payment_method_collection": "always", "payment_method_options": {}, "payment_method_types": [ "card" ], "payment_status": "unpaid", "phone_number_collection": { "enabled": false }, "recovered_from": null, "setup_intent": null, "shipping_address_collection": null, "shipping_cost": null, "shipping_details": null, "shipping_options": [], "status": "open", "submit_type": null, "subscription": null, "success_url": "https://example.com/success", "total_details": { "amount_discount": 0, "amount_shipping": 0, "amount_tax": 0 }, "url": "https://checkout.stripe.com/c/pay/cs_test_a11YYufWQzNY63zpQ6QSNRQhkUpVph4WRmzW0zWJO2znZKdVujZ0N0S22u#fidkdWxOYHwnPyd1blpxYHZxWjA0SDdPUW5JbmFMck1wMmx9N2BLZjFEfGRUNWhqTmJ%2FM2F8bUA2SDRySkFdUV81T1BSV0YxcWJcTUJcYW5rSzN3dzBLPUE0TzRKTTxzNFBjPWZEX1NKSkxpNTVjRjN8VHE0YicpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBabHFgaCcpJ2BrZGdpYFVpZGZgbWppYWB3dic%2FcXdwYHgl" } ``` --- # Source: https://docs.stripe.com/invoicing/dashboard/credit-notes.md # Issue credit notes Use the Dashboard to adjust or refund finalized invoices with credit notes. Credit notes are documents that decrease the amount of an `open` or `paid` *invoice* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice). The difference between issuing a credit note and adjusting the amount of an invoice by [revising it](https://docs.stripe.com/invoicing/invoice-edits.md) is that a credit note doesn’t void and replace the original invoice. Some example scenarios where you might use credit notes include: - **You accidentally overbilled a customer**—You accidentally charged your customer 110 USD instead of 100 USD because of a data entry mistake. Use a credit note to give your customer a 10 USD credit for the overcharge. - **You’re short on inventory**—You billed your customer for five items, but when it’s time to ship them you realize you only have three items left in stock. Use a credit note to refund your customer for the two items they didn’t receive. - **Discounts**—You and your customer negotiate a discount on an invoice. Instead of voiding the invoice and issuing a new one, you can use a credit note to adjust the amount owed on the existing invoice. A credit note reduces the amount due without recording any payment. However, if a credit note reduces the balance of an `open` invoice to 0, the invoice status changes to `paid`. For information on invoice statuses, see the [Invoicing overview](https://docs.stripe.com/invoicing/overview.md#invoice-statuses). > For information about working with credit notes using the API, see [Generate credit notes programmatically](https://docs.stripe.com/invoicing/integration/programmatic-credit-notes.md). ## Get started When you issue a credit note for an `open` invoice, it decreases the amount due on the invoice. When you issue a credit note for a `paid` invoice, you credit the customer’s account balance or give them a refund outside of Stripe. The sum of all credit notes issued for an invoice can’t exceed the ​​total amount of the invoice. For a `paid` invoice, the sum of the refund, credit, and out-of-band payment amounts must equal the credit note total. When you create a credit note, you can apply credit amounts in three ways: - Discount a fixed amount from an invoice line item. - Discount a quantity from an invoice line item. The total discount is the discount quantity times the unit price of that line item. - Apply a discount to the total invoice amount by adding a custom discount line item with a description, quantity, and unit price. The total discount is the quantity times the unit price. We recommend discounting invoice line items when possible, since it associates each credit with a line item. Adding a custom discount line item can make reporting and tracking difficult, because the credit isn’t associated with a real invoice line item. > You can’t combine discount types on an invoice line item. For example, if you discount a line item quantity, then a future credit note can only discount that line item by quantity, not by amount. If you discount a line item amount, then a future credit note can only discount that line item by amount, not by quantity. ## Create a credit note You can create credit notes for open or paid invoices. 1. Open the [Invoices page](https://dashboard.stripe.com/test/invoices) in the Dashboard. 1. Select the open or paid invoice you want to add a credit note to. 1. Click **More** and select **Issue a credit note**. 1. Select a reason for the credit note. 1. (*Optional*) Perform the following actions: - Edit line item credit quantities or amounts. - Click **Add item** to add a custom line item. - Click **Set item tax** to select a tax rate to use for credit purposes. 1. If the invoice is `paid`, choose whether to refund the customer’s card, credit their balance, or refund the amount outside of Stripe (for example, cash). 1. Click **Issue credit note** to submit the credit note. > Open invoices can’t have a credit note with a pending [payment_intent](https://docs.stripe.com/api/invoices/object.md#invoice_object-payment_intent). ![](https://b.stripecdn.com/docs-statics-srv/assets/credit-note-dashboard.d9f67171b43e5ad618bc6d153b86286a.png) Issue a credit note in the Dashboard ## Credit balances and discounts When you issue a credit note on an invoice with an applied [customer credit balance](https://docs.stripe.com/invoicing/customer/balance.md), funds are sometimes credited to the credit balance instead of the initial payment method. For example, if a credit balance of 150 USD is applied to an invoice for 200 USD, then the finalized invoice is for 50 USD. If you issue a credit note for 50 USD or less, the funds are refunded to the customer’s payment method. Anything above 50 USD is added to the customer’s credit balance and is applied to the next invoice. [Discounts](https://docs.stripe.com/billing/taxes/tax-rates.md#discounts) apply proportionally to all of the line items on an invoice. For example, applying a 50% discount to an invoice with 10 line items at 10 USD each changes the amount of each line item to 5 USD. If you then apply a credit note for one line item, it reduces the invoice amount by 5 USD. Fixed-amount discounts work the same way. If you apply a 10 USD discount to an invoice with 10 line items at 10 USD, each line item is 10% of the sum amount and is discounted by 10% * 10 USD = 1 USD. The amount of each line item becomes 9 USD. If you then apply a credit note for one line item, it reduces the invoice amount by 9 USD. If you want to credit the original line item amount, you can make up the difference by adding a custom discount line item to the credit note. For example, if a discount reduced a line item’s credit amount from 10 USD to 9 USD, you can add a custom discount line item for 1 USD. ## Voiding credit notes You can void a credit note only if it’s on an open invoice. Voiding a credit note reverses its adjustment, increasing the amount due on the invoice by the amount of the credit note. To void a credit note in the Dashboard, click the overflow menu (⋯) at the top right of the credit note, then select **Void credit note**. ## Crediting negative line items You can also credit negative invoice line items. The following restrictions apply: - The total amount of the credit note must remain positive. - The total amount credited to a negative line item must be negative. - The total amount credited to a negative line item can’t be less than the line item amount. You also can’t credit a negative amount on a custom credit note line item. We only support negative amounts on credit note line items that are tied to invoice line items. ## See also - [Stripe data](https://docs.stripe.com/stripe-data.md) --- # Source: https://docs.stripe.com/financial-accounts/connect/moving-money/into/credit-reversals.md # Moving money using CreditReversal objects Learn how you can return funds from received credits that add money to your financial account. Reversing a [ReceivedCredit](https://docs.stripe.com/api/treasury/received_credits.md) creates a [CreditReversal](https://docs.stripe.com/api/treasury/credit_reversals.md). You can reverse `ReceivedCredits` only in some scenarios (detailed in the following table). Whether you can reverse a `ReceivedCredit` depends on the network and source flow. The `reversal_details` sub-hash on the `ReceivedCredit` object can have the following combination of values, which determines if you can reverse the `ReceivedCredit`. | RESTRICTED REASON | DEADLINE (EPOCH TIMESTAMP) | EXAMPLE SCENARIO | | ------------------------ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `source_flow_restricted` | `null` | A Stripe network `ReceivedCredit` that’s the result of a flow other than an `OutboundPayment`. Stripe restricts users from reversing such `ReceivedCredits`. | | `network_restricted` | `null` | Network constraints prevent Stripe from allowing reversal on some `ReceivedCredits`, such as a `ReceivedCredit` from a wire transfer. | | `null` | `{{TIMESTAMP}}` | A `ReceivedCredit`, which is reversible, but only until the timestamp in `deadline`. ACH `ReceivedCredits` have a deadline that determines how long you have to reverse them. | | `deadline_passed` | `{{TIMESTAMP}}` | A `ReceivedCredit` that’s reversible before the timestamp in `deadline`, but is no longer reversible because the `deadline` has passed. ACH `ReceivedCredits` have a limited time of when they’re reversible after they’re created. | | `already_reversed` | `null` | A `ReceivedCredit` that’s already reversed has this `restricted_reason`. It might have a non-null `deadline` value. | | `null` | `null` | You can reverse `ReceivedCredits` anytime if they have `null` for both `restricted_reason` and `deadline`. | ## Create a CreditReversal Use `POST /v1/treasury/credit_reversals` to create a `CreditReversal`. Set the `received_credit` parameter in the body of the request to the value of the `ReceivedCredit` ID to reverse. > You can’t update `CreditReversals`, so you must set any optional [metadata](https://docs.stripe.com/api/treasury/credit_reversals/create.md#create_credit_reversal-metadata) on creation. The following request creates a `CreditReversal` based on the `ReceivedCredit` ID value on the required `received_credit` parameter. The request also sets an optional metadata value. ```curl curl https://api.stripe.com/v1/treasury/credit_reversals \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d received_credit={{RECEIVED_CREDIT_ID}} \ -d "metadata[reason]"=Because ``` ```cli stripe treasury credit_reversals create \ --stripe-account {{CONNECTEDACCOUNT_ID}} \ --received-credit={{RECEIVED_CREDIT_ID}} \ -d "metadata[reason]"=Because ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") credit_reversal = client.v1.treasury.credit_reversals.create( { received_credit: '{{RECEIVED_CREDIT_ID}}', metadata: {reason: 'Because'}, }, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. credit_reversal = client.v1.treasury.credit_reversals.create( {"received_credit": "{{RECEIVED_CREDIT_ID}}", "metadata": {"reason": "Because"}}, {"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $creditReversal = $stripe->treasury->creditReversals->create( [ 'received_credit' => '{{RECEIVED_CREDIT_ID}}', 'metadata' => ['reason' => 'Because'], ], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CreditReversalCreateParams params = CreditReversalCreateParams.builder() .setReceivedCredit("{{RECEIVED_CREDIT_ID}}") .putMetadata("reason", "Because") .build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. CreditReversal creditReversal = client.v1().treasury().creditReversals().create(params, requestOptions); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const creditReversal = await stripe.treasury.creditReversals.create( { received_credit: '{{RECEIVED_CREDIT_ID}}', metadata: { reason: 'Because', }, }, { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TreasuryCreditReversalCreateParams{ ReceivedCredit: stripe.String("{{RECEIVED_CREDIT_ID}}"), } params.AddMetadata("reason", "Because") params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result, err := sc.V1TreasuryCreditReversals.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Treasury.CreditReversalCreateOptions { ReceivedCredit = "{{RECEIVED_CREDIT_ID}}", Metadata = new Dictionary { { "reason", "Because" } }, }; var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Treasury.CreditReversals; Stripe.Treasury.CreditReversal creditReversal = service.Create(options, requestOptions); ``` If successful, the response returns the new `CreditReversal` object. ```json { "id": "{{CREDIT_REVERSAL_ID}}", "object": "credit_reversal", "amount": 1000, "currency": "usd", "financial_account": "{{FINANCIAL_ACCOUNT_ID}}", "hosted_regulatory_receipt_url": "https://payments.stripe.com/regulatory-receipt/{{URL_ID}}", "livemode": false, "metadata": { "csr_id": "CSR-12" }, "network": "ach", "received_credit": "{{RECEIVED_CREDIT_ID}}", "status": "processing", "status_transitions": { "posted_at": null }, "transaction": "{{TRANSACTION_ID}}" } ``` ## Retrieve a CreditReversal Use `GET /v1/treasury/credit_reversals/{{CREDIT_REVERSAL_ID}}` to retrieve the `CreditReversal` with the associated ID. ```curl curl https://api.stripe.com/v1/treasury/credit_reversals/{{CREDIT_REVERSAL_ID}} \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" ``` ```cli stripe treasury credit_reversals retrieve {{CREDIT_REVERSAL_ID}} \ --stripe-account {{CONNECTEDACCOUNT_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") credit_reversal = client.v1.treasury.credit_reversals.retrieve( '{{CREDIT_REVERSAL_ID}}', {}, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. credit_reversal = client.v1.treasury.credit_reversals.retrieve( "{{CREDIT_REVERSAL_ID}}", options={"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $creditReversal = $stripe->treasury->creditReversals->retrieve( '{{CREDIT_REVERSAL_ID}}', [], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CreditReversalRetrieveParams params = CreditReversalRetrieveParams.builder().build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. CreditReversal creditReversal = client.v1().treasury().creditReversals().retrieve( "{{CREDIT_REVERSAL_ID}}", params, requestOptions ); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const creditReversal = await stripe.treasury.creditReversals.retrieve( '{{CREDIT_REVERSAL_ID}}', { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TreasuryCreditReversalRetrieveParams{} params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result, err := sc.V1TreasuryCreditReversals.Retrieve( context.TODO(), "{{CREDIT_REVERSAL_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Treasury.CreditReversals; Stripe.Treasury.CreditReversal creditReversal = service.Get( "{{CREDIT_REVERSAL_ID}}", null, requestOptions); ``` The response returns the specific `CreditReversal` object. #### JSON (commented) ```json { "id": "{{CREDIT_REVERSAL_ID}}", "object": "credit_reversal", "livemode": "{{Boolean}}", "created": "{{Timestamp}}", "financial_account": "{{FINANCIAL_ACCOUNT_ID}}", "amount": 1000, "currency": "usd", // The ReceivedCredit that was reversed "received_credit": "{{RECEIVED_CREDIT_ID}}", // The rails used to reversed. Always the same as that of the ReceivedCredit "network": "ach", "status": "processing" | "posted", "status_transitions": { "posted_at": null | "{{Timestamp}}", }, // Transaction representing balance impact of the CreditReversal "transaction": "{{TRANSACTION_ID}}", // A unique, Stripe-hosted direct link to the regulatory receipt for the CreditReversal "hosted_regulatory_receipt_url": "{{Url}}", // A map of String-String intended for users to use custom data "metadata": {}, } ``` #### JSON ```json { "id": "{{CREDIT_REVERSAL_ID}}", "object": "credit_reversal", "livemode": "{{Boolean}}", "created": "{{Timestamp}}", "financial_account": "{{FINANCIAL_ACCOUNT_ID}}", "amount": 1000, "currency": "usd", "received_credit": "{{RECEIVED_CREDIT_ID}}", "network": "ach", "status": "posted", "status_transitions": { "posted_at": "{{Timestamp}}", }, "transaction": "{{TRANSACTION_ID}}", "hosted_regulatory_receipt_url": "{{Url}}", "metadata": {}, } ``` ## List CreditReversals Use `GET /v1/treasury/credit_reversals` to retrieve a list of `CreditReversals` for the financial account with the ID provided in the required `financial_account` parameter. You can filter the list by standard list parameters, `status`, or by `ReceivedCredit` ID using the `received_credit` parameter. ``` { // Standard list parameters "limit", "starting_after", "ending_before", // Filter by status "status": "processing" | "posted", // Filter by FinancialAccount (Required) "financial_account": "{{FINANCIAL_ACCOUNT_ID}}", // Filter by ReceivedCredit "received_credit": "{{RECEIVED_CREDIT_ID}}" } ``` The following request returns the three most recent credit reversals with a status of `posted` for the specified financial account. ```curl curl -G https://api.stripe.com/v1/treasury/credit_reversals \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d limit=3 \ -d status=posted \ -d financial_account="{{TREASURYFINANCIALACCOUNT_ID}}" ``` ```cli stripe treasury credit_reversals list \ --stripe-account {{CONNECTEDACCOUNT_ID}} \ --limit=3 \ --status=posted \ --financial-account="{{TREASURYFINANCIALACCOUNT_ID}}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") credit_reversals = client.v1.treasury.credit_reversals.list( { limit: 3, status: 'posted', financial_account: '{{TREASURYFINANCIALACCOUNT_ID}}', }, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. credit_reversals = client.v1.treasury.credit_reversals.list( { "limit": 3, "status": "posted", "financial_account": "{{TREASURYFINANCIALACCOUNT_ID}}", }, {"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $creditReversals = $stripe->treasury->creditReversals->all( [ 'limit' => 3, 'status' => 'posted', 'financial_account' => '{{TREASURYFINANCIALACCOUNT_ID}}', ], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CreditReversalListParams params = CreditReversalListParams.builder() .setLimit(3L) .setStatus(CreditReversalListParams.Status.POSTED) .setFinancialAccount("{{TREASURYFINANCIALACCOUNT_ID}}") .build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. StripeCollection stripeCollection = client.v1().treasury().creditReversals().list(params, requestOptions); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const creditReversals = await stripe.treasury.creditReversals.list( { limit: 3, status: 'posted', financial_account: '{{TREASURYFINANCIALACCOUNT_ID}}', }, { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TreasuryCreditReversalListParams{ Status: stripe.String(stripe.TreasuryCreditReversalStatusPosted), FinancialAccount: stripe.String("{{TREASURYFINANCIALACCOUNT_ID}}"), } params.Limit = stripe.Int64(3) params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result := sc.V1TreasuryCreditReversals.List(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Treasury.CreditReversalListOptions { Limit = 3, Status = "posted", FinancialAccount = "{{TREASURYFINANCIALACCOUNT_ID}}", }; var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Treasury.CreditReversals; StripeList creditReversals = service.List( options, requestOptions); ``` If successful, the response returns the relevant list of [CreditReversal objects](https://docs.stripe.com/api/treasury/credit_reversals.md). ## Test CreditReversals To test CreditReversals, you must first create [test ReceivedCredits](https://docs.stripe.com/financial-accounts/connect/moving-money/into/credit-reversals.md#testingrc). Then use `POST /v1/treasury/credit_reversals` and specify the test `ReceivedCredit` ID in the `received_credit` parameter to create a test `CreditReversal`. ## CreditReversal webhooks Stripe emits the following `CreditReversal` events to your [webhook](https://docs.stripe.com/webhooks.md) endpoint: - `treasury.credit_reversal.created` on `CreditReversal` creation. - `treasury.credit_reversal.posted` when the `CreditReversal` posts. --- # Source: https://docs.stripe.com/payments/checkout/cross-sells.md # Cross-sells Enable customers to purchase complementary products at checkout by using cross-sells. # Stripe-hosted page > This is a Stripe-hosted page for when payment-ui is stripe-hosted. View the full page at https://docs.stripe.com/payments/checkout/cross-sells?payment-ui=stripe-hosted. ![Cross-sell product in Checkout](https://b.stripecdn.com/docs-statics-srv/assets/cross-sell-session.8fe2f9cfc326da5998ae2e2ebebf7dc9.png) A cross-sell is a product that you can add to an order using Checkout. Cross-sells enable customers to optionally purchase other related products using Checkout. Cross-sells can increase your average order value and revenue. For Checkout to offer a product as a cross-sell, the product must meet the following criteria: - The product must be associated with only a single [Price](https://docs.stripe.com/api/prices/object.md#price_object-product). - The [currency](https://docs.stripe.com/api/prices/object.md#price_object-currency) of the cross-sell product’s price must match the currency of the other prices in the Checkout Session. - If the cross-sell product’s price [type](https://docs.stripe.com/api/prices/object.md#price_object-type) is `recurring`, the Checkout Session must be in subscription mode and its recurring interval must match the recurring interval of the other prices in the Checkout Session. - If you’re using [subscription upsells](https://docs.stripe.com/payments/checkout/upsells.md), cross-sells only support products with non-recurring prices. For example, you can cross-sell a one-time setup fee while also upselling a monthly subscription to annual billing. - If you’re using [automatic taxes](https://docs.stripe.com/tax.md), cross-sells only support products with prices with specified [tax behavior](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-behavior). You can either [set tax behavior for a price](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#set-tax-behavior-on-price) or set the default tax behavior for all prices under [Tax Settings](https://dashboard.stripe.com/test/settings/tax) in the Stripe Dashboard. ## Create a cross-sell ![Configure a cross-sell on the Product details page](https://b.stripecdn.com/docs-statics-srv/assets/add-cross-sell.685564769c217a27f88b9ab9605d9c65.gif) Configure a cross-sell on the Product details page. You can configure a cross-sell in the [Dashboard](https://dashboard.stripe.com/products?active=true) on the Product details page. Visit the Product details page for the product from which you want to cross-sell another complementary product. You’ll see a **Cross-sells** section with a dropdown menu containing your other Products. Select a Product with a single Price. After you configure it, all eligible Checkout Sessions cross-sell the product selected from the dropdown menu. For example, a customer purchasing a subscription to the ‘Professional’ tier would be cross-sold the ‘Professional Services: Deployment’ product. ## Checkout flow In Checkout, buyers see an option to add the cross-sell to their purchase. If buyers add the cross-sell to the Checkout Session, they can also remove it. If they remove it, the option to add the cross-sell appears again. > The quantity of cross-sell line items can’t be adjusted. The current maximum is 1. ![](https://docs.stripecdn.com/73a4baa89ea5ac0e30a39cd03f33b21e35979759cdc9293b680695226a5b7dbe.mp4) ## Retrieve Checkout Session line items After a customer adds a cross-sell, the `line_items` for the Checkout Session update to reflect the addition. When [fulfilling your order](https://docs.stripe.com/checkout/fulfillment.md#create-payment-event-handler) using the `checkout.session.completed` webhook, make sure to [retrieve the line items](https://docs.stripe.com/api/checkout/sessions/line_items.md). ## Remove a cross-sell You can remove a cross-sell on the Product details page. After you remove it, the product won’t be offered to any new Checkout Sessions. ![Remove a cross-sell from the Product details page](https://b.stripecdn.com/docs-statics-srv/assets/remove-cross-sell.a08765b1278a8187c282964f89641b92.gif) Remove a cross-sell. # Embedded form > This is a Embedded form for when payment-ui is embedded-form. View the full page at https://docs.stripe.com/payments/checkout/cross-sells?payment-ui=embedded-form. ![Cross-sell product in Checkout](https://b.stripecdn.com/docs-statics-srv/assets/cross-sell-session.8fe2f9cfc326da5998ae2e2ebebf7dc9.png) A cross-sell is a product that you can add to an order using Checkout. Cross-sells enable customers to optionally purchase other related products using Checkout. Cross-sells can increase your average order value and revenue. For Checkout to offer a product as a cross-sell, the product must meet the following criteria: - The product must be associated with only a single [Price](https://docs.stripe.com/api/prices/object.md#price_object-product). - The [currency](https://docs.stripe.com/api/prices/object.md#price_object-currency) of the cross-sell product’s price must match the currency of the other prices in the Checkout Session. - If the cross-sell product’s price [type](https://docs.stripe.com/api/prices/object.md#price_object-type) is `recurring`, the Checkout Session must be in subscription mode and its recurring interval must match the recurring interval of the other prices in the Checkout Session. - If you’re using [subscription upsells](https://docs.stripe.com/payments/checkout/upsells.md), cross-sells only support products with non-recurring prices. For example, you can cross-sell a one-time setup fee while also upselling a monthly subscription to annual billing. - If you’re using [automatic taxes](https://docs.stripe.com/tax.md), cross-sells only support products with prices with specified [tax behavior](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#tax-behavior). You can either [set tax behavior for a price](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md#set-tax-behavior-on-price) or set the default tax behavior for all prices under [Tax Settings](https://dashboard.stripe.com/test/settings/tax) in the Stripe Dashboard. ## Create a cross-sell ![Configure a cross-sell on the Product details page](https://b.stripecdn.com/docs-statics-srv/assets/add-cross-sell.685564769c217a27f88b9ab9605d9c65.gif) Configure a cross-sell on the Product details page. You can configure a cross-sell in the [Dashboard](https://dashboard.stripe.com/products?active=true) on the Product details page. Visit the Product details page for the product from which you want to cross-sell another complementary product. You’ll see a **Cross-sells** section with a dropdown menu containing your other Products. Select a Product with a single Price. After you configure it, all eligible Checkout Sessions cross-sell the product selected from the dropdown menu. For example, a customer purchasing a subscription to the ‘Professional’ tier would be cross-sold the ‘Professional Services: Deployment’ product. ## Checkout flow In Checkout, buyers see an option to add the cross-sell to their purchase. If buyers add the cross-sell to the Checkout Session, they can also remove it. If they remove it, the option to add the cross-sell appears again. > The quantity of cross-sell line items can’t be adjusted. The current maximum is 1. ![](https://docs.stripecdn.com/73a4baa89ea5ac0e30a39cd03f33b21e35979759cdc9293b680695226a5b7dbe.mp4) ## Retrieve Checkout Session line items After a customer adds a cross-sell, the `line_items` for the Checkout Session update to reflect the addition. When [fulfilling your order](https://docs.stripe.com/checkout/fulfillment.md#create-payment-event-handler) using the `checkout.session.completed` webhook, make sure to [retrieve the line items](https://docs.stripe.com/api/checkout/sessions/line_items.md). ## Remove a cross-sell You can remove a cross-sell on the Product details page. After you remove it, the product won’t be offered to any new Checkout Sessions. ![Remove a cross-sell from the Product details page](https://b.stripecdn.com/docs-statics-srv/assets/remove-cross-sell.a08765b1278a8187c282964f89641b92.gif) Remove a cross-sell. # Embedded components > This is a Embedded components for when payment-ui is embedded-components. View the full page at https://docs.stripe.com/payments/checkout/cross-sells?payment-ui=embedded-components. Cross-sells aren’t available for Elements with Checkout Sessions API. --- # Source: https://docs.stripe.com/currencies.md # Supported currencies Learn which currencies Stripe supports for payments and bank payouts. Use this guide to understand which currencies Stripe supports for payments and bank payouts, how conversions work, how to format amounts in API requests (including minor units and decimals), each currency’s minimum and maximum charge limits, and specific currency rules. You can charge customers in over 135 currencies and receive funds in your preferred currency. Converting prices to local currencies can improve customer conversion and authorization rates, while lowering payment processing costs. Learn how to [display and charge customers in multiple currencies](https://docs.stripe.com/payments/currencies/localize-prices.md). ## Currency presentment and settlement Currency affects three aspects of Stripe payments: - The customer’s payment method currency, such as their credit card or bank account - The currency of the charge, called the *presentment* currency - The currency accepted by your destination bank account or debit card, called the *settlement* currency. To learn more, see [Settle in additional currencies](https://docs.stripe.com/payments/currencies/settlement-payouts.md). If the charge currency differs from the customer’s payment method currency, their bank or card issuer might charge the *customer* a foreign exchange fee. The bank or card issuer might also charge the customer if the payment method and your business are in different countries, regardless of the currency used. If the charge currency differs from your *settlement currency* (The settlement currency is the currency your bank account uses), Stripe converts the charge to your settlement currency, with [multiple options](https://docs.stripe.com/payments/currencies/localize-prices.md) for presenting, converting, and charging customers in different currencies. In certain countries, Stripe might support [settlement in additional currencies](https://docs.stripe.com/payments/currencies/settlement-payouts.md). If you need liquidity in additional currencies, you can enable settlement in those currencies and add a bank account in the [payout settings of your Dashboard](https://dashboard.stripe.com/account/payouts). Our [payouts documentation](https://docs.stripe.com/payouts.md#multiple-bank-accounts) lists the different bank account currencies we support. See [Stripe pricing](https://www.stripe.com/pricing) for conversion costs. ### Connect platforms If you use *Connect* (Connect is Stripe's solution for multi-party businesses, such as marketplace or software platforms, to route payments between sellers, customers, and other recipients), your platform has additional currency conversion considerations. See [Work with multiple currencies](https://docs.stripe.com/connect/currencies.md) to manage currency conversions. ## Supported presentment currencies Currencies are two-decimal currencies unless otherwise specified. Currencies shown as links are [zero-decimal](https://docs.stripe.com/currencies.md#zero-decimal) currencies. Make sure to use all lowercase letters when entering the three-letter ISO code in any payment request. \* American Express doesn’t support any currencies marked with an asterisk (*). ## Specify amounts in API requests Currencies are two-decimal currencies unless otherwise specified. All API requests expect `amount` values in the *currency’s minor unit* (The Stripe API expects currency values using the given denomination's smallest unit represented without decimals. For example, enter 1099 to charge 10.99 USD (or any other two-decimal currency). Enter 10 to charge 10 JPY (or any other zero-decimal currency)). For example, set `amount` as follows: - `1000` to charge 10 USD (or any other two-decimal currency). - `10` to charge 10 JPY (or any other zero-decimal currency). ### Zero-decimal currencies For the following zero-decimal currencies, the charge and the amount are the same, without requiring multiplication. For example, to charge 500 JPY, provide an `amount` value of `500`. > This list contains zero-decimal currencies that have general API support. Currencies listed here might not be available in your specific country. For the list of presentment currencies for your country, see [Supported presentment currencies](https://docs.stripe.com/currencies.md#presentment-currencies). ### Special cases The following currencies have special conditions that you need to consider when creating payouts or charges. | Currency | Description | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Icelandic Króna (ISK) | ISK transitioned to a zero-decimal currency, but backward compatibility requires you to represent it as a two-decimal value, where the decimal amount is always `00`. For example, to charge 5 ISK, provide an `amount` value of `500`. You can’t charge fractions of ISK. | | Hungarian Forint (HUF) | Stripe treats HUF as a zero-decimal currency for payouts, even though you can charge two-decimal amounts. When you create a manual payout in HUF, you must provide integer amounts that are evenly divisible by 100. For example, if you have an available balance of HUF 10.45, you can pay out HUF 10 by submitting `1000` for the `amount` value. You can’t submit a payout for the full balance, HUF 10.45, because the `amount` value of `1045` isn’t evenly divisible by 100. | | New Taiwan Dollar (TWD) | Stripe treats TWD as a zero-decimal currency for payouts, even though you can charge two-decimal amounts. When you create a manual payout in TWD, you must provide integer amounts that are evenly divisible by 100. For example, if you have an available balance of TWD 800.45, you can pay out TWD 800 by submitting `80000` for the `amount` value. You can’t submit a payout for the full balance, TWD 800.45, because the `amount` value of `80045` isn’t evenly divisible by 100. | | Ugandan Shilling (UGX) | UGX transitioned to a zero-decimal currency, but backwards compatibility requires you to represent it as a two-decimal value, where the decimal amount is always `00`. For example, to charge 5 UGX, provide an `amount` value of `500`. You can’t charge fractions of UGX. For invoices where the `amount` is fractional after prorations, coupons, or taxes, Stripe automatically rounds that amount to the nearest number evenly divisible by 100. We credit or debit any difference from rounding to the customer balance. | ## Minimum and maximum charge amounts Stripe enforces a minimum payment amount for all charges to make sure the Stripe fee doesn’t exceed your charge. The minimum amount you can charge depends on the payout [bank account settlement currency](https://docs.stripe.com/payouts.md#supported-accounts-and-settlement-currencies). Subscription charges support zero-amount charges to account for coupons and free trials. However, any non-zero amount is still subject to the applicable minimum. ### Minimum charge amount by currency If you only have one bank account, the minimum amount shown applies to all charges in the same currency as the account. Charges requiring [conversion](https://docs.stripe.com/payments/currencies/localize-prices.md) into your account’s [default settlement currency](https://docs.stripe.com/payouts.md#multiple-bank-accounts) must meet the equivalent minimum of the settlement currency. For example, if you have GBP and USD bank accounts, with GBP set as your default currency, any non-USD charges you create convert to GBP. These charges must meet the minimum amount required for GBP after conversion. Use these minimum amounts by currency: - 0.50 USD - 2.00 AED - 0.50 AUD - 0.50 BRL - 0.50 CAD - 0.50 CHF - 15.00 CZK - 2.50 DKK - 0.50 EUR - 0.30 GBP - 4.00 HKD - 175.00 HUF - 0.50 INR - 50 JPY - 10 MXN - 2.00 MYR - 3.00 NOK - 0.50 NZD - 2.00 PLN - 2.00 RON - 3.00 SEK - 0.50 SGD - 10 THB Exceptions to the minimum charge amount apply to some payment methods, such as [iDEAL](https://docs.stripe.com/payments/ideal.md) (allows `amount` values as low as `1`). ### Maximum charge amounts In general, the number of allowed digits limits the maximum amount you can charge a customer. The `amount` value supports up to: - 12 digits for IDR, for a maximum charge of 9,999,999,999.99 IDR (`999999999999`) - 9 digits for IDR with American Express, for a maximum charge of 9,999,999.99 IDR (`999999999`) - 9 digits for INR, for a maximum charge of 9,999,999.99 INR (`999999999`) - 8 digits for all other currencies, for a maximum charge of 999,999.99 (`99999999`) When accepting card payments, these currencies support higher maximum amounts: - 12 digits for LBP, for a maximum charge of 9,999,999,999.99 LBP (`999999999999`) - 10 digits for COP, for a maximum charge of 9,999,999,999.9 COP (`9999999999999`) - 10 digits for HUF, for a maximum charge of 9,999,999,999 HUF (`9999999999999`) - 10 digits for JPY, for a maximum charge of 9,999,999,999 JPY (`9999999999999`) Card networks can impose charge amount limits that are more restrictive than digit number. > When processing JCB, Diners Club, and Discover cards from Japanese Stripe accounts, the maximum amount is 8 digits (99,999,999 JPY), regardless of the JPY currency limits listed above. Learn more about [accepting JCB payments in Japan](https://support.stripe.com/questions/enabling-jcb-payments-for-japan-based-stripe-accounts). ## Supported payment methods In the United States, you can accept these cards: Visa, Mastercard, American Express, Discover, JCB, Diners Club, China UnionPay, debit cards. You can accept additional [payment methods](https://docs.stripe.com/payments/payment-methods/payment-method-support.md#country-currency-support) based on your Stripe account’s country, which you set when you [activate your account](https://docs.stripe.com/get-started/account/activate.md#activation). ### Review EEA card pricing Cards issued in the *European Economic Area* (The European Economic Area is a regional single market with free movement of labor, goods, and capital. It encompasses the European Union member states and three additional states that are part of the European Free Trade Association) (EEA) often have fees that differ from other regions. Processing costs can vary by issuing region because of cross-border fees and exchange rates, which means EEA-issued cards can incur different fees depending on the transaction currency. Use these region-specific fees to inform your pricing when you accept multiple currencies. Stripe defines EEA cards as cards issued in the following countries: - Andorra (AD) - Austria (AT) - Belgium (BE) - Bulgaria (BG) - Croatia (HR) - Cyprus (CY) - Czech Republic (CZ) - Denmark (DK) - Estonia (EE) - Faroe Islands (FO) - Finland (FI) - France (FR) - Germany (DE) - Gibraltar (GI) - Greece (GR) - Greenland (GL) - Guernsey (GG) - Holy See (Vatican City State) (VA) - Hungary (HU) - Iceland (IS) - Ireland (IE) - Isle of Man (IM) - Italy (IT) - Jersey (JE) - Latvia (LV) - Liechtenstein (LI) - Lithuania (LT) - Luxembourg (LU) - Malta (MT) - Monaco (MC) - Netherlands (NL) - Norway (NO) - Poland (PL) - Portugal (PT) - Romania (RO) - Saint Pierre and Miquelon (PM) - San Marino (SM) - Slovakia (SK) - Slovenia (SI) - Spain (ES) - Sweden (SE) - Türkiye (TR) - United Kingdom (GB) ## Countries with foreign exchange control Remittance to or from countries with foreign exchange control (including, but not limited to, Brazil) is carried out exclusively through authorized channels, pursuant to the legislation applicable in those countries. ## See also - [Receive payouts](https://docs.stripe.com/payouts.md) - [Localize prices](https://docs.stripe.com/payments/currencies/localize-prices.md) --- # Source: https://docs.stripe.com/connect/custom-accounts.md # Using Connect with Custom connected accounts Use Custom connected accounts with Connect to control your connected accounts' entire experience. > #### Newer Connect integrations > > The information on this page applies only to platforms that already use legacy connected account types. If you’re setting up a new Connect platform, or your integration uses the Accounts v2 API, see [Configure the behavior of connected accounts](https://docs.stripe.com/connect/accounts-v2/connected-account-configuration.md) to learn about connected account configurations. If your integration uses the Accounts v1 API, see [Account controller properties](https://docs.stripe.com/connect/migrate-to-controller-properties.md#account-controller-properties). A *Custom* connected account is almost completely invisible to the account holder. You, the platform, are responsible for all interactions with your connected accounts and for collecting all the information needed to verify each account. With Custom connected accounts, you can modify the connected account’s details and settings through the API, including managing their bank accounts and *payout* (A payout is the transfer of funds to an external account, usually a bank account, in the form of a deposit) schedule. Since Custom connected account holders can’t log into Stripe, it’s up to you to build the onboarding flow, connected account dashboard, reporting functionality, and communication channels. Creating a Custom connected account involves the following steps: 1. Make sure you meet the [minimum requirements](https://docs.stripe.com/connect/custom-accounts.md#requirements). 1. Properly identify the [country](https://docs.stripe.com/connect/custom-accounts.md#country) and any related requirements. 1. [Create](https://docs.stripe.com/connect/custom-accounts.md#create) the account. 1. Complete the [identity verification](https://docs.stripe.com/connect/custom-accounts.md#identity-verification) process. Identity verification requirements are updated as laws and regulations change globally. If you’re building your own onboarding flow to onboard accounts, you must plan on reviewing and updating onboarding requirements at least every six months. To avoid this maintenance obligation, use [Connect Onboarding for Custom Accounts](https://docs.stripe.com/connect/custom/hosted-onboarding.md). > To comply with French PSD2 regulations, platforms in France [must use account tokens](https://stripe.com/guides/frequently-asked-questions-about-stripe-connect-and-psd2#regulatory-status-of-connect). An additional benefit of tokens is that the platform doesn’t have to store PII data, which is transferred from the connected account directly to Stripe. For platforms in other countries, we recommend using account tokens, but they aren’t required. ## Requirements for creating Custom connected accounts To use Custom connected accounts, you must meet all of these requirements: - **Minimum API version**: You must be using an API version at least as recent as 2014-12-17. You can [view and upgrade](https://dashboard.stripe.com/workbench) your API version in the Dashboard if needed. - **Terms of Service update**: Creating Custom connected accounts requires an [update to your terms of service](https://docs.stripe.com/connect/updating-service-agreements.md#tos-acceptance), as it must include a reference to Stripe’s services agreement. Stripe recommends that you consult with your attorneys on whether you should update your terms acceptance language to include reference to Stripe’s terms. - **Handling information requests**: Instead of requesting information—such as a Social Security Number or passport scan—directly from your connected account user, Stripe requests the information it needs from you. You must collect that information from your connected account and provide it to Stripe. Otherwise, Stripe might disable payouts to the connected account. - **Platform in a supported country**: Platforms in Australia, Austria, Belgium, Brazil, Bulgaria, Canada, Cyprus, the Czech Republic, Denmark, Estonia, Finland, France, Germany, Greece, Hong Kong, Hungary, India, Ireland, Italy, Japan, Latvia, Lithuania, Luxembourg, Malta, Mexico, the Netherlands, New Zealand, Norway, Poland, Portugal, Romania, Singapore, Slovakia, Slovenia, Spain, Sweden, Switzerland, Thailand, the United Kingdom, and the United States can create Custom accounts for any country [Stripe supports](https://stripe.com/global). [Contact us](connect@stripe.com) to be notified when platforms in your country can use Custom connected accounts. - **Countries that don’t support self-serve**: Due to restrictions that apply when using Connect in the [United Arab Emirates](https://support.stripe.com/questions/connect-availability-in-the-uae), [India](https://support.stripe.com/questions/stripe-india-support-for-marketplaces), and [Thailand](https://support.stripe.com/questions/stripe-thailand-support-for-marketplace), platform users in these countries can’t self-serve Custom connected accounts. To begin onboarding for Custom connected accounts in these countries, [contact us](https://stripe.com/contact/sales). - **Platforms in the UAE**: Platforms in the UAE can only use Custom connected accounts based in the UAE with the following charge types: [destination_charges](https://docs.stripe.com/connect/destination-charges.md) and [separate charges and transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md). Destination charges using the [on_behalf_of](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-on_behalf_of) attribute are not yet supported for UAE platforms. > Platforms outside of Mexico that want to create Custom connected accounts in Mexico and make them [settlement merchants](https://docs.stripe.com/connect/account-capabilities.md#card-payments) require further review. [Contact us](https://support.stripe.com/contact) to start the process. - **Vetting for fraud**: Because your platform is responsible for losses incurred by Custom connected accounts, you must scrutinize all accounts that sign up through your platform for potential fraud. Refer to our [risk management best practices guide](https://docs.stripe.com/connect/risk-management/best-practices.md) for more information. Note there’s an [additional cost](https://stripe.com/connect/pricing) for active Custom connected accounts. A Custom connected account is considered active if it has received at least one successful payout in a given month. ## Identify the country to use The only piece of information you need to create a Custom connected account is the country where the individual or business primarily operates. You can collect everything else at a later time. For example, if you’re in the United States and the business or individual you’re creating a connected account for is legally represented in Canada, assign `CA` as the country. The country value also determines the [required verification information](https://docs.stripe.com/connect/required-verification-information.md) for the connected account. ## Create a Custom connected account The basic process to create and connect a Custom connected account is to call the account creation endpoint, setting `type` to `custom` and providing a country and the [appropriate capabilities](https://docs.stripe.com/connect/account-capabilities.md#supported-capabilities). ```curl curl https://api.stripe.com/v1/accounts \ -u "<>:" \ -d country=US \ -d type=custom \ -d "capabilities[card_payments][requested]"=true \ -d "capabilities[transfers][requested]"=true ``` ```cli stripe accounts create \ --country=US \ --type=custom \ -d "capabilities[card_payments][requested]"=true \ -d "capabilities[transfers][requested]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.accounts.create({ country: 'US', type: 'custom', capabilities: { card_payments: {requested: true}, transfers: {requested: true}, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.accounts.create({ "country": "US", "type": "custom", "capabilities": { "card_payments": {"requested": True}, "transfers": {"requested": True}, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->accounts->create([ 'country' => 'US', 'type' => 'custom', 'capabilities' => [ 'card_payments' => ['requested' => true], 'transfers' => ['requested' => true], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountCreateParams params = AccountCreateParams.builder() .setCountry("US") .setType(AccountCreateParams.Type.CUSTOM) .setCapabilities( AccountCreateParams.Capabilities.builder() .setCardPayments( AccountCreateParams.Capabilities.CardPayments.builder() .setRequested(true) .build() ) .setTransfers( AccountCreateParams.Capabilities.Transfers.builder().setRequested(true).build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().accounts().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.accounts.create({ country: 'US', type: 'custom', capabilities: { card_payments: { requested: true, }, transfers: { requested: true, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.AccountCreateParams{ Country: stripe.String("US"), Type: stripe.String(stripe.AccountTypeCustom), Capabilities: &stripe.AccountCreateCapabilitiesParams{ CardPayments: &stripe.AccountCreateCapabilitiesCardPaymentsParams{ Requested: stripe.Bool(true), }, Transfers: &stripe.AccountCreateCapabilitiesTransfersParams{ Requested: stripe.Bool(true), }, }, } result, err := sc.V1Accounts.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new AccountCreateOptions { Country = "US", Type = "custom", Capabilities = new AccountCapabilitiesOptions { CardPayments = new AccountCapabilitiesCardPaymentsOptions { Requested = true }, Transfers = new AccountCapabilitiesTransfersOptions { Requested = true }, }, }; var client = new StripeClient("<>"); var service = client.V1.Accounts; Account account = service.Create(options); ``` Stripe supports cross-border transfers on the payments balance between the United States, Canada, United Kingdom, EEA, and Switzerland. In other scenarios, your platform and any connected account must be in the same region. Attempting to transfer funds across unsupported borders or balances returns an error. See [Cross-border payouts](https://docs.stripe.com/connect/cross-border-payouts.md) for supported funds flows between other regions. You must only use transfers in combination with the permitted use cases for [charges](https://docs.stripe.com/connect/charges.md), [tops-ups](https://docs.stripe.com/connect/top-ups.md) and [fees](https://docs.stripe.com/connect/custom-accounts.md#collect-fees). We recommend using separate charges and transfers only when you’re responsible for negative balances of your connected accounts. The result of a successful API call is the connected account information: ```json { ... "id": ""{{CONNECTED_ACCOUNT_ID}}"", "type": "custom" ... } ``` Store the `id` in your database—it’s the account ID. You’ll provide this value to [authenticate](https://docs.stripe.com/connect/authentication.md) as the connected account by passing it into requests in the `Stripe-Account` header. > Store the received account ID. You need this information to perform requests on the connected account’s behalf. ## Start the identity verification process An account created with only a country is fairly limited: it can only receive a small amount of funds. If you wish to enable payouts and keep the account in good standing, you need to [provide more information](https://docs.stripe.com/connect/identity-verification.md) about the account holder. The [required verification information](https://docs.stripe.com/connect/required-verification-information.md) page lists the minimum and likely identity verification requirements. The easiest way to collect this information is to integrate [Connect Onboarding](https://docs.stripe.com/connect/custom/hosted-onboarding.md), which lets Stripe take care of the verification complexity. Otherwise, you must not only write your own API calls for initial integration, but also continue to check for changing onboarding requirements because of changing regulations around the world. You can collect required information when you [create the account](https://docs.stripe.com/api.md#create_account) or by [updating the account](https://docs.stripe.com/api.md#update_account) later. At the very least, we recommend collecting and providing the connected account user’s name and date of birth up front. If you collect [address information](https://support.stripe.com/questions/connect-address-validation) upfront, make sure to validate the state value for US, CA, and AU connected accounts in your onboarding flow. > For accounts with [business_type](https://docs.stripe.com/api/accounts/object.md#account_object-business_type) set to `individual`, provide at least one `individual` property (for example, `individual.first_name`) and a [Person](https://docs.stripe.com/api/persons/object.md) object is created automatically. If you don’t, or for accounts with the `business_type` set to `company`, you need to [create each Person](https://docs.stripe.com/api/persons/create.md) for the account. ## Webhooks After an account is created, all notifications about changes to the account are sent to your [webhooks](https://docs.stripe.com/connect/webhooks.md) as `account.updated` events. Provide your *Connect* (Connect is Stripe's solution for multi-party businesses, such as marketplace or software platforms, to route payments between sellers, customers, and other recipients) *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) URL in your [account settings](https://dashboard.stripe.com/account/webhooks) and then watch for these events and respond to them as needed. ## See also - [Onboarding custom accounts](https://docs.stripe.com/connect/custom/onboarding.md) - [Updating service agreements](https://docs.stripe.com/connect/updating-service-agreements.md) - [Identity verification](https://docs.stripe.com/connect/identity-verification.md) - [Authentication](https://docs.stripe.com/connect/authentication.md) - [Creating charges](https://docs.stripe.com/connect/charges.md) --- # Source: https://docs.stripe.com/payments/checkout/custom-domains.md # Use your custom domain Learn how to bring your own custom domain to Stripe Checkout, Payment Links, and customer portal. # Stripe-hosted page > This is a Stripe-hosted page for when payment-ui is stripe-hosted. View the full page at https://docs.stripe.com/payments/checkout/custom-domains?payment-ui=stripe-hosted. If you’re using the [Stripe-hosted page](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=checkout&ui=stripe-hosted) for Checkout, you can add your own custom domain to Stripe. Adding custom domains is a paid feature. For information about cost, see Checkout’s [Pricing](https://stripe.com/pricing). ## Add your custom domain to the Stripe Dashboard Decide what subdomain to use with your Checkout Sessions, Payment Links, and customer portal. > If your domain is `example.com`, we recommend using `payments.example.com` as your custom subdomain. You can replace `payments` with anything you like, as long it’s a valid subdomain. You can’t use a path like `example.com/checkout` and must specify a subdomain of your existing domain. After you decide on a subdomain, visit the [Custom domains settings page](https://dashboard.stripe.com/settings/custom-domains) to start the domain connection process. On the settings page click **Add your domain**. In the pop up, enter your desired subdomain. Click **Add** when you’re done. You’ll see the popup update with instructions for setting up your DNS records. Your custom domain is activated automatically when your DNS records are verified. To disable this behavior, uncheck the **Switch to this domain once added** checkbox. > #### When will my domain be added? > > When your domain is in the `Adding...` state, we wait to verify your DNS records that you set up in the next step. After Stripe verifies the DNS records, we create TLS certificates for your subdomain, set up the correct CDN routing, and then your domain is `ready` to enable and use. ## Identify your DNS Provider To start, figure out what service is managing your DNS records, so you know exactly where to login and create the new records. If you **already know** your DNS provider, you can move on to the next section. Often, it’s the same place you registered your domain, but sometimes the DNS provider is different from your domain registrar. If you’re not certain who your DNS provider is, try looking up your domain’s nameservers, replacing **stripe.com** with your own domain in this command: ```bash nslookup -querytype=NS stripe.com ``` You’ll see a list of nameservers for your domain in the output. Here’s some example output for **stripe.com**: ``` # Looks like AWS is providing our DNS here: stripe.com nameserver = ns-423.awsdns-52.com. stripe.com nameserver = ns-705.awsdns-24.net. stripe.com nameserver = ns-1087.awsdns-07.org. stripe.com nameserver = ns-1882.awsdns-43.co.uk. ``` If you’re more comfortable using a browser-based tool, go to [MXLookup’s DNS Lookup tool](https://mxtoolbox.com/DnsLookup.aspx) and enter your domain. It might be able to tell you who your DNS provider is (but not always). ## Create required DNS records In this section, you’ll create the DNS records you need to connect your domain. As you go through each step, check each checkbox to keep track of where you are in the process. Select the tab that matches your DNS provider from the tabs below—this gives you specific, guided instructions for creating the required DNS records. If your DNS provider isn’t an option, follow the Standard instructions: #### Standard instructions These are standard instructions for creating your DNS records. If you have issues with any of the steps, please contact your DNS provider for more assistance. > To track your progress, go through each step and check it off when you’ve completed it. - [ ] Sign into your DNS provider Most DNS providers have a control panel you can sign into to manage your DNS. Find your provider’s control panel page and sign in. - [ ] Find the page to manage the DNS for your domain Now that you’re logged in, find where you can manage the DNS records for your domain in your provider’s control panel. If you’re having issues finding the right page, you can: - See if your DNS provider has a help article for adding new DNS records that can point you in the right direction. - Contact your DNS provider for additional support. - [ ] Create your CNAME record From your DNS control panel, add a new record that maps your desired subdomain to Checkout. Most DNS providers ask you for the record type, name, value, and TTL or expiration when creating a new record. > This record is what connects your subdomain to Stripe Checkout. Enter these values and save the new DNS record: | Field | Instructions | Description | | -------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Type** | Select `CNAME` from the dropdown | What kind of DNS record this is. | | **Name** | If your custom subdomain is **checkout.powdur.me**, enter `checkout` | For CNAME records, this field is the first part of your subdomain (the part leading up to the first period). | | **Value** | Enter `hosted-checkout.stripecdn.com` | This is what the new subdomain record points to–in this case, Stripe. Some providers may expect a trailing period (`.`) after the CNAME value. Make sure to verify that your CNAME value matches the format your provider expects. | | **TTL/Expiry** | Enter `300` | An expiration of 5 minutes (300 seconds) is OK. Your DNS provider might not allow you to change the TTL value. If this field is missing or you can’t change it, it’s safe to ignore this part of the configuration. | - [ ] Create your TXT record From your DNS control panel, add a new TXT record. > This TXT record lets us verify that you’re the owner of this domain. This is required to issue TLS certificates for your domain, so you can continue to accept payments securely. Enter these values and save the new DNS record: | Field | Instructions | Description | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Type** | Select `TXT` from the dropdown | What kind of DNS record this is. | | **Name** | If your custom domain is **checkout.powdur.me**, enter `_acme-challenge.checkout` | For TXT records, this field is the subdomain portion of your domain. | | **Value** | Visit the [Dashboard settings](https://dashboard.stripe.com/settings/custom-domains) and click **View instructions** to copy the correct TXT value record. | This is a long, unique string used for domain verification. | | **TTL/Expiry** | Enter `300` | An expiration of 5 minutes (300 seconds) is OK. Your DNS provider might not allow you to change the TTL value. If this field is missing or you can’t change it, it’s safe to ignore this part of the configuration. | - [ ] Verify your CNAME record is setup After you save your DNS record, verify that it has the correct values. #### Verify in your terminal 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Replace **checkout.powdur.me** with your custom domain in the following command and run it from your terminal: ```bash nslookup -querytype=CNAME checkout.powdur.me ``` You should see output like: ``` canonical name = hosted-checkout.stripecdn.com. ``` When you see that output, move onto the next step. #### Verify with your web browser 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Open the [NSLookup Online Tool](https://coding.tools/nslookup). 1. Enter your custom domain name in the **Domain or IP Address** field. 1. Select **CNAME (Canonical name record)** from the **Query Type** dropdown. 1. Click **Nslookup** to query for your CNAME record. You should see `canonical name = hosted-checkout.stripecdn.com` in the output. When you see that output, move onto the next step. If you don’t see that output at first, wait a few minutes and try the query again. - [ ] Verify your TXT record After you save your DNS record, verify that it has the correct values. #### Verify in your terminal 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Replace **checkout.powdur.me** with your custom domain in the following command and run it from your terminal: ```bash nslookup -querytype=TXT _acme-challenge.checkout.powdur.me ``` You should see output like this: ``` _acme-challenge. text = "" ``` If you don’t see your unique TXT record value in the output, wait a bit longer and try running the command again. #### Verify with your web browser 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Open the [NSLookup Online Tool](https://coding.tools/nslookup). 1. Enter `_acme-challenge.[your custom domain name]` in the **Domain or IP Address** field. 1. Select **TXT (Text record)** from the **Query Type** dropdown. 1. Click **Nslookup** to query for your CNAME record. You’ll see the TXT record value you entered in the previous step in the output. If you don’t see that output at first, wait a few minutes and try the query again. When you finish this step, your DNS records are configured. #### GoDaddy Use these instructions to create your DNS records with GoDaddy. If you have issues with any of the steps, please [contact GoDaddy Support](https://www.godaddy.com/help/contact-us) for more assistance. > To track your progress, go through each step and check it off when you completed it. - [ ] Sign into GoDaddy Visit [GoDaddy](https://sso.godaddy.com/) and log into the GoDaddy dashboard. - [ ] Navigate to the DNS panel for your domain From the GoDaddy Dashboard: 1. Click your domain on the GoDaddy home page: ![The GoDaddy homepage](https://b.stripecdn.com/docs-statics-srv/assets/home.20b5c1d760ee29489f34bd2da87f72d9.png) 1. You should now be on the admin page for your domain: ![The GoDaddy Admin view](https://b.stripecdn.com/docs-statics-srv/assets/admin.e30f10909b86e9d6ea9452f5fba6d324.png) 1. Click **View Domain Settings**. 1. Click **Manage DNS**. 1. You should see a DNS management page for your domain: ![The GoDaddy DNS Management view](https://b.stripecdn.com/docs-statics-srv/assets/dns-management.0ba48fee0b095cfb135eec91f30476d2.png) - [ ] Create your CNAME record Add a new record that maps your desired subdomain to Stripe Checkout. 1. Click **Add** in the DNS Records section. 1. Enter these values in the form that opens: | Field | Value to enter | Description | | --------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | **Type** | Select `CNAME` from the dropdown | What kind of DNS record this is. | | **Name** | If your custom subdomain is **checkout.powdur.me**, enter `checkout` | For CNAME records, this field is the first part of your subdomain (the part leading up to the first period). | | **Value** | `hosted-checkout.stripecdn.com` | This is what the new subdomain record points to–in this case, Stripe Checkout. | | **TTL** | Select `Custom` from the dropdown and enter `600` seconds | An expiration of 10 minutes (600 seconds) is OK. | ![What the form looks like filled out, for an example domain](https://b.stripecdn.com/docs-statics-srv/assets/filled-form-cname.c1208c4e8b931447ecdec0fff817d14b.png) An example of what the form for adding your CNAME record might look like when filled out. 1. Click **Add record**. 1. You’ll see a new table row for the new DNS record, with the following values: - **Type**: `CNAME` - **Name**: `` - **Data**: `hosted-checkout.stripecdn.com` - **TTL**: 600 seconds - [ ] Create your TXT record From your DNS Management page, add a new TXT record. > This TXT record lets us verify that you’re the owner of this domain. This is required to issue TLS certificates for your domain, so you can continue to accept payments securely. 1. Click **Add**. 1. Enter these values in the form that opens: | Field | Value to enter | Description | | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | **Type** | Select `TXT` from the dropdown | What kind of DNS record this is. | | **Name** | If your custom domain is **checkout.powdur.me**, enter `_acme-challenge.checkout` | For TXT records, this field is the subdomain portion of your domain. | | **Value** | Visit the [Dashboard settings](https://dashboard.stripe.com/settings/custom-domains) and click **View instructions** to copy the correct TXT value record. | This is a long, unique string used for domain verification. | | **TTL** | Select `Custom` from the dropdown and enter `600` seconds | An expiration of 10 minutes (600 seconds) is OK. | ![What the form looks like filled out, for an example domain](https://b.stripecdn.com/docs-statics-srv/assets/filled-form-txt.a717729a495d2aa61a68381155206f37.png) An example of what the form for adding your TXT record might look like when filled out. 1. Click **Add record**. 1. You’ll see a new table row for the new DNS record, with the following values: - **Type**: `TXT` - **Name**: `_acme-challenge.` - **Data**: `` - **TTL**: 600 seconds - [ ] Verify your CNAME record is setup After you save your DNS record, verify that it has the correct values. #### Verify in your terminal 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Replace **checkout.powdur.me** with your custom domain in the following command and run it from your terminal: ```bash nslookup -querytype=CNAME checkout.powdur.me ``` You should see output like: ``` canonical name = hosted-checkout.stripecdn.com. ``` When you see that output, move onto the next step. #### Verify with your web browser 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Open the [NSLookup Online Tool](https://coding.tools/nslookup). 1. Enter your custom domain name in the **Domain or IP Address** field. 1. Select **CNAME (Canonical name record)** from the **Query Type** dropdown. 1. Click **Nslookup** to query for your CNAME record. You should see `canonical name = hosted-checkout.stripecdn.com` in the output. When you see that output, move onto the next step. If you don’t see that output at first, wait a few minutes and try the query again. - [ ] Verify your TXT record After you save your DNS record, verify that it has the correct values. #### Verify in your terminal 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Replace **checkout.powdur.me** with your custom domain in the following command and run it from your terminal: ```bash nslookup -querytype=TXT _acme-challenge.checkout.powdur.me ``` You should see output like this: ``` _acme-challenge. text = "" ``` If you don’t see your unique TXT record value in the output, wait a bit longer and try running the command again. #### Verify with your web browser 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Open the [NSLookup Online Tool](https://coding.tools/nslookup). 1. Enter `_acme-challenge.[your custom domain name]` in the **Domain or IP Address** field. 1. Select **TXT (Text record)** from the **Query Type** dropdown. 1. Click **Nslookup** to query for your CNAME record. You’ll see the TXT record value you entered in the previous step in the output. If you don’t see that output at first, wait a few minutes and try the query again. When you finish this step, your DNS records are configured. If you need any additional information, please read GoDaddy’s official developer guides, starting with [Manage DNS records](https://www.godaddy.com/help/manage-dns-records-680). #### Cloudflare Use these instructions to create your DNS records with Cloudflare. If you have issues with any of the steps, please [contact Cloudflare Support](https://support.cloudflare.com/) for more assistance. > To track your progress, go through each step and check it off when you completed it. - [ ] Sign into Cloudflare Visit [Cloudflare](https://cloudflare.com) and log into the Cloudflare dashboard. - [ ] Navigate to the DNS panel for your domain From the Cloudflare Dashboard: 1. Click **Websites** on the left side of the page. 1. Find your domain in the list of websites. 1. Click the table row containing your domain name: ![The table of websites you'll see on the Cloudflare dashboard](https://b.stripecdn.com/docs-statics-srv/assets/websites-table.c794d196f321659ff795e7456e8c1438.png) In this example image, you’d click on the powdur.me table row. 1. You should now be on the admin page for your domain. 1. Click **DNS** on the left side of the page. 1. You should see a DNS management page for your domain: ![The DNS view](https://b.stripecdn.com/docs-statics-srv/assets/dns-panel.deb9b0988ff2b2864d39ccd498d7c351.png) - [ ] Create your CNAME record Add a new record that maps your desired subdomain to Stripe Checkout. 1. Click **Add record**. 1. Enter these values in the form that opens: | Field | Value to enter | Description | | ---------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | **Type** | Select `CNAME` from the dropdown | What kind of DNS record this is. | | **Target** | If your custom subdomain is **checkout.powdur.me**, enter `checkout` | For CNAME records, this field is the first part of your subdomain (the part leading up to the first period). | | **Value** | `hosted-checkout.stripecdn.com` | This is what the new subdomain record points to–in this case, Stripe Checkout. | | **TTL** | `5 min` | An expiration of 5 minutes (300 seconds) is OK. | | **Proxy status** | `Off` | Set the proxy status to `off` to avoid issues during setup. | ![What the form looks like filled out, for an example domain](https://b.stripecdn.com/docs-statics-srv/assets/filled-form-cname.fd46677b9723447c3f718939e97b8007.png) An example of what the form for adding your CNAME record might look like when filled out. 1. Click **Save**. 1. You’ll see a new table row for the new DNS record, with the following values: - **Type**: `CNAME` - **Name**: `` - **Content**: `hosted-checkout.stripecdn.com` - **Proxy status**: DNS only - **TTL**: 5 minutes - [ ] Create your TXT record From your DNS control panel, add a new TXT record. > This TXT record lets us verify that you’re the owner of this domain. This is required to issue TLS certificates for your domain, so you can continue to accept payments securely. 1. Click **Add record**. 1. Enter these values in the form that opens: | Field | Value to enter | Description | | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | **Type** | Select `TXT` from the dropdown | What kind of DNS record this is. | | **Name** | If your custom domain is **checkout.powdur.me**, enter `_acme-challenge.checkout` | For TXT records, this field is the subdomain portion of your domain. | | **Content** | Visit the [Dashboard settings](https://dashboard.stripe.com/settings/custom-domains) and click **View instructions** to copy the correct TXT value record. | This is a long, unique string used for domain verification. | | **TTL** | `5 min` | An expiration of 5 minutes (300 seconds) is OK. | ![What the form looks like filled out, for an example domain](https://b.stripecdn.com/docs-statics-srv/assets/filled-form-txt.5d164d597718eff86d45e6ce1e8d2d6a.png) An example of what the form for adding your TXT record might look like when filled out. 1. Click **Save**. 1. You’ll see a new table row for the new DNS record, with the following values: - **Type**: `TXT` - **Name**: `_acme-challenge.` - **Content**: `` - **Proxy status**: DNS only - **TTL**: 5 minutes - [ ] Verify your CNAME record is setup After you save your DNS record, verify that it has the correct values. #### Verify in your terminal 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Replace **checkout.powdur.me** with your custom domain in the following command and run it from your terminal: ```bash nslookup -querytype=CNAME checkout.powdur.me ``` You should see output like: ``` canonical name = hosted-checkout.stripecdn.com. ``` When you see that output, move onto the next step. #### Verify with your web browser 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Open the [NSLookup Online Tool](https://coding.tools/nslookup). 1. Enter your custom domain name in the **Domain or IP Address** field. 1. Select **CNAME (Canonical name record)** from the **Query Type** dropdown. 1. Click **Nslookup** to query for your CNAME record. You should see `canonical name = hosted-checkout.stripecdn.com` in the output. When you see that output, move onto the next step. If you don’t see that output at first, wait a few minutes and try the query again. - [ ] Verify your TXT record After you save your DNS record, verify that it has the correct values. #### Verify in your terminal 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Replace **checkout.powdur.me** with your custom domain in the following command and run it from your terminal: ```bash nslookup -querytype=TXT _acme-challenge.checkout.powdur.me ``` You should see output like this: ``` _acme-challenge. text = "" ``` If you don’t see your unique TXT record value in the output, wait a bit longer and try running the command again. #### Verify with your web browser 1. Wait up to 10 minutes for your DNS provider to update its nameservers. 1. Open the [NSLookup Online Tool](https://coding.tools/nslookup). 1. Enter `_acme-challenge.[your custom domain name]` in the **Domain or IP Address** field. 1. Select **TXT (Text record)** from the **Query Type** dropdown. 1. Click **Nslookup** to query for your CNAME record. You’ll see the TXT record value you entered in the previous step in the output. If you don’t see that output at first, wait a few minutes and try the query again. When you finish this step, your DNS records are configured. If you need any additional information, please read Cloudflare’s official developer guides, starting with [Manage DNS records](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/). > If verifying your DNS records or domain seems very slow, try setting CNAME flattening to > > **Flatten CNAME at root**> > .> > > > You can find that setting in your Cloudflare Dashboard under > > **DNS**> > > > > **Settings**> > > > > **CNAME Flattening**> > .> > > > If setting CNAME Flattening doesn’t fix the issue, > > [contact Stripe Support](https://support.stripe.com/)> > . Now that you’ve created your DNS records and verified them, Stripe verifies the connection and provisions your domain on our end. We’ll send you an email and a Dashboard notification when the domain is ready for you to enable it. You can also visit the [Dashboard settings](https://dashboard.stripe.com/settings/custom-domains) at any time to see the current status of your custom domain connection. ## Optional: Test your custom domain ### Create a test payment link You receive a notification when your custom domain is added and enabled for testing. 1. Go to the [Dashboard settings](https://dashboard.stripe.com/settings/custom-domains). 1. Verify you have an `Added` indicator above your custom domain name. 1. [Create a payment link](https://docs.stripe.com/payment-links/create.md) in test mode. You see your new custom domain in the details page of your newly created payment link. > Adding custom domains is currently not supported in sandboxes. ## Optional: Removing your custom domain If you need to remove your custom domain for any reason, you can. If you remove your custom domain, you’ll need to remove any DNS records you created for your custom subdomain and follow this guide again to add it back. To remove your custom domain completely: 1. Go to the [Dashboard settings](https://dashboard.stripe.com/settings/custom-domains) for custom domains. 1. Click the **Remove** button. 1. Read the popup confirmation, and click **Remove** to confirm the removal. 1. Login to your DNS provider and delete the two DNS records you previously created for your custom subdomain. > After you cancel your subscription, payment links and the customer portal link that use your custom domain stop working. You can copy and share new `buy.stripe.com` or `billing.stripe.com` links for each of your existing links. ## Optional: Using custom domains with Connect When combining custom domains with a Connect integration, we match the same rules as our other [branding settings](https://docs.stripe.com/payments/checkout/customization.md): | Connect integration type | Description | Which account’s custom domain is used? | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | Destination charge | Your integration uses `payment_intent_data[transfer_data][destination]`. See [docs](https://docs.stripe.com/connect/destination-charges.md) to read more. | The **platform account’s** domain. | | `on_behalf_of` | Similar to the destination charge, but the settlement merchant is different. See [docs](https://docs.stripe.com/connect/destination-charges.md#settlement-merchant) to read more. | The **connected account’s** domain. | | Direct charge | Your integration passes in the connected account ID in the `Stripe-Account` header. See [docs](https://docs.stripe.com/connect/direct-charges.md) to read more. | The **connected account’s** domain. | | Separate charges and transfers | Charges and transfers are handled separately from the Checkout Session. See [docs](https://docs.stripe.com/connect/separate-charges-and-transfers.md) to read more. | The **platform account’s** domain. | ## Optional: Troubleshooting your integration If you’ve gone through this guide and activated your custom domain in live mode but still aren’t seeing it used for your Checkout Sessions, you might be using an unsupported Checkout integration type. Stripe has three types of Checkout integrations, and we only support server-side redirects today. Use this table to figure out what kind of integration you’re using: | Integration type | You’re using this type if… | Notes | Works with custom domains? | | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | -------------------------- | | Client-only integration | If you’re not creating Checkout Sessions from your server and are only using client-side [stripe.redirectToCheckout](https://docs.stripe.com/js/deprecated/redirect_to_checkout) and providing items such as SKUs or Plans. | This integration path is deprecated. | **✗ No** | | Server-side Checkout Session creation and client-side `stripe.redirectToCheckout` | If you’re creating Checkout Sessions from your server and redirecting your customers client-side by using [stripe.redirectToCheckout](https://docs.stripe.com/js/deprecated/redirect_to_checkout) and providing the Checkout Session ID. | This was the standard documented integration path before September 2021. | **✗ No** | | Server-side Checkout Session creation and redirect | If you’re creating Checkout Sessions and redirecting your customers to the returned [URL](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-url) all server-side. See the [Accept a payment](https://docs.stripe.com/payments/accept-a-payment.md?integration=checkout) guide for an example. | This is the standard documented integration path since September 2021. | **✓ Yes** | If you’re using an unsupported integration type, use our [Accept a payment guide](https://docs.stripe.com/payments/accept-a-payment.md?integration=checkout) to switch to using server-side redirects so you can start using custom domains. ## Optional: Troubleshooting CAA DNS records The following CAA DNS records issues can occur when you attempt to add a custom domain to Checkout: - Your CAA record doesn’t include `letsencrypt.org` as a valid CA issuer. - You have a CAA record at the same level as your custom domain name. ### Your CAA record doesn’t include letsencrypt.org as a valid CA issuer Stripe uses [Let’s Encrypt](https://letsencrypt.org) to generate TLS certificates for your custom domain. This ensures that all requests to your custom domain are secure and encrypted. As a result, if you have an existing `CAA` DNS record, you need to include `letsencrypt.org` as a valid issuer. To add Let’s Encrypt as an issuer: 1. Go to your DNS panel and find the existing `CAA` record for your domain, and make a note of its current values. 1. Add a new record at the same level as your other `CAA` records, and enter these values: - **Name**: This should be the same as your other CAA records. There is usually a name of `@` for CAA records on the root of the domain (for example, `powdur.me`). - **Flags**: `0` - **Tag**: `issue` - **Value**: `letsencrypt.org` - **TTL**: 3600 seconds (1 hour) is a good default. 1. Save the record. Most DNS updates take effect within an hour, but could take up to 72 hours to update globally. To read more about setting up Let’s Encrypt CAA records, see their [CAA guide](https://letsencrypt.org/docs/caa/). ### Your CAA record is at the same level as your custom domain name If you received an error in the Dashboard about your CAA record being at the same level as your custom domain name, there’s already an existing `CAA` DNS record for the custom domain name that you’re trying to connect to Checkout. For example, if you’re trying to connect **checkout.powdur.me** to Checkout but there’s already a `CAA` DNS record at that domain, Stripe returns an error. You have a few options for fixing this issue: 1. You can move the `CAA` record down a level: - If you want a custom domain name of **checkout.powdur.me**, you can create a duplicate `CAA` record with the same values at **powdur.me** instead. - Once the new `CAA` record has propagated, you can safely remove the conflicting `CAA` record from your DNS provider. - Once the removal has propagated, you can try to add your custom domain to the Dashboard again. 1. You can choose a custom domain name above your `CAA` record. - If your `CAA` record lives at **checkout.powdur.me**, you could choose a custom domain name like **pay.checkout.powdur.me**. ## Optional: Troubleshooting a blocked domain Cloudflare, our domain provider, occasionally blocks some domains from being automatically added to Cloudflare as part of an additional security check. If you’re seeing an error message in the [Dashboard settings](https://dashboard.stripe.com/settings/custom-domains) about Cloudflare blocking your domain, you can email [abusereply@cloudflare.com](mailto:abusereply@cloudflare.com) to resolve the issue. When emailing Cloudflare, copy and paste this email template and change any of the bold **[placeholders]** to your own information: **To:** abusereply@cloudflare.com **Subject:** Unblock request for **[insert your domain name]** Cloudflare, We’re in the process of adding a custom domain name to Stripe Checkout that leverages Cloudflare. It’s currently blocked by you. Can you please unblock this hostname for us? Domain/Hostname we are attempting to add: **[insert your domain name]** Association with the domain: **[provide an explanation of your association with/ownership of the domain]** Please let us know if you have additional questions. Thanks,**[Your name]** # Embedded form > This is a Embedded form for when payment-ui is embedded-form. View the full page at https://docs.stripe.com/payments/checkout/custom-domains?payment-ui=embedded-form. This feature doesn’t apply to using the embedded form since it’s embedded in your website. # Embedded components > This is a Embedded components for when payment-ui is embedded-components. View the full page at https://docs.stripe.com/payments/checkout/custom-domains?payment-ui=embedded-components. This feature doesn’t apply to using embedded components since they’re embedded in your website. --- # Source: https://docs.stripe.com/payments/checkout/custom-fields.md # Add custom fields Add additional fields to a prebuilt payment page with Checkout. You can add custom fields on the payment form to collect additional information from your customers. The information is available after the payment is complete and is useful for fulfilling the purchase. Custom fields have the following limitations: - Up to three fields allowed. - Not available in `setup` mode. - Support for up to 255 characters on text fields. - Support for up to 255 digits on numeric fields. - Support for up to 200 options on dropdown fields. > Don’t use custom fields to collect personal, protected, or sensitive data, or information restricted by law. ## Create a Checkout Session Create a Checkout Session while specifying an array of [custom fields](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-custom_fields). Each field must have a unique `key` that your integration uses to reconcile the field. Also provide a label for the field that you display to your customer. Labels for custom fields aren’t translated, but you can use the [locale](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-locale) parameter to set the language of your Checkout Session to match the same language as your labels. #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text ``` ```cli stripe checkout sessions create \ --mode=payment \ --success-url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "success_url": "https://example.com/success", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "engraving", "label": {"type": "custom", "custom": "Personalized engraving"}, "type": "text", }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'success_url' => 'https://example.com/success', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'engraving', 'label' => [ 'type' => 'custom', 'custom' => 'Personalized engraving', ], 'type' => 'text', ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("engraving") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Personalized engraving") .build() ) .setType(SessionCreateParams.CustomField.Type.TEXT) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("engraving"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Personalized engraving"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeText), }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", SuccessUrl = "https://example.com/success", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "engraving", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Personalized engraving", }, Type = "text", }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text ``` ```cli stripe checkout sessions create \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "engraving", "label": {"type": "custom", "custom": "Personalized engraving"}, "type": "text", }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'engraving', 'label' => [ 'type' => 'custom', 'custom' => 'Personalized engraving', ], 'type' => 'text', ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("engraving") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Personalized engraving") .build() ) .setType(SessionCreateParams.CustomField.Type.TEXT) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("engraving"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Personalized engraving"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeText), }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "engraving", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Personalized engraving", }, Type = "text", }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ![](https://d37ugbyn3rpeym.cloudfront.net/videos/checkout/custom_fields_embedded.mov) ## Retrieve custom fields When your customer completes the Checkout Session, we send a [checkout.session.completed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) with the completed fields. Example `checkout.session.completed` payload: ```json { "id": "evt_1Ep24XHssDVaQm2PpwS19Yt0", "object": "event", "api_version": "2022-11-15", "created": 1664928000, "data": { "object": { "id": "cs_test_MlZAaTXUMHjWZ7DcXjusJnDU4MxPalbtL5eYrmS2GKxqscDtpJq8QM0k", "object": "checkout.session","custom_fields": [{ "key": "engraving", "label": { "type": "custom", "custom": "Personalized engraving" }, "optional": false, "type": "text", "text": { "value": "Jane" } }], "mode": "payment" } }, "livemode": false, "pending_webhooks": 1, "request": { "id": null, "idempotency_key": null }, "type": "checkout.session.completed" } ``` You can also look up and edit custom field values from the Dashboard, by clicking into a specific payment in the [Transactions](https://dashboard.stripe.com/payments) tab or including custom field values when exporting your payments from the [Dashboard](https://dashboard.stripe.com/payments). ## Use a custom field ### Mark a field as optional By default, customers must complete all fields before completing payment. To mark a field as optional, pass in `optional=true`. #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][optional]"=true ``` ```cli stripe checkout sessions create \ --mode=payment \ --success-url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][optional]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', optional: true, }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "success_url": "https://example.com/success", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "engraving", "label": {"type": "custom", "custom": "Personalized engraving"}, "type": "text", "optional": True, }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'success_url' => 'https://example.com/success', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'engraving', 'label' => [ 'type' => 'custom', 'custom' => 'Personalized engraving', ], 'type' => 'text', 'optional' => true, ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("engraving") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Personalized engraving") .build() ) .setType(SessionCreateParams.CustomField.Type.TEXT) .setOptional(true) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', optional: true, }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("engraving"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Personalized engraving"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeText), Optional: stripe.Bool(true), }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", SuccessUrl = "https://example.com/success", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "engraving", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Personalized engraving", }, Type = "text", Optional = true, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][optional]"=true ``` ```cli stripe checkout sessions create \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][optional]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', optional: true, }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "engraving", "label": {"type": "custom", "custom": "Personalized engraving"}, "type": "text", "optional": True, }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'engraving', 'label' => [ 'type' => 'custom', 'custom' => 'Personalized engraving', ], 'type' => 'text', 'optional' => true, ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("engraving") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Personalized engraving") .build() ) .setType(SessionCreateParams.CustomField.Type.TEXT) .setOptional(true) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', optional: true, }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("engraving"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Personalized engraving"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeText), Optional: stripe.Bool(true), }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "engraving", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Personalized engraving", }, Type = "text", Optional = true, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ![](https://b.stripecdn.com/docs-statics-srv/assets/optional.bf0c1564296ff02264bd5e8c066a6034.png) ### Add a dropdown field A dropdown field presents your customers with a list of options to select from. To create a dropdown field, specify `type=dropdown` and a list of options, each with a `label` and a `value`. The `label` displays to the customer while your integration uses the `value` to reconcile which option the customer selected. #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=sample \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Free sample" \ -d "custom_fields[0][optional]"=true \ -d "custom_fields[0][type]"=dropdown \ -d "custom_fields[0][dropdown][options][0][label]"="Balm sample" \ -d "custom_fields[0][dropdown][options][0][value]"=balm \ -d "custom_fields[0][dropdown][options][1][label]"="BB cream sample" \ -d "custom_fields[0][dropdown][options][1][value]"=cream ``` ```cli stripe checkout sessions create \ --mode=payment \ --success-url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=sample \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Free sample" \ -d "custom_fields[0][optional]"=true \ -d "custom_fields[0][type]"=dropdown \ -d "custom_fields[0][dropdown][options][0][label]"="Balm sample" \ -d "custom_fields[0][dropdown][options][0][value]"=balm \ -d "custom_fields[0][dropdown][options][1][label]"="BB cream sample" \ -d "custom_fields[0][dropdown][options][1][value]"=cream ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'sample', label: { type: 'custom', custom: 'Free sample', }, optional: true, type: 'dropdown', dropdown: { options: [ { label: 'Balm sample', value: 'balm', }, { label: 'BB cream sample', value: 'cream', }, ], }, }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "success_url": "https://example.com/success", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "sample", "label": {"type": "custom", "custom": "Free sample"}, "optional": True, "type": "dropdown", "dropdown": { "options": [ {"label": "Balm sample", "value": "balm"}, {"label": "BB cream sample", "value": "cream"}, ], }, }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'success_url' => 'https://example.com/success', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'sample', 'label' => [ 'type' => 'custom', 'custom' => 'Free sample', ], 'optional' => true, 'type' => 'dropdown', 'dropdown' => [ 'options' => [ [ 'label' => 'Balm sample', 'value' => 'balm', ], [ 'label' => 'BB cream sample', 'value' => 'cream', ], ], ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("sample") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Free sample") .build() ) .setOptional(true) .setType(SessionCreateParams.CustomField.Type.DROPDOWN) .setDropdown( SessionCreateParams.CustomField.Dropdown.builder() .addOption( SessionCreateParams.CustomField.Dropdown.Option.builder() .setLabel("Balm sample") .setValue("balm") .build() ) .addOption( SessionCreateParams.CustomField.Dropdown.Option.builder() .setLabel("BB cream sample") .setValue("cream") .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'sample', label: { type: 'custom', custom: 'Free sample', }, optional: true, type: 'dropdown', dropdown: { options: [ { label: 'Balm sample', value: 'balm', }, { label: 'BB cream sample', value: 'cream', }, ], }, }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("sample"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Free sample"), }, Optional: stripe.Bool(true), Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeDropdown), Dropdown: &stripe.CheckoutSessionCreateCustomFieldDropdownParams{ Options: []*stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ &stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ Label: stripe.String("Balm sample"), Value: stripe.String("balm"), }, &stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ Label: stripe.String("BB cream sample"), Value: stripe.String("cream"), }, }, }, }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", SuccessUrl = "https://example.com/success", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "sample", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Free sample", }, Optional = true, Type = "dropdown", Dropdown = new Stripe.Checkout.SessionCustomFieldDropdownOptions { Options = new List { new Stripe.Checkout.SessionCustomFieldDropdownOptionOptions { Label = "Balm sample", Value = "balm", }, new Stripe.Checkout.SessionCustomFieldDropdownOptionOptions { Label = "BB cream sample", Value = "cream", }, }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=sample \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Free sample" \ -d "custom_fields[0][optional]"=true \ -d "custom_fields[0][type]"=dropdown \ -d "custom_fields[0][dropdown][options][0][label]"="Balm sample" \ -d "custom_fields[0][dropdown][options][0][value]"=balm \ -d "custom_fields[0][dropdown][options][1][label]"="BB cream sample" \ -d "custom_fields[0][dropdown][options][1][value]"=cream ``` ```cli stripe checkout sessions create \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=sample \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Free sample" \ -d "custom_fields[0][optional]"=true \ -d "custom_fields[0][type]"=dropdown \ -d "custom_fields[0][dropdown][options][0][label]"="Balm sample" \ -d "custom_fields[0][dropdown][options][0][value]"=balm \ -d "custom_fields[0][dropdown][options][1][label]"="BB cream sample" \ -d "custom_fields[0][dropdown][options][1][value]"=cream ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'sample', label: { type: 'custom', custom: 'Free sample', }, optional: true, type: 'dropdown', dropdown: { options: [ { label: 'Balm sample', value: 'balm', }, { label: 'BB cream sample', value: 'cream', }, ], }, }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "sample", "label": {"type": "custom", "custom": "Free sample"}, "optional": True, "type": "dropdown", "dropdown": { "options": [ {"label": "Balm sample", "value": "balm"}, {"label": "BB cream sample", "value": "cream"}, ], }, }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'sample', 'label' => [ 'type' => 'custom', 'custom' => 'Free sample', ], 'optional' => true, 'type' => 'dropdown', 'dropdown' => [ 'options' => [ [ 'label' => 'Balm sample', 'value' => 'balm', ], [ 'label' => 'BB cream sample', 'value' => 'cream', ], ], ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("sample") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Free sample") .build() ) .setOptional(true) .setType(SessionCreateParams.CustomField.Type.DROPDOWN) .setDropdown( SessionCreateParams.CustomField.Dropdown.builder() .addOption( SessionCreateParams.CustomField.Dropdown.Option.builder() .setLabel("Balm sample") .setValue("balm") .build() ) .addOption( SessionCreateParams.CustomField.Dropdown.Option.builder() .setLabel("BB cream sample") .setValue("cream") .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'sample', label: { type: 'custom', custom: 'Free sample', }, optional: true, type: 'dropdown', dropdown: { options: [ { label: 'Balm sample', value: 'balm', }, { label: 'BB cream sample', value: 'cream', }, ], }, }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("sample"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Free sample"), }, Optional: stripe.Bool(true), Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeDropdown), Dropdown: &stripe.CheckoutSessionCreateCustomFieldDropdownParams{ Options: []*stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ &stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ Label: stripe.String("Balm sample"), Value: stripe.String("balm"), }, &stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ Label: stripe.String("BB cream sample"), Value: stripe.String("cream"), }, }, }, }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "sample", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Free sample", }, Optional = true, Type = "dropdown", Dropdown = new Stripe.Checkout.SessionCustomFieldDropdownOptions { Options = new List { new Stripe.Checkout.SessionCustomFieldDropdownOptionOptions { Label = "Balm sample", Value = "balm", }, new Stripe.Checkout.SessionCustomFieldDropdownOptionOptions { Label = "BB cream sample", Value = "cream", }, }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ![A checkout page with a dropdown field](https://b.stripecdn.com/docs-statics-srv/assets/dropdown.4501d199ebe009030c2be6935cfdf2dd.png) ### Add a numbers only field A numbers-only field provides your customers a text field that only accepts numerical values, up to 255 digits. To create a numbers-only field, specify `type=numeric`. #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=invoice \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Invoice number" \ -d "custom_fields[0][type]"=numeric ``` ```cli stripe checkout sessions create \ --mode=payment \ --success-url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=invoice \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Invoice number" \ -d "custom_fields[0][type]"=numeric ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'invoice', label: { type: 'custom', custom: 'Invoice number', }, type: 'numeric', }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "success_url": "https://example.com/success", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "invoice", "label": {"type": "custom", "custom": "Invoice number"}, "type": "numeric", }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'success_url' => 'https://example.com/success', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'invoice', 'label' => [ 'type' => 'custom', 'custom' => 'Invoice number', ], 'type' => 'numeric', ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("invoice") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Invoice number") .build() ) .setType(SessionCreateParams.CustomField.Type.NUMERIC) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'invoice', label: { type: 'custom', custom: 'Invoice number', }, type: 'numeric', }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("invoice"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Invoice number"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeNumeric), }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", SuccessUrl = "https://example.com/success", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "invoice", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Invoice number", }, Type = "numeric", }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=invoice \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Invoice number" \ -d "custom_fields[0][type]"=numeric ``` ```cli stripe checkout sessions create \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=invoice \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Invoice number" \ -d "custom_fields[0][type]"=numeric ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'invoice', label: { type: 'custom', custom: 'Invoice number', }, type: 'numeric', }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "invoice", "label": {"type": "custom", "custom": "Invoice number"}, "type": "numeric", }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'invoice', 'label' => [ 'type' => 'custom', 'custom' => 'Invoice number', ], 'type' => 'numeric', ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("invoice") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Invoice number") .build() ) .setType(SessionCreateParams.CustomField.Type.NUMERIC) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'invoice', label: { type: 'custom', custom: 'Invoice number', }, type: 'numeric', }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("invoice"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Invoice number"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeNumeric), }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "invoice", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Invoice number", }, Type = "numeric", }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ### Retrieve custom fields for a subscription You can retrieve the custom fields associated with a subscription by querying for the Checkout Session that created it using the [subscription](https://docs.stripe.com/api/checkout/sessions/list.md#list_checkout_sessions-subscription) parameter. ```curl curl -G https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d subscription="{{SUBSCRIPTION_ID}}" ``` ```cli stripe checkout sessions list \ --subscription="{{SUBSCRIPTION_ID}}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") sessions = client.v1.checkout.sessions.list({subscription: '{{SUBSCRIPTION_ID}}'}) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. sessions = client.v1.checkout.sessions.list({ "subscription": "{{SUBSCRIPTION_ID}}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $sessions = $stripe->checkout->sessions->all([ 'subscription' => '{{SUBSCRIPTION_ID}}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionListParams params = SessionListParams.builder().setSubscription("{{SUBSCRIPTION_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. StripeCollection stripeCollection = client.v1().checkout().sessions().list(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const sessions = await stripe.checkout.sessions.list({ subscription: '{{SUBSCRIPTION_ID}}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionListParams{ Subscription: stripe.String("{{SUBSCRIPTION_ID}}"), } result := sc.V1CheckoutSessions.List(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionListOptions { Subscription = "{{SUBSCRIPTION_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; StripeList sessions = service.List(options); ``` ### Add character length validations You can optionally specify a minimum and maximum character length [requirement](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-custom_fields-numeric-maximum_length) for `text` and `numeric` field types. #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][text][minimum_length]"=10 \ -d "custom_fields[0][text][maximum_length]"=20 \ -d "custom_fields[0][optional]"=true ``` ```cli stripe checkout sessions create \ --mode=payment \ --success-url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][text][minimum_length]"=10 \ -d "custom_fields[0][text][maximum_length]"=20 \ -d "custom_fields[0][optional]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', text: { minimum_length: 10, maximum_length: 20, }, optional: true, }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "success_url": "https://example.com/success", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "engraving", "label": {"type": "custom", "custom": "Personalized engraving"}, "type": "text", "text": {"minimum_length": 10, "maximum_length": 20}, "optional": True, }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'success_url' => 'https://example.com/success', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'engraving', 'label' => [ 'type' => 'custom', 'custom' => 'Personalized engraving', ], 'type' => 'text', 'text' => [ 'minimum_length' => 10, 'maximum_length' => 20, ], 'optional' => true, ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("engraving") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Personalized engraving") .build() ) .setType(SessionCreateParams.CustomField.Type.TEXT) .setText( SessionCreateParams.CustomField.Text.builder() .setMinimumLength(10L) .setMaximumLength(20L) .build() ) .setOptional(true) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', text: { minimum_length: 10, maximum_length: 20, }, optional: true, }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("engraving"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Personalized engraving"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeText), Text: &stripe.CheckoutSessionCreateCustomFieldTextParams{ MinimumLength: stripe.Int64(10), MaximumLength: stripe.Int64(20), }, Optional: stripe.Bool(true), }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", SuccessUrl = "https://example.com/success", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "engraving", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Personalized engraving", }, Type = "text", Text = new Stripe.Checkout.SessionCustomFieldTextOptions { MinimumLength = 10, MaximumLength = 20, }, Optional = true, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][text][minimum_length]"=10 \ -d "custom_fields[0][text][maximum_length]"=20 \ -d "custom_fields[0][optional]"=true ``` ```cli stripe checkout sessions create \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][text][minimum_length]"=10 \ -d "custom_fields[0][text][maximum_length]"=20 \ -d "custom_fields[0][optional]"=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', text: { minimum_length: 10, maximum_length: 20, }, optional: true, }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "engraving", "label": {"type": "custom", "custom": "Personalized engraving"}, "type": "text", "text": {"minimum_length": 10, "maximum_length": 20}, "optional": True, }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'engraving', 'label' => [ 'type' => 'custom', 'custom' => 'Personalized engraving', ], 'type' => 'text', 'text' => [ 'minimum_length' => 10, 'maximum_length' => 20, ], 'optional' => true, ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("engraving") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Personalized engraving") .build() ) .setType(SessionCreateParams.CustomField.Type.TEXT) .setText( SessionCreateParams.CustomField.Text.builder() .setMinimumLength(10L) .setMaximumLength(20L) .build() ) .setOptional(true) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', text: { minimum_length: 10, maximum_length: 20, }, optional: true, }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("engraving"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Personalized engraving"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeText), Text: &stripe.CheckoutSessionCreateCustomFieldTextParams{ MinimumLength: stripe.Int64(10), MaximumLength: stripe.Int64(20), }, Optional: stripe.Bool(true), }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "engraving", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Personalized engraving", }, Type = "text", Text = new Stripe.Checkout.SessionCustomFieldTextOptions { MinimumLength = 10, MaximumLength = 20, }, Optional = true, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ![A field with character limits](https://b.stripecdn.com/docs-statics-srv/assets/between-validation.20431cd8e0c03a028843945d1f1ea314.png) ### Add default values You can optionally provide a default value for the [text](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-custom_fields-text-default_value), [numeric](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-custom_fields-numeric-default_value), and [dropdown](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-custom_fields-dropdown-default_value) field types. Default values are prefilled on the payment page. #### Stripe-hosted page ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][text][default_value]"=Stella \ -d "custom_fields[1][key]"=size \ -d "custom_fields[1][label][type]"=custom \ -d "custom_fields[1][label][custom]"=Size \ -d "custom_fields[1][type]"=dropdown \ -d "custom_fields[1][dropdown][default_value]"=small \ -d "custom_fields[1][dropdown][options][0][value]"=small \ -d "custom_fields[1][dropdown][options][0][label]"=Small \ -d "custom_fields[1][dropdown][options][1][value]"=large \ -d "custom_fields[1][dropdown][options][1][label]"=Large ``` ```cli stripe checkout sessions create \ --mode=payment \ --success-url="https://example.com/success" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][text][default_value]"=Stella \ -d "custom_fields[1][key]"=size \ -d "custom_fields[1][label][type]"=custom \ -d "custom_fields[1][label][custom]"=Size \ -d "custom_fields[1][type]"=dropdown \ -d "custom_fields[1][dropdown][default_value]"=small \ -d "custom_fields[1][dropdown][options][0][value]"=small \ -d "custom_fields[1][dropdown][options][0][label]"=Small \ -d "custom_fields[1][dropdown][options][1][value]"=large \ -d "custom_fields[1][dropdown][options][1][label]"=Large ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', text: {default_value: 'Stella'}, }, { key: 'size', label: { type: 'custom', custom: 'Size', }, type: 'dropdown', dropdown: { default_value: 'small', options: [ { value: 'small', label: 'Small', }, { value: 'large', label: 'Large', }, ], }, }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "success_url": "https://example.com/success", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "engraving", "label": {"type": "custom", "custom": "Personalized engraving"}, "type": "text", "text": {"default_value": "Stella"}, }, { "key": "size", "label": {"type": "custom", "custom": "Size"}, "type": "dropdown", "dropdown": { "default_value": "small", "options": [ {"value": "small", "label": "Small"}, {"value": "large", "label": "Large"}, ], }, }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'success_url' => 'https://example.com/success', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'engraving', 'label' => [ 'type' => 'custom', 'custom' => 'Personalized engraving', ], 'type' => 'text', 'text' => ['default_value' => 'Stella'], ], [ 'key' => 'size', 'label' => [ 'type' => 'custom', 'custom' => 'Size', ], 'type' => 'dropdown', 'dropdown' => [ 'default_value' => 'small', 'options' => [ [ 'value' => 'small', 'label' => 'Small', ], [ 'value' => 'large', 'label' => 'Large', ], ], ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("engraving") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Personalized engraving") .build() ) .setType(SessionCreateParams.CustomField.Type.TEXT) .setText( SessionCreateParams.CustomField.Text.builder().setDefaultValue("Stella").build() ) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("size") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Size") .build() ) .setType(SessionCreateParams.CustomField.Type.DROPDOWN) .setDropdown( SessionCreateParams.CustomField.Dropdown.builder() .setDefaultValue("small") .addOption( SessionCreateParams.CustomField.Dropdown.Option.builder() .setValue("small") .setLabel("Small") .build() ) .addOption( SessionCreateParams.CustomField.Dropdown.Option.builder() .setValue("large") .setLabel("Large") .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', success_url: 'https://example.com/success', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', text: { default_value: 'Stella', }, }, { key: 'size', label: { type: 'custom', custom: 'Size', }, type: 'dropdown', dropdown: { default_value: 'small', options: [ { value: 'small', label: 'Small', }, { value: 'large', label: 'Large', }, ], }, }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("engraving"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Personalized engraving"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeText), Text: &stripe.CheckoutSessionCreateCustomFieldTextParams{ DefaultValue: stripe.String("Stella"), }, }, &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("size"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Size"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeDropdown), Dropdown: &stripe.CheckoutSessionCreateCustomFieldDropdownParams{ DefaultValue: stripe.String("small"), Options: []*stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ &stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ Value: stripe.String("small"), Label: stripe.String("Small"), }, &stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ Value: stripe.String("large"), Label: stripe.String("Large"), }, }, }, }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", SuccessUrl = "https://example.com/success", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "engraving", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Personalized engraving", }, Type = "text", Text = new Stripe.Checkout.SessionCustomFieldTextOptions { DefaultValue = "Stella", }, }, new Stripe.Checkout.SessionCustomFieldOptions { Key = "size", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Size", }, Type = "dropdown", Dropdown = new Stripe.Checkout.SessionCustomFieldDropdownOptions { DefaultValue = "small", Options = new List { new Stripe.Checkout.SessionCustomFieldDropdownOptionOptions { Value = "small", Label = "Small", }, new Stripe.Checkout.SessionCustomFieldDropdownOptionOptions { Value = "large", Label = "Large", }, }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` #### Embedded form ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][text][default_value]"=Stella \ -d "custom_fields[1][key]"=size \ -d "custom_fields[1][label][type]"=custom \ -d "custom_fields[1][label][custom]"=Size \ -d "custom_fields[1][type]"=dropdown \ -d "custom_fields[1][dropdown][default_value]"=small \ -d "custom_fields[1][dropdown][options][0][value]"=small \ -d "custom_fields[1][dropdown][options][0][label]"=Small \ -d "custom_fields[1][dropdown][options][1][value]"=large \ -d "custom_fields[1][dropdown][options][1][label]"=Large ``` ```cli stripe checkout sessions create \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/return" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "custom_fields[0][key]"=engraving \ -d "custom_fields[0][label][type]"=custom \ -d "custom_fields[0][label][custom]"="Personalized engraving" \ -d "custom_fields[0][type]"=text \ -d "custom_fields[0][text][default_value]"=Stella \ -d "custom_fields[1][key]"=size \ -d "custom_fields[1][label][type]"=custom \ -d "custom_fields[1][label][custom]"=Size \ -d "custom_fields[1][type]"=dropdown \ -d "custom_fields[1][dropdown][default_value]"=small \ -d "custom_fields[1][dropdown][options][0][value]"=small \ -d "custom_fields[1][dropdown][options][0][label]"=Small \ -d "custom_fields[1][dropdown][options][1][value]"=large \ -d "custom_fields[1][dropdown][options][1][label]"=Large ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', text: {default_value: 'Stella'}, }, { key: 'size', label: { type: 'custom', custom: 'Size', }, type: 'dropdown', dropdown: { default_value: 'small', options: [ { value: 'small', label: 'Small', }, { value: 'large', label: 'Large', }, ], }, }, ], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/return", "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "custom_fields": [ { "key": "engraving", "label": {"type": "custom", "custom": "Personalized engraving"}, "type": "text", "text": {"default_value": "Stella"}, }, { "key": "size", "label": {"type": "custom", "custom": "Size"}, "type": "dropdown", "dropdown": { "default_value": "small", "options": [ {"value": "small", "label": "Small"}, {"value": "large", "label": "Large"}, ], }, }, ], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/return', 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'custom_fields' => [ [ 'key' => 'engraving', 'label' => [ 'type' => 'custom', 'custom' => 'Personalized engraving', ], 'type' => 'text', 'text' => ['default_value' => 'Stella'], ], [ 'key' => 'size', 'label' => [ 'type' => 'custom', 'custom' => 'Size', ], 'type' => 'dropdown', 'dropdown' => [ 'default_value' => 'small', 'options' => [ [ 'value' => 'small', 'label' => 'Small', ], [ 'value' => 'large', 'label' => 'Large', ], ], ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/return") .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("engraving") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Personalized engraving") .build() ) .setType(SessionCreateParams.CustomField.Type.TEXT) .setText( SessionCreateParams.CustomField.Text.builder().setDefaultValue("Stella").build() ) .build() ) .addCustomField( SessionCreateParams.CustomField.builder() .setKey("size") .setLabel( SessionCreateParams.CustomField.Label.builder() .setType(SessionCreateParams.CustomField.Label.Type.CUSTOM) .setCustom("Size") .build() ) .setType(SessionCreateParams.CustomField.Type.DROPDOWN) .setDropdown( SessionCreateParams.CustomField.Dropdown.builder() .setDefaultValue("small") .addOption( SessionCreateParams.CustomField.Dropdown.Option.builder() .setValue("small") .setLabel("Small") .build() ) .addOption( SessionCreateParams.CustomField.Dropdown.Option.builder() .setValue("large") .setLabel("Large") .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/return', line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], custom_fields: [ { key: 'engraving', label: { type: 'custom', custom: 'Personalized engraving', }, type: 'text', text: { default_value: 'Stella', }, }, { key: 'size', label: { type: 'custom', custom: 'Size', }, type: 'dropdown', dropdown: { default_value: 'small', options: [ { value: 'small', label: 'Small', }, { value: 'large', label: 'Large', }, ], }, }, ], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/return"), LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, CustomFields: []*stripe.CheckoutSessionCreateCustomFieldParams{ &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("engraving"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Personalized engraving"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeText), Text: &stripe.CheckoutSessionCreateCustomFieldTextParams{ DefaultValue: stripe.String("Stella"), }, }, &stripe.CheckoutSessionCreateCustomFieldParams{ Key: stripe.String("size"), Label: &stripe.CheckoutSessionCreateCustomFieldLabelParams{ Type: stripe.String("custom"), Custom: stripe.String("Size"), }, Type: stripe.String(stripe.CheckoutSessionCustomFieldTypeDropdown), Dropdown: &stripe.CheckoutSessionCreateCustomFieldDropdownParams{ DefaultValue: stripe.String("small"), Options: []*stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ &stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ Value: stripe.String("small"), Label: stripe.String("Small"), }, &stripe.CheckoutSessionCreateCustomFieldDropdownOptionParams{ Value: stripe.String("large"), Label: stripe.String("Large"), }, }, }, }, }, } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/return", LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, CustomFields = new List { new Stripe.Checkout.SessionCustomFieldOptions { Key = "engraving", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Personalized engraving", }, Type = "text", Text = new Stripe.Checkout.SessionCustomFieldTextOptions { DefaultValue = "Stella", }, }, new Stripe.Checkout.SessionCustomFieldOptions { Key = "size", Label = new Stripe.Checkout.SessionCustomFieldLabelOptions { Type = "custom", Custom = "Size", }, Type = "dropdown", Dropdown = new Stripe.Checkout.SessionCustomFieldDropdownOptions { DefaultValue = "small", Options = new List { new Stripe.Checkout.SessionCustomFieldDropdownOptionOptions { Value = "small", Label = "Small", }, new Stripe.Checkout.SessionCustomFieldDropdownOptionOptions { Value = "large", Label = "Large", }, }, }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` --- # Source: https://docs.stripe.com/use-stripe-apps/netsuite/custom-payment-application.md # Custom payment application Learn how to customize the way payments are recorded and applied using the Stripe Connector for NetSuite. To learn more and get a demo of the Stripe Connector for NetSuite, go to the [Stripe App Marketplace](https://marketplace.stripe.com/apps/netsuite-connector) and click **Install app**. The Stripe Connector for NetSuite provides a way for you to reconcile Stripe payment activity from your custom or prebuilt, third-party integration to NetSuite. Using the following tools, you can customize how the connector records and reconciles payments in NetSuite: - [Stripe metadata](https://docs.stripe.com/use-stripe-apps/netsuite/custom-payment-application.md#stripe-metadata) - [Invoices for payments](https://docs.stripe.com/use-stripe-apps/netsuite/custom-payment-application.md#invoices-payments) - [Connector add-ons](https://docs.stripe.com/use-stripe-apps/netsuite/custom-payment-application.md#connector-addons) ## Stripe metadata You can use Stripe metadata to make sure your Stripe activity is properly represented in NetSuite. ### Relate a Stripe object to a NetSuite record Add metadata to Stripe objects to relate them to existing NetSuite records. You can add this metadata at the time of syncing, before the Stripe object syncs to NetSuite, or in conjunction with controls that modify the sync timing. You can relate records in the following ways: - Add `netsuite_invoice_id: 12345` to a Stripe charge so that the connector applies the customer payment to NetSuite invoice with internal ID `12345`. - Add `netsuite_credit_memo_id: 67890` to a Stripe refund so that the connector applies the customer refund to NetSuite credit memo with internal ID `67890`. - Add `netsuite_customer_id: 101010` to a Stripe charge so that the connector creates the customer payment under NetSuite customer with internal ID `101010`. ### Override sync timing You can choose to override the default sync timing by programmatically controlling when a record syncs to NetSuite. There are two ways to override record sync timing: add records to a denylist or add records to an allowlist. #### Add records to a denylist You can add metadata to temporarily stop the connector from syncing a record to NetSuite. This is helpful if your backend integration with Stripe requires adding data to a record before syncing to NetSuite. Use a denylist to control the timing of a customer sync to NetSuite: 1. Ask your implementation partner to enable the **Denylist payments and refunds** feature in your Stripe app settings. Consult with your implementation partner to understand all accounting and technical implications. 1. Add `netsuite_block_integration: true` to the metadata of any Stripe object. 1. To allow record syncing again, replace `true` with `nil`. You can’t permanently add a payment or payment-related record to the denylist. After 2 days, the connector automatically attempts to create a bank deposit for the Stripe payout. Until you remove the payment or record from the denylist, the deposit automation fails and the payment or record can’t sync to NetSuite. #### Examples The following are examples of when you might want to use a denylist: **Example 1**: You might have a customer record that your system created when a Stripe customer started the signup process and made a prepayment. Later you collect address data for that customer. The connector typically syncs the customer and payment data to NetSuite right away; however, you can delay syncing to NetSuite until you finish collecting all data for a customer. **Example 2**: Your Stripe account includes Stripe Billing and an e-commerce app. You want to associate the payments from the e-commerce app with your NetSuite orders, and to automatically sync the subscription invoices and payments. To do so, add metadata to the payments from the e-commerce system. The connector syncs the Stripe Billing invoices and payments to NetSuite. The e-commerce payments without a Netsuite order or invoice ID won’t sync until the associated order or invoice is imported into your NetSuite account. After the order detail is added, you can remove the denylist metadata and add the NetSuite invoice ID to associate the records. #### Add records to an allowlist You can add metadata to stop the connector from syncing a record to NetSuite until it is granted permission. This is helpful if you have an e-commerce system that uses Stripe to process payments before the invoice is created in NetSuite. Use an allowlist to control the syncing of a record to NetSuite: 1. Ask your implementation partner to enable the **Allowlist payments** feature in your Stripe app settings. Consult with your implementation partner to understand all accounting and technical implications. 1. Add `netsuite_allow_integration: true` to the metadata of a record. Don’t use an allowlist if either of the following applies: - You use Stripe Billing. In most cases, Stripe automatically generates invoices, which can create challenges with making sure invoices are added to the allowlist. Instead, you can use a denylist for payments that aren’t related to Stripe Billing. - You don’t have a fully comprehensive custom system that accounts for every payment in your Stripe account. If a payment in your Stripe account isn’t synced to NetSuite, the deposit automation fails until the payment is synced. #### Override NetSuite record creation Override any part of the connector’s record syncing process by adding metadata to Stripe objects to relate them to existing NetSuite records. You can add this metadata at the time of syncing, before the Stripe object syncs to NetSuite, or in conjunction with controls that modify the sync timing. This prevents the connector from creating that record in NetSuite. For example, you have an existing system that creates customers that you want to use alongside the connector. You can pass the NetSuite customer’s internal ID to the Stripe customer to allow the connector to create a link between the two, rather than creating a new customer. You can also use the same process to link Stripe prices to existing NetSuite items. See below for the list of [metadata keys](https://docs.stripe.com/use-stripe-apps/netsuite/custom-payment-application.md#metadata-keys) to link records and override record creation. If you use the [price matching setting](https://docs.stripe.com/use-stripe-apps/netsuite/stripe-prices-coupons-netsuite.md#how-netsuite-represents-products-and-prices), this overrides the method of adding the `netsuite_service_sale_item_id` metadata key to the price object. > Overriding any part of the connector’s record syncing process that affects accounts receivable might introduce accounting inaccuracies. Our system guarantees that the created records are accurate, but can’t guarantee the accuracy of records created by another system. ### Connector metadata keys The connector uses metadata keys to link Stripe objects to existing NetSuite records. You can add this metadata at the time of syncing, before the Stripe object syncs to NetSuite, or in conjunction with controls that modify the sync timing. | Stripe record | Stripe metadata key | NetSuite record | | -------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | Customer | `netsuite_customer_id` | Customer | | Invoice | `netsuite_invoice_id` | Invoice | | Price | `netsuite_service_sale_item_id` | Service Sale Item If unspecified, this is the default item type that the connector uses to create new items. | | Price | `netsuite_service_resale_item_id` | Service Resale Item You can use this item type in place of a Service Sale Item. | | Price | `netsuite_non_inventory_sale_item_id` | Non Inventory Sale Item You can use this item type in place of a Service Sale Item. | | Price | `netsuite_non_inventory_resale_item_id` | Non Inventory Resale Item You can use this item type in place of a Service Sale Item. | | Price | `netsuite_discount_item_id` | Discount Item Only applicable if the line item amount is negative. | | Invoice Line Item | `netsuite_discount_item_id` | Discount Item Only applicable if the line item amount is negative. | | Coupon | `netsuite_discount_item_id` | Discount Item | | Charge | `netsuite_customer_payment_id` | Customer Payment | | Charge | `netsuite_customer_deposit_id` | Customer Deposit | | Refund | `netsuite_customer_refund_id` | Customer Refund | | Refund | `netsuite_credit_memo_id` | Credit Memo Only applicable if the refund’s charge is linked to a Stripe-created invoice. | | Dispute (chargeback) | `netsuite_customer_refund_id` | Customer Refund | | Payout | `netsuite_deposit_id` | Deposit | ## Invoices for payments If your system uses Stripe to process payments and it creates a payment in Stripe that isn’t associated with an invoice, you can choose to allow the connector to create an invoice using information from the charge. The connector then applies a customer payment to represent revenue and cash for that transaction. This workflow doesn’t support discounts, multiple line items, and other complex integrations. ### How it works 1. The connector creates a NetSuite invoice for each charge in Stripe and includes the charge description in a memo on the invoice. You can choose to add data from the Stripe metadata fields to the invoice by using field mappings. 1. The invoice uses a single line item to represent the revenue earned by the entire Stripe charge. By default, all payments on the Stripe account use the same NetSuite item. You can customize this. 1. The connector creates a payment and applies it to the invoice. The payment is automatically reconciled to a bank deposit and fees are recorded. 1. Refunds and disputes automatically represent as a credit memo and refund. ### Customize the NetSuite line item All invoices generated from charges use the same NetSuite item (Stripe Generic Line Item), by default. If charges are used to purchase multiple types of products in your app, you need to record the revenue for the different products against unique NetSuite items. This allows you to have detailed reports in NetSuite based on revenue by item, quantity of items sold, and more. You can’t have multiple line items on an invoice from charges. The connector can’t distribute the revenue across separate items from the metadata information on the Stripe charge. If you need to use multiple line items on your NetSuite invoice, you can use a Stripe invoice to sync line-item details. You can use metadata or a standard field on the Stripe charge to select a NetSuite item. The connector uses the Stripe metadata or field to search for a field on the NetSuite item. If the connector doesn’t find a match, it uses the Stripe Generic Line Item. Matches aren’t case sensitive. For example, you create a Stripe charge and add the `product_name` metadata that includes the name of a NetSuite item. The connector searches for an item in NetSuite that matches the `product_name` in Stripe. If the connector finds a match, it uses that item on the invoice created for that charge. Use invoices for payments flow: 1. Ask your implementation partner to enable the **Create invoices for payments** feature in your Stripe app settings. Consult with your implementation partner to understand all accounting and technical implications. 1. Add the following for the connector to use for matching: - Add a NetSuite field on the item record - Add the corresponding Stripe field on the `Charge` object For example, you can add a metadata key on a Stripe charge and `itemid` or `displayName` on the NetSuite item. ## Connector add-ons [Contact us](http://stripe.com/sales) to learn more or to get started with connector add-ons. The connector provides NetSuite add-ons (bundles) to support common use cases and allow seamless operation with core workflows. You can work with an official implementation partner to customize your integration with these add-ons, which live exclusively in NetSuite. You can customize the add-ons by developing new workflows on top of them, or modifying existing workflows to support your business needs. For example, you might want to align the payment and reconciliation processes with your unique NetSuite setup, while still using core connector automations. ### Autopay add-on Use the Autopay add-on to automatically bill your customer’s saved payment method and pay open invoices in NetSuite. You can modify the billing details, such as cadence and parameters, to make sure the correct invoices are billed. ### NetSuite Initiated Refunds add-on Use the NetSuite Initiated Refunds add-on to trigger [Stripe refunds](https://docs.stripe.com/use-stripe-apps/netsuite/stripe-refunds-netsuite.md) from NetSuite, instead of the Stripe Dashboard or API. NetSuite records are linked or created automatically in multiple scenarios to fully represent the Stripe refund. ### Payment Linker add-on If you integrate Stripe with a third-party service, such as an e-commerce site, you can use the Payment Linker add-on to automatically sync Stripe payments as customer deposits applied to NetSuite sales orders, or payments applied to NetSuite invoices. Stripe supports total upfront capture or auth-capture flows. ## See also - [Fields and references](https://docs.stripe.com/use-stripe-apps/netsuite/fields-references.md) - [Field mappings](https://docs.stripe.com/use-stripe-apps/netsuite/field-mappings.md) - [Sync data](https://docs.stripe.com/use-stripe-apps/netsuite/sync-data.md) --- # Source: https://docs.stripe.com/payments/payment-methods/custom-payment-methods.md # Custom payment methods Extend your integrations with additional payment methods processed outside of Stripe. Custom payment methods allow you to extend your payment and billing integrations with payment methods processed outside of Stripe. For a list of payment methods offered by Stripe, see the [payment method overview page](https://docs.stripe.com/payments/payment-methods/overview.md). While you process custom payment method transactions outside of Stripe, you can still [record the transaction details](https://docs.stripe.com/api/payment-record/report-payment/report.md) to your Stripe account to unify reporting and build back office workflows. ## Configure custom payment method types In the Dashboard, create the custom payment method type your customers will pay with. Custom payment method types allow you to specify branding for the custom payment methods you define for each customer. For example, if you’re using `SamplePay` as another processor, you might want to create a `SamplePayCard` to represent cards that you process with `SamplePay`. Go to [Custom payment method types](https://dashboard.stripe.com/settings/custom_payment_methods) in the Dashboard. At the end of these steps, you’ll have one or more custom payment method types defined that you can offer your customers when they checkout. 1. Create a custom payment method type. 1. Set the display name and logo for the custom payment method type. Alternatively, use one of over 50 preset methods for common payment methods processed outside of Stripe. > Set your own display name and logo if you use a custom front end or want the logo to display when interacting with the custom payment method through the [Payment Methods API](https://docs.stripe.com/api/payment_methods.md). A preset is suitable if you rely on Payment Element to render the custom payment method. > Make sure your custom payment method display name and logo align with our [marks policy](https://docs.stripe.com/payments/payment-methods/custom-payment-methods.md#marks-requirements). 1. Click **Create** to make a new payment method type, `SamplePayCard`, which you can then use to set up a custom payment method. 1. You can see the created custom payment method type details in the Dashboard. 1. Custom payment method types aren’t retrievable through the API. We recommend storing the ID in your database and retrieving it during payment method creation. ### Payment Methods Create and retrieve custom payment methods with the [Payment Methods API](https://docs.stripe.com/api/payment_methods.md). When creating them, pass the ID of the custom payment method type you configured in the Stripe Dashboard as `custom[type]`. ```curl curl https://api.stripe.com/v1/payment_methods \ -u "<>:" \ -d type=custom \ -d "custom[type]"={{CUSTOM_PAYMENT_METHOD_TYPE_ID}} ``` ```cli stripe payment_methods create \ --type=custom \ -d "custom[type]"={{CUSTOM_PAYMENT_METHOD_TYPE_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_method = client.v1.payment_methods.create({ type: 'custom', custom: {type: '{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_method = client.v1.payment_methods.create({ "type": "custom", "custom": {"type": "{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentMethod = $stripe->paymentMethods->create([ 'type' => 'custom', 'custom' => ['type' => '{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentMethodCreateParams params = PaymentMethodCreateParams.builder() .setType(PaymentMethodCreateParams.Type.CUSTOM) .setCustom( PaymentMethodCreateParams.Custom.builder() .setType("{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}") .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentMethod paymentMethod = client.v1().paymentMethods().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentMethod = await stripe.paymentMethods.create({ type: 'custom', custom: { type: '{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentMethodCreateParams{ Type: stripe.String(stripe.PaymentMethodTypeCustom), Custom: &stripe.PaymentMethodCreateCustomParams{ Type: stripe.String("{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}"), }, } result, err := sc.V1PaymentMethods.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentMethodCreateOptions { Type = "custom" }; options.AddExtraParam("custom[type]", "{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}"); var client = new StripeClient("<>"); var service = client.V1.PaymentMethods; PaymentMethod paymentMethod = service.Create(options); ``` ```json { "id": "pm_123456789", "object": "payment_method", "billing_details": { "address": {...}, "email": "jenny@example.com", "name": "Jenny Rosen", "phone": "+335555555555" },"custom": { "display_name": "SamplePayCard", "logo": { "content_type": "image/jpeg", "url": "https://files.stripe.com/files/..." }, "type": "cpmt_..." }, "type": "custom", (...) } ``` ## Integrations | Payment method | Connect | Checkout | Payment Links | Payment Element | Express Checkout Element | Mobile Payment Element | Subscriptions | Invoicing | Customer Portal | | ---------------------- | ----------- | ------------- | ------------- | --------------- | ------------------------ | ---------------------- | ------------- | ----------- | --------------- | | Custom payment methods | ✓ Supported | - Unsupported | - Unsupported | ✓ Supported 1 | - Unsupported | ✓ Supported 1 | ✓ Supported | ✓ Supported | ✓ Supported | 1 Not compatible with the [Checkout Sessions API](https://docs.stripe.com/api/checkout/sessions.md) ### Payment Element The Payment Element can display custom payment methods so you can provide your customers with unified checkout. See [Custom payment methods in Payment Element](https://docs.stripe.com/payments/payment-element/custom-payment-methods.md) to learn more. ### Subscription Billing Integrate Stripe Billing with your third-party payment service processors to create subscriptions that automatically charge payment methods not stored on Stripe, manage subscription states, and track payment success for external payments. See [Integrate with third-party payment processors](https://docs.stripe.com/billing/subscriptions/third-party-payment-processing.md) to learn more. ### Connect Your platform account can create custom payment methods in its connected accounts using its own custom payment method types, as well as the connected account’s custom payment method types. ```curl curl https://api.stripe.com/v1/payment_methods \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d type=custom \ -d "custom[type]"={{CUSTOM_PAYMENT_METHOD_TYPE_ID}} ``` ```cli stripe payment_methods create \ --stripe-account {{CONNECTEDACCOUNT_ID}} \ --type=custom \ -d "custom[type]"={{CUSTOM_PAYMENT_METHOD_TYPE_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_method = client.v1.payment_methods.create( { type: 'custom', custom: {type: '{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}'}, }, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_method = client.v1.payment_methods.create( {"type": "custom", "custom": {"type": "{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}"}}, {"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentMethod = $stripe->paymentMethods->create( [ 'type' => 'custom', 'custom' => ['type' => '{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}'], ], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentMethodCreateParams params = PaymentMethodCreateParams.builder() .setType(PaymentMethodCreateParams.Type.CUSTOM) .setCustom( PaymentMethodCreateParams.Custom.builder() .setType("{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}") .build() ) .build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentMethod paymentMethod = client.v1().paymentMethods().create(params, requestOptions); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentMethod = await stripe.paymentMethods.create( { type: 'custom', custom: { type: '{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}', }, }, { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentMethodCreateParams{ Type: stripe.String(stripe.PaymentMethodTypeCustom), Custom: &stripe.PaymentMethodCreateCustomParams{ Type: stripe.String("{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}"), }, } params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result, err := sc.V1PaymentMethods.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentMethodCreateOptions { Type = "custom" }; options.AddExtraParam("custom[type]", "{{CUSTOM_PAYMENT_METHOD_TYPE_ID}}"); var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.PaymentMethods; PaymentMethod paymentMethod = service.Create(options, requestOptions); ``` ## Compliance ### Ongoing availability of custom payment methods and PSP integrations Stripe might at any time decide to remove or block the availability of any payment method as a custom payment method (for example, if required to do so by a governmental authority). Stripe notifies you of any removal of a custom payment method that you’re using, and you must immediately remove the custom payment method in your code. Failure to do so results in the custom payment method not rendering to your customers. ### Restricted custom payment methods The following payment methods or types of payment methods are prohibited from being used with custom payment methods and third-party payment processors: - In Indonesia and Thailand: - The [crypto payment methods](https://market.sec.or.th/public/idisc/th/Viewmore/invalert-head?LicenseType=03&PublicFlag=Y) provided by the operators - Any other crypto-related payment methods ### Marks requirements The use of name, logo, icon, design element or anything else that can identify a payment method (“Marks”) must adhere to the following guidance: - Follow any Marks guidelines of that payment method provider (for example, [terms](https://stripe.com/legal/marks) for use of Stripe Marks). - Don’t alter or modify the payment method Marks, unless you have permission to do so. - Don’t use the payment method Marks in violation of your obligations to that payment method provider. - Don’t use Marks of one payment method provider for another payment method provider. - Don’t use methods, devices or designs to obfuscate or mislead as to the true underlying payment method. - Don’t use the payment method Marks in violation of any laws or regulations. ### Disclaimer By using custom payment methods (CPM) and [third-party payment processors](https://docs.stripe.com/billing/subscriptions/third-party-payment-processing.md), you acknowledge that: - The third-party payment services provider (PSP) provides operation and support of CPMs and your third-party payment processors integration. - Your chosen PSP complies with applicable laws, including anti-money laundering (AML) and sanctions laws. - You’re responsible for maintaining a direct integration with the PSP. - You must maintain an agreement with the PSP and must comply with your agreements with each PSP. - You’re responsible for obtaining all necessary [rights to use the PSP’s marks and logos](https://docs.stripe.com/payments/payment-methods/custom-payment-methods.md#marks-requirements) within your checkout. - Stripe isn’t responsible for the processing of any transactions with any PSP including, for example, any charges, refunds, disputes, settlements, or funds flows. - You or the PSP are responsible for the completion of the purchase flow after a customer has selected a CPM, including, for example, the order confirmation and reconciliation of orders. - You’re responsible for properly configuring the CPM and third-party payment processor integration, which might include configuring a redirect URL. - You must immediately remove any CPM and disable your PSP integration in the event your agreement with any PSP terminates or Stripe, at its sole discretion, gives you notices or documents its [prohibition of use of that type of custom payment method](https://docs.stripe.com/payments/payment-methods/custom-payment-methods.md#restricted-custom-payment-methods). - You can’t integrate with [restricted PSPs](https://docs.stripe.com/payments/payment-methods/custom-payment-methods.md#restricted-custom-payment-methods). - You’re solely responsible for correctly presenting buyers with their chosen CPM. - You won’t misrepresent that Stripe processes payments for the CPMs you present to your customers. - As a third-party payment processor user, you’ve obtained the requisite permission to enable Stripe to collect, use, retain, and disclose the data provided through the integration (“PSP Data”). - You authorize Stripe to access and use the PSP Data to provide and update the Stripe services, comply with legal and financial partner requirements, and prevent and mitigate fraud, financial loss, and other harm. - To the extent permitted by law, upon Stripe’s written request, you agree to provide Stripe with information about transactions with PSPs using the services so that Stripe can comply with any investigations, administrative inquiries, legal requirements, audits, and demands or inquiries from consumers, businesses, or PSPs. > Consult with legal counsel to confirm what additional requirements specific to your business you might need to comply with before using these services. --- # Source: https://docs.stripe.com/payments/checkout/custom-shipping-options.md # Dynamically customize shipping options Update shipping options based on a customer's shipping address. Learn how to dynamically update shipping options based on the address that your customer enters when you use the embedded version of Checkout. Dynamic updates aren’t available with the Stripe-hosted version of Checkout. ### Use cases - **Validate an address**: Confirm whether you can ship a product to a customer’s address using your own custom validation rules. You can also create a custom UI for customers to confirm their preferred address. - **Show relevant shipping options**: Display only available shipping methods, based on the customer’s address. For example, show overnight shipping only for deliveries in your country. - **Dynamically calculate shipping rates**: Calculate and display shipping fees based on a customer’s delivery address. - **Update shipping rates based on order total**: Offer shipping rates based on the shipping address or order total, such as free shipping for orders over 100 USD. For checkouts allowing quantity changes or cross-sells, see [Dynamically updating line items](https://docs.stripe.com/payments/checkout/dynamically-update-line-items.md). ### Limitations - Only supported in [payment mode](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-mode). [Shipping rates](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-shipping_options) aren’t available in subscription mode. - Doesn’t support updates in response to changes from outside of the checkout page. ## Create a Checkout Session [Server-side] From your server, create a *Checkout Session* (A Checkout Session represents your customer's session as they pay for one-time purchases or subscriptions through Checkout. After a successful payment, the Checkout Session contains a reference to the Customer, and either the successful PaymentIntent or an active Subscription). - Set the [ui_mode](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-ui_mode) to `embedded`. - Set the [permissions.update_shipping_details](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-permissions-update_shipping_details) to `server_only`. - Set the [shipping_address_collection.allowed_countries](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-shipping_address_collection-allowed_countries) to the list of countries you want to offer shipping to. - Set the [shipping_options.shipping_rate_data](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-shipping_options-shipping_rate_data) that creates a dummy shipping rate with a 0 USD shipping amount. By default, the Stripe Checkout client automatically updates the [shipping_details](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-collected_information-shipping_details) of the [Checkout Session](https://docs.stripe.com/api/checkout/sessions/object.md) object with the shipping information the customer enters, including the customer’s [name](https://docs.stripe.com/api/checkout/sessions/update.md#update_checkout_session-collected_information-shipping_details-name) and [address](https://docs.stripe.com/api/checkout/sessions/update.md#update_checkout_session-collected_information-shipping_details-address). > When [permissions.update_shipping_details](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-permissions-update_shipping_details) is `server_only`, it disables the automatic client-side update and only your server can update the shipping details using your Stripe secret key. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d ui_mode=embedded \ -d "permissions[update_shipping_details]"=server_only \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_options[0][shipping_rate_data][display_name]"="Dummy shipping" \ -d "shipping_options[0][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[0][shipping_rate_data][fixed_amount][amount]"=0 \ -d "shipping_options[0][shipping_rate_data][fixed_amount][currency]"=usd \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode return_url="https://example.com/return" ``` ```cli stripe checkout sessions create \ --ui-mode=embedded \ -d "permissions[update_shipping_details]"=server_only \ -d "shipping_address_collection[allowed_countries][0]"=US \ -d "shipping_options[0][shipping_rate_data][display_name]"="Dummy shipping" \ -d "shipping_options[0][shipping_rate_data][type]"=fixed_amount \ -d "shipping_options[0][shipping_rate_data][fixed_amount][amount]"=0 \ -d "shipping_options[0][shipping_rate_data][fixed_amount][currency]"=usd \ -d "line_items[0][price]"={{PRICE_ID}} \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --return-url="https://example.com/return" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ ui_mode: 'embedded', permissions: {update_shipping_details: 'server_only'}, shipping_address_collection: {allowed_countries: ['US']}, shipping_options: [ { shipping_rate_data: { display_name: 'Dummy shipping', type: 'fixed_amount', fixed_amount: { amount: 0, currency: 'usd', }, }, }, ], line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', return_url: 'https://example.com/return', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "ui_mode": "embedded", "permissions": {"update_shipping_details": "server_only"}, "shipping_address_collection": {"allowed_countries": ["US"]}, "shipping_options": [ { "shipping_rate_data": { "display_name": "Dummy shipping", "type": "fixed_amount", "fixed_amount": {"amount": 0, "currency": "usd"}, }, }, ], "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "mode": "payment", "return_url": "https://example.com/return", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'ui_mode' => 'embedded', 'permissions' => ['update_shipping_details' => 'server_only'], 'shipping_address_collection' => ['allowed_countries' => ['US']], 'shipping_options' => [ [ 'shipping_rate_data' => [ 'display_name' => 'Dummy shipping', 'type' => 'fixed_amount', 'fixed_amount' => [ 'amount' => 0, 'currency' => 'usd', ], ], ], ], 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'mode' => 'payment', 'return_url' => 'https://example.com/return', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setPermissions( SessionCreateParams.Permissions.builder() .setUpdateShippingDetails( SessionCreateParams.Permissions.UpdateShippingDetails.SERVER_ONLY ) .build() ) .setShippingAddressCollection( SessionCreateParams.ShippingAddressCollection.builder() .addAllowedCountry( SessionCreateParams.ShippingAddressCollection.AllowedCountry.US ) .build() ) .addShippingOption( SessionCreateParams.ShippingOption.builder() .setShippingRateData( SessionCreateParams.ShippingOption.ShippingRateData.builder() .setDisplayName("Dummy shipping") .setType( SessionCreateParams.ShippingOption.ShippingRateData.Type.FIXED_AMOUNT ) .setFixedAmount( SessionCreateParams.ShippingOption.ShippingRateData.FixedAmount.builder() .setAmount(0L) .setCurrency("usd") .build() ) .build() ) .build() ) .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setReturnUrl("https://example.com/return") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ ui_mode: 'embedded', permissions: { update_shipping_details: 'server_only', }, shipping_address_collection: { allowed_countries: ['US'], }, shipping_options: [ { shipping_rate_data: { display_name: 'Dummy shipping', type: 'fixed_amount', fixed_amount: { amount: 0, currency: 'usd', }, }, }, ], line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], mode: 'payment', return_url: 'https://example.com/return', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), Permissions: &stripe.CheckoutSessionCreatePermissionsParams{ UpdateShippingDetails: stripe.String(stripe.CheckoutSessionPermissionsUpdateShippingDetailsServerOnly), }, ShippingAddressCollection: &stripe.CheckoutSessionCreateShippingAddressCollectionParams{ AllowedCountries: []*string{stripe.String("US")}, }, ShippingOptions: []*stripe.CheckoutSessionCreateShippingOptionParams{ &stripe.CheckoutSessionCreateShippingOptionParams{ ShippingRateData: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataParams{ DisplayName: stripe.String("Dummy shipping"), Type: stripe.String("fixed_amount"), FixedAmount: &stripe.CheckoutSessionCreateShippingOptionShippingRateDataFixedAmountParams{ Amount: stripe.Int64(0), Currency: stripe.String(stripe.CurrencyUSD), }, }, }, }, LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), ReturnURL: stripe.String("https://example.com/return"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { UiMode = "embedded", Permissions = new Stripe.Checkout.SessionPermissionsOptions { UpdateShippingDetails = "server_only", }, ShippingAddressCollection = new Stripe.Checkout.SessionShippingAddressCollectionOptions { AllowedCountries = new List { "US" }, }, ShippingOptions = new List { new Stripe.Checkout.SessionShippingOptionOptions { ShippingRateData = new Stripe.Checkout.SessionShippingOptionShippingRateDataOptions { DisplayName = "Dummy shipping", Type = "fixed_amount", FixedAmount = new Stripe.Checkout.SessionShippingOptionShippingRateDataFixedAmountOptions { Amount = 0, Currency = "usd", }, }, }, }, LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Mode = "payment", ReturnUrl = "https://example.com/return", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Customize shipping options [Server-side] From your server, create a new endpoint to calculate the shipping options based on the customer’s shipping address. 1. [Retrieve](https://docs.stripe.com/api/checkout/sessions/retrieve.md) the [Checkout Session](https://docs.stripe.com/api/checkout/sessions/object.md) using the `checkoutSessionId` from the request body. 1. Validate the customer’s shipping details from the request body. 1. Calculate the shipping options based on the customer’s shipping address and the [Checkout Session](https://docs.stripe.com/api/checkout/sessions/object.md)’s line items. 1. [Update](https://docs.stripe.com/api/checkout/sessions/update.md) the [Checkout Session](https://docs.stripe.com/api/checkout/sessions/object.md) with the customer’s [shipping_details](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-collected_information-shipping_details) and the [shipping_options](https://docs.stripe.com/api/checkout/sessions/update.md#update_checkout_session-shipping_options). #### Ruby ```ruby require 'sinatra' require 'json' require 'stripe' set :port, 4242 # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = "<>" # Return a boolean indicating whether the shipping details are valid def validate_shipping_details(shipping_details) # TODO: Remove error and implement... raise NotImplementedError.new(<<~MSG) Validate the shipping details the customer has entered. MSG end # Return an array of the updated shipping options or the original options if no update is needed def calculate_shipping_options(shipping_details, session) # TODO: Remove error and implement... raise NotImplementedError.new(<<~MSG) Calculate shipping options based on the customer's shipping details and the Checkout Session's line items. MSG end post '/calculate-shipping-options' do content_type :json request.body.rewind request_data = JSON.parse(request.body.read) checkout_session_id = request_data['checkout_session_id'] shipping_details = request_data['shipping_details'] # 1. Retrieve the Checkout Session session = Stripe::Checkout::Session.retrieve(checkout_session_id) # 2. Validate the shipping details if !validate_shipping_details(shipping_details) return { type: 'error', message: "We can't ship to your address. Please choose a different address." }.to_json end # 3. Calculate the shipping options shipping_options = calculate_shipping_options(shipping_details, session) # 4. Update the Checkout Session with the customer's shipping details and shipping options if shipping_options Stripe::Checkout::Session.update(checkout_session_id, { collected_information: { shipping_details: shipping_details }, shipping_options: shipping_options }) return { type: 'object', value: { succeeded: true } }.to_json else return { type: 'error', message: "We can't find shipping options. Please try again." }.to_json end end ``` #### Python ```python from flask import Flask, request, jsonify import stripe app = Flask(__name__) # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' # Return a boolean indicating whether the shipping details are valid def validate_shipping_details(shipping_details): # TODO: Remove error and implement... raise ValueError("Validate the shipping details the customer has entered.") # Return an array of the updated shipping options or the original options if no update is needed def calculate_shipping_options(shipping_details, session): # TODO: Remove error and implement... raise ValueError("Calculate shipping options based on the customer's shipping details and the Checkout Session's line items.") @app.route('/calculate-shipping-options', methods=['POST']) def calculate_shipping_options_route(): request_data = request.get_json() checkout_session_id = request_data.get('checkout_session_id') shipping_details = request_data.get('shipping_details') # 1. Retrieve the Checkout Session session = stripe.checkout.Session.retrieve(checkout_session_id) # 2. Validate the shipping details if !validate_shipping_details(shipping_details) return jsonify({'type': 'error', 'message': 'We can't ship to your address. Please choose a different address.'}), 400 # 3. Calculate the shipping options shipping_options = calculate_shipping_options(shipping_details, session) # 4. Update the Checkout Session with the customer's shipping details and shipping options if shipping_options: stripe.checkout.Session.modify( checkout_session_id, collected_information={'shipping_details': shipping_details}, shipping_options=shipping_options ) return jsonify({'type': 'object', 'value': {'succeeded': True}}) return jsonify({'type': 'error', 'message': "We can't find shipping options. Please try again."}), 400 if __name__ == '__main__': app.run(port=4242) ``` #### PHP ```php >'); # Return a boolean indicating whether the shipping details are valid function validateShippingDetails($shippingDetails) { # TODO: Remove error and implement... throw new Exception("Validate the shipping details the customer has entered."); } # Return an array of the updated shipping options or the original options if no update is needed function calculateShippingOptions($shippingDetails, $session) { # TODO: Remove error and implement... throw new Exception("Calculate shipping options based on the customer's shipping details and the Checkout Session's line items."); } // Handle the POST request if ($_SERVER['REQUEST_METHOD'] === 'POST') { header('Content-Type: application/json'); $request_data = json_decode(file_get_contents('php://input'), true); $checkoutSessionId = $request_data['checkout_session_id']; $shippingDetails = $request_data['shipping_details']; try { // 1. Retrieve the Checkout Session $session = $stripe->checkout->sessions->retrieve($checkoutSessionId); // 2. Validate the shipping details if (!validateShippingDetails($shippingDetails)) { echo json_encode(['type' => 'error', 'message' => "We can't ship to your address. Please choose a different address."]); exit; } // 3. Calculate the shipping options $shippingOptions = calculateShippingOptions($shippingDetails, $session); // 4. Update the Checkout Session with the customer's shipping details and shipping options if ($shippingOptions) { $stripe->checkout->sessions->update($checkoutSessionId, [ 'collected_information' => ['shipping_details' => $shippingDetails], 'shipping_options' => $shippingOptions, ]); echo json_encode(['type' => 'object', 'value' => ['succeeded' => true]]); exit; } else { echo json_encode(['type' => 'error', 'message' => "We can't find shipping options. Please try again."]); exit; } } catch (Exception $e) { echo json_encode(['type' => 'error', 'message' => 'We can't ship to your address. Please choose a different address.']); exit; } } ?> ``` #### Node.js ```javascript const express = require('express'); const app = express(); // Return a boolean indicating whether the shipping details are valid. function validateShippingDetails(shippingDetails) { // TODO: Remove error and implement... throw new Error(` Validate the shipping details the customer has entered. `); } // Return an array of the updated shipping options or the original options if no update is needed. function calculateShippingOptions(shippingDetails, session) { // TODO: Remove error and implement... throw new Error(` Calculate shipping options based on the customer's shipping details and the Checkout Session's line items. `); } app.post('/calculate-shipping-options', async (req, res) => { const {checkout_session_id, shipping_details} = req.body; // 1. Retrieve the Checkout Session const session = await stripe.checkout.sessions.retrieve(checkout_session_id); // 2. Validate the shipping details if (!validateShippingDetails(shipping_details)) { return res.json({type: 'error', message: 'We can't ship to your address. Please choose a different address.'}); } // 3. Calculate the shipping options const shippingOptions = calculateShippingOptions(shipping_details, session); // 4. Update the Checkout Session with the customer's shipping details and shipping options if (shippingOptions) { await stripe.checkout.sessions.update(checkout_session_id, { collected_information: {shipping_details}, shipping_options: shippingOptions, }); return res.json({type:'object', value: {succeeded: true}}); } else { return res.json({type:'error', message: "We can't find shipping options. Please try again."}); } }); app.listen(4242, () => { console.log('Running on port 4242'); }); ``` #### .NET ```dotnet using System; using System.IO; using Microsoft.AspNetCore.Mvc; using Stripe; // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; [Route("calculate-shipping-options")] [ApiController] public class ShippingController : ControllerBase { [HttpPost] public async Task HandleShippingOptions([FromBody] ShippingRequest request) { try { // 1. Retrieve the Checkout Session var service = new Stripe.Checkout.SessionService(); var session = service.Get(request.CheckoutSessionId); // 2. Validate the shipping details if (!ValidateShippingDetails(request.ShippingDetails)) { return BadRequest(new { type = "error", message = "We can't ship to your address. Please choose a different address." }); } // 3. Calculate shipping options (placeholder) var shippingOptions = CalculateShippingOptions(request.ShippingDetails, session); // 4. Update the Checkout Session with the customer's shipping details if (shippingOptions != null) { var updateOptions = new Stripe.Checkout.SessionUpdateOptions { CollectedInformation = new SessionCollectedInformationOptions { ShippingDetails = request.ShippingDetails }, ShippingOptions = shippingOptions }; service.Update(request.CheckoutSessionId, updateOptions); return Ok(new { type = "object", value = new { succeeded = true } }); } else { return BadRequest(new { type = "error", message = "We can't find shipping options. Please try again." }); } } catch (Exception) { return BadRequest(new { type = "error", message = "We can't ship to your address. Please choose a different address." }); } } // Return a boolean indicating whether the shipping details are valid. private bool ValidateShippingDetails(Dictionary shippingDetails) { // TODO: Remove error and implement... throw new NotImplementedException("Validate the shipping details the customer has entered.") } // Return an array of the updated shipping options or the original options if no update is needed. private List CalculateShippingOptions(Dictionary shippingDetails, Session session) { // TODO: Remove error and implement... throw new NotImplementedException("Calculate shipping options based on the customer's shipping details and the Checkout Session's line items."); } } ``` #### Go ```go package main import ( "encoding/json" "fmt" "net/http" "os" "github.com/stripe/stripe-go/v81.2.0-beta.1" "github.com/stripe/stripe-go/v81.2.0-beta.1/checkout/sessions" ) type UpdateShippingRequest struct { CheckoutSessionID string `json:"checkout_session_id"` ShippingDetails ShippingDetails `json:"shipping_details"` } // Address represents a postal address with JSON tags. type Address struct { Line1 string `json:"line1"` Line2 string `json:"line2"` City string `json:"city"` State string `json:"state"` PostalCode string `json:"postal_code"` Country string `json:"country"` } type ShippingDetails struct { Name string `json:"name"` Address Address `json:"address"` } // Return a boolean indicating whether the shipping details are valid func validateShippingDetails(shippingDetails ShippingDetails) error { // TODO: Remove error and implement... panic(fmt.Errorf("validate the shipping details the customer has entered")) } // Return an array of the updated shipping options or the original options if no update is needed func calculateShippingOptions(shippingDetails ShippingDetails, session *stripe.CheckoutSession) ([]*stripe.CheckoutSessionShippingOptionParams, error) { // TODO: Remove error and implement... panic(nil, fmt.Errorf("calculate shipping options based on the customer's shipping details and the Checkout Session's line items")) } func calculateShippingOptionsHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) return } var requestData UpdateShippingRquest if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil { http.Error(w, "Invalid request payload", http.StatusBadRequest) return } // 1. Retrieve the Checkout Session session, err := checkout.Get(requestData.CheckoutSessionID) if err != nil { http.Error(w, "Error retrieving checkout session", http.StatusInternalServerError) return } // 2. Validate the shipping details if err := validateShippingDetails(requestData.ShippingDetails); err != nil { response := map[string]string{ "type": "error", "message": "We can't ship to your address. Please choose a different address.", } json.NewEncoder(w).Encode(response) return } // 3. Calculate the shipping options shippingOptions, err := calculateShippingOptions(requestData.ShippingDetails, session) if err != nil { response := map[string]string{ "type": "error", "message": "We can't find shipping options. Please try again.", } json.NewEncoder(w).Encode(response) return } // 4. Update the Checkout Session with the customer's shipping details and shipping options if shippingOptions != nil { _, err := checkout.Update(requestData.CheckoutSessionID, &stripe.CheckoutSessionParams{ CollectedInformation: &stripe.CheckoutSessionCollectedInformationParams{ ShippingDetails: requestData.ShippingDetails, }, ShippingOptions: shippingOptions, }) if err != nil { http.Error(w, "Error updating checkout session", http.StatusInternalServerError) return } response := map[string]interface{}{ "type": "object", "value": map[string]bool{"succeeded": true}, } json.NewEncoder(w).Encode(response) return } response := map[string]string{ "type": "error", "message": "We can't find shipping options. Please try again.", } json.NewEncoder(w).Encode(response) } func main() { // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" http.HandleFunc("/calculate-shipping-options", calculateShippingOptionsHandler) fmt.Println("Server starting on port 4242...") http.ListenAndServe(":4242", nil) } ``` #### Java ```java import com.stripe.Stripe; import com.stripe.model.checkout.Session; import com.stripe.param.checkout.SessionRetrieveParams; import com.stripe.param.checkout.SessionUpdateParams; import org.springframework.web.bind.annotation.*; import org.springframework.http.ResponseEntity; import java.util.List; import java.util.Map; @RestController @RequestMapping("/calculate-shipping-options") public class ShippingController { static { // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; } @PostMapping public ResponseEntity> calculateShippingOptions(@RequestBody Map request) { String checkoutSessionId = (String) request.get("checkout_session_id"); Map shippingDetails = (Map) request.get("shipping_details"); // 1. Retrieve the Checkout Session Session session = Session.retrieve(checkoutSessionId); // 2. Validate the shipping details if (!validateShippingDetails(shippingDetails)) { return ResponseEntity.badRequest().request(Map.of("type", "error", "message", "We can't ship to your address. Please choose a different address.")); } // 3. Calculate shipping options List shippingOptions = calculateShippingOptions(shippingDetails, session); // 4. Update the Checkout Session with the shipping options if (shippingOptions != null) { SessionUpdateParams updateParams = SessionUpdateParams.builder() .setCollectedInformation(new SessionUpdateParams.CollectedInformation() .setShippingDetails(shippingDetails)) .addShippingOptions(shippingOptions) .build(); Session.update(checkoutSessionId, updateParams); return ResponseEntity.ok(Map.of("type", "object", "value", Map.of("succeeded", true))); } else { return ResponseEntity.badRequest().request(Map.of("type", "error", "message", "We can't find shipping options. Please try again.")); } } // Return a boolean indicating whether the shipping details are valid. private boolean validateShippingDetails(Map shippingDetails) { // TODO: Remove error and implement... throw new NotImplementedException("Validate the shipping details the customer has entered."); } // Return an array of the updated shipping options or the original options if no update is needed. private List calculateShippingOptions(Map shippingDetails, Session session) { // TODO: Remove error and implement... throw new NotImplementedException("Calculate shipping options based on the customer's shipping details and the Checkout Session's line items."); } } ``` ## Mount Checkout [Client-side] #### HTML + JS Checkout is available as part of [Stripe.js](https://docs.stripe.com/js.md). Include the Stripe.js script on your page by adding it to the head of your HTML file. Next, create an empty DOM node (container) to use for mounting. ```html
``` Initialize Stripe.js with your publishable API key. ```javascript // Set your publishable key: remember to change this to your live publishable key in production // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe('<>'); ``` Create an asynchronous `fetchClientSecret` function that makes a request to your server to create the [Checkout Session](https://docs.stripe.com/api/checkout/sessions/object.md) and retrieve the client secret. Create an asynchronous `onShippingDetailsChange` function that makes a request to your server to calculate the shipping options based on the customer’s shipping address. Stripe Checkout calls the function when the customer completes the shipping details form. ```javascript initialize(); async function initialize() { // Fetch Checkout Session and retrieve the client secret const fetchClientSecret = async () => { const response = await fetch("/create-checkout-session", { method: "POST", }); const { clientSecret } = await response.json(); return clientSecret; }; // Call your backend to set shipping options const onShippingDetailsChange = async (shippingDetailsChangeEvent) => { const {checkoutSessionId, shippingDetails} = shippingDetailsChangeEvent; const response = await fetch("/calculate-shipping-options", { method: "POST", body: JSON.stringify({ checkout_session_id: checkoutSessionId, shipping_details: shippingDetails, }) }) if (response.type === 'error') { return Promise.resolve({type: "reject", errorMessage: response.message}); } else { return Promise.resolve({type: "accept"}); } }; // Initialize Checkout const checkout = await stripe.initEmbeddedCheckout({ fetchClientSecret, onShippingDetailsChange, }); // Mount Checkout checkout.mount('#checkout'); } ``` #### React Install [react-stripe-js](https://docs.stripe.com/sdks/stripejs-react.md) and the Stripe.js loader from npm: ```bash npm install --save @stripe/react-stripe-js @stripe/stripe-js ``` Initialize the `stripe` instance with your publishable API key. ```jsx import {loadStripe} from '@stripe/stripe-js'; // Make sure to call `loadStripe` outside of a component’s render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe('<>'); ``` To use the Embedded Checkout component, create an `EmbeddedCheckoutProvider`. Create an asynchronous `fetchClientSecret` function that makes a request to your server to create the [Checkout Session](https://docs.stripe.com/api/checkout/sessions/object.md) and retrieve the client secret. Create an asynchronous `onShippingDetailsChange` function that makes a request to your server to calculate the shipping options based on the customer’s shipping address. Stripe Checkout calls the function when the customer completes the shipping details form. Pass `stripePromise` to the provider and the functions into the `options` prop accepted by the provider. ```jsx import * as React from 'react'; import { EmbeddedCheckoutProvider, EmbeddedCheckout } from '@stripe/react-stripe-js'; const App = () => { const fetchClientSecret = useCallback(() => { // Create a Checkout Session return fetch("/create-checkout-session", { method: "POST", }) .then((res) => res.json()) .then((data) => data.clientSecret); }, []); // Call your backend to set shipping options const onShippingDetailsChange = async (shippingDetailsChangeEvent) => { const {checkoutSessionId, shippingDetails} = shippingDetailsChangeEvent; const response = await fetch("/calculate-shipping-options", { method: "POST", body: JSON.stringify({ checkout_session_id: checkoutSessionId, shipping_details: shippingDetails, }) }) if (response.type === 'error') { return Promise.resolve({type: "reject", errorMessage: response.message}); } else { return Promise.resolve({type: "accept"}); } }; const options = {fetchClientSecret, onShippingDetailsChange}; return (
) } ``` > Always return a `Promise` from your `onShippingDetailsChange` function and resolve it with a [ResultAction](https://docs.stripe.com/js/embedded_checkout/init#embedded_checkout_init-options-onShippingDetailsChange-ResultAction) object. The Checkout client updates the UI based on the result of your `onShippingDetailsChange` function. - When the result has `type: "accept"`, the Checkout UI renders the shipping options that you set from your server. - When the result has `type: "reject"`, the Checkout UI shows the error message that you set in the result. Optionally, you can listen to `onShippingDetailsChange` and create a custom UI for customers to select and confirm their preferred address from multiple possible addresses. Checkout renders in an iframe that securely sends payment information to Stripe over an HTTPS connection. > Avoid placing Checkout within another iframe because some payment methods require redirecting to another page for payment confirmation. ## Test the integration Follow these steps to test your integration, and ensure your custom shipping options work correctly. 1. Set up a sandbox environment that mirrors your production setup. Use your Stripe sandbox API keys for this environment. 1. Simulate various shipping addresses to verify that your `calculateShippingOptions` function handles different scenarios correctly. 1. Verify server-side logic by using logging or debugging tools to confirm that your server: - Retrieves the [Checkout Session](https://docs.stripe.com/api/checkout/sessions/object.md). - Validates shipping details. - Calculates shipping options. - Updates the [Checkout Session](https://docs.stripe.com/api/checkout/sessions/object.md) with new shipping details and options. Make sure the update response contains the new shipping details and options. 1. Verify client-side logic by completing the checkout process multiple times in your browser. Pay attention to how the UI updates after entering shipping details. Make sure that: - The `onShippingDetailsChange` function is called when expected. - Shipping options update correctly based on the provided address. - Error messages display properly when shipping is unavailable. 1. Enter invalid shipping addresses or simulate server errors to test error handling, both server-side and client-side. --- # Source: https://docs.stripe.com/payments/checkout/custom-success-page.md # Customize redirect behavior Display a confirmation page with your customer's order information. # Stripe-hosted page > This is a Stripe-hosted page for when payment-ui is stripe-hosted. View the full page at https://docs.stripe.com/payments/checkout/custom-success-page?payment-ui=stripe-hosted. If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. If you have a Checkout integration that uses a Stripe-hosted page, Stripe redirects your customer to a success page that you create and host on your site. You can use the details from a [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) to display an order confirmation page for your customer (for example, their name or payment amount) after the payment. ## Redirect customers to a success page To use the details from a Checkout Session: 1. Modify the [success_url](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-success_url) to pass the Checkout Session ID to the client side. 1. Look up the Checkout Session using the ID on your success page. 1. Use the Checkout Session to customize what’s displayed on your success page. > #### Webhooks are required for fulfillment > > You can’t rely on triggering fulfillment only from your checkout landing page, because your customers aren’t guaranteed to visit that page. For example, someone can pay successfully and then lose their connection to the internet before your landing page loads. > > [Set up a webhook event handler](https://docs.stripe.com/checkout/fulfillment.md?payment-ui=stripe-hosted#create-payment-event-handler) so Stripe can send payment events directly to your server, bypassing the client entirely. Webhooks provide the most reliable way to confirm when you get paid. If webhook event delivery fails, Stripe [retries multiple times](https://docs.stripe.com/webhooks.md#automatic-retries). ## Modify the success URL (Server-side) Add the `{CHECKOUT_SESSION_ID}` template variable to the `success_url` when you create the Checkout Session. Note that this is a literal string and must be added exactly as you see it here. Do not substitute it with a Checkout Session ID—this happens automatically after your customer pays and is redirected to the success page. #### Ruby ```ruby session = Stripe::Checkout::Session.create(success_url: "http://yoursite.com/order/success?session_id={CHECKOUT_SESSION_ID}", # other options..., ) ``` #### Python ```python session = stripe.checkout.Session.create(success_url="http://yoursite.com/order/success?session_id={CHECKOUT_SESSION_ID}", # other options..., ) ``` #### PHP ```php $session = $stripe->checkout->sessions->create(['success_url' => "http://yoursite.com/order/success?session_id={CHECKOUT_SESSION_ID}", // other options..., ]); ``` #### Java ```java Map params = new HashMap<>(); params.put( "success_url","http://yoursite.com/order/success?session_id={CHECKOUT_SESSION_ID}", ); params.put( // other options... ); Session session = Session.create(params); ``` #### Node.js ```javascript const session = await stripe.checkout.sessions.create({success_url: "http://yoursite.com/order/success?session_id={CHECKOUT_SESSION_ID}", // other options..., }); ``` #### Go ```go params := &stripe.CheckoutSessionParams{SuccessURL: stripe.String("http://yoursite.com/order/success?session_id={CHECKOUT_SESSION_ID}"), // other options... ); s, _ := session.New(params) ``` #### .NET ```dotnet var options = new SessionCreateOptions {SuccessUrl = "http://yoursite.com/order/success?session_id={CHECKOUT_SESSION_ID}", // other options... }; var service = new SessionService(); var session = service.Create(options); ``` ## Create the success page (Server-side) Look up the Checkout Session using the ID and create a success page to display the order information. This example prints out the customer’s name: #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' require 'sinatra' get '/order/success' dosession = Stripe::Checkout::Session.retrieve(params[:session_id]) customer = Stripe::Customer.retrieve(session.customer) "

Thanks for your order, #{customer.name}!

" end ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck. import os import stripe from flask import Flask, request, render_template_string app = Flask(__name__) # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' @app.route('/order/success', methods=['GET']) def order_success():session = stripe.checkout.Session.retrieve(request.args.get('session_id')) customer = stripe.Customer.retrieve(session.customer) return render_template_string('

Thanks for your order, {{customer.name}}!

', customer=customer) if __name__== '__main__': app.run(port=4242) ``` #### PHP ```php >'); try { $session = $stripe->checkout->sessions->retrieve($_GET['session_id']); $customer = $stripe->customers->retrieve($session->customer);echo "

Thanks for your order, $customer->name!

"; http_response_code(200); } catch (Error $e) { http_response_code(500); echo json_encode(['error' => $e->getMessage()]); } ``` #### Java ```java import static spark.Spark.get; import static spark.Spark.port; import com.stripe.Stripe; import com.stripe.model.checkout.Session; import com.stripe.model.Customer; public class Server { public static void main(String[] args) { port(4242); // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; get("/order/success", (request, response) -> {Session session = Session.retrieve(request.queryParams("session_id")); Customer customer = Customer.retrieve(session.getCustomer()); return "

Thanks for your order, " + customer.getName() + "!

"; }); } } ``` #### Node.js ```javascript // This example sets up an endpoint using the Express framework. const express = require('express'); const app = express(); // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); app.get('/order/success', async (req, res) => {const session = await stripe.checkout.sessions.retrieve(req.query.session_id); const customer = await stripe.customers.retrieve(session.customer); res.send(`

Thanks for your order, ${customer.name}!

`); }); app.listen(4242, () => console.log(`Listening on port ${4242}!`)); ``` #### Go ```go package main import ( "net/http" "github.com/labstack/echo" "github.com/labstack/echo/middleware" "github.com/stripe/stripe-go/v76.0.0" "github.com/stripe/stripe-go/v76.0.0/customer" "github.com/stripe/stripe-go/v76.0.0/checkout/session" ) // This example sets up an endpoint using the Echo framework. // Watch this video to get started: https://youtu.be/ePmEVBu8w6Y. func main() { // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" e := echo.New() e.Use(middleware.Logger()) e.Use(middleware.Recover()) e.GET("/order/success", orderSuccess) e.Logger.Fatal(e.Start("localhost:4242")) } func orderSuccess(c echo.Context) (err error) {s, _ := session.Get(c.QueryParam("session_id"), nil) cus, _ := customer.Get(s.Customer, nil) return c.String(http.StatusOK, "

Thanks for your order, " + cus.Name + "!

") } ``` #### .NET ```dotnet // This example sets up an endpoint using the ASP.NET MVC framework. // Watch this video to get started: https://youtu.be/2-mMOB8MhmE. using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Stripe; using Stripe.Checkout; namespace server.Controllers { public class SuccessController : Controller { public SuccessController() { // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; } [HttpGet("/order/success")] public ActionResult OrderSuccess([FromQuery] string session_id) {var sessionService = new SessionService(); Session session = sessionService.Get(session_id); var customerService = new CustomerService(); Customer customer = customerService.Get(session.CustomerId); return Content($"

Thanks for your order, {customer.Name}!

"); } } } ``` ## Test the integration To confirm that your redirect is working as expected: 1. Click the checkout button. 1. Fill in the customer name and other payment details. 1. Click **Pay**. If it works, you’re redirected to the success page with your custom message. For example, if you used the message in the code samples, the success page displays this message: **Thanks for your order, Jenny Rosen!** # Embedded form > This is a Embedded form for when payment-ui is embedded-form. View the full page at https://docs.stripe.com/payments/checkout/custom-success-page?payment-ui=embedded-form. If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. If you have a Checkout integration that uses an embedded form, you can customize how and whether Stripe redirects your customers after they complete payment. You can have Stripe always redirect customers, only redirect for some payment methods, or completely disable redirects. To set up redirects, specify the return page in the `return_url` [parameter](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-return_url). Alternatively, you can: - [Only redirect customers if the payment method requires it](https://docs.stripe.com/payments/checkout/custom-success-page.md#redirect-if-required) (for example, a bank authorization page for a debit-based method). - Not use a return page and [disable redirect-based payment methods](https://docs.stripe.com/payments/checkout/custom-success-page.md#disable-redirects). > #### Webhooks are required for fulfillment > > You can’t rely on triggering fulfillment only from your checkout landing page, because your customers aren’t guaranteed to visit that page. For example, someone can pay successfully and then lose their connection to the internet before your landing page loads. > > [Set up a webhook event handler](https://docs.stripe.com/checkout/fulfillment.md?payment-ui=embedded-form#create-payment-event-handler) so Stripe can send payment events directly to your server, bypassing the client entirely. Webhooks provide the most reliable way to confirm when you get paid. If webhook event delivery fails, Stripe [retries multiple times](https://docs.stripe.com/webhooks.md#automatic-retries). ## Redirect customers to a return page When you create the [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md), you specify the URL of the return page in the `return_url` [parameter](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-return_url). Include the `{CHECKOUT_SESSION_ID}` template variable in the URL. When Checkout redirects a customer, it replaces the variable with the actual Checkout Session ID. When rendering your return page, retrieve the Checkout Session status using the Checkout Session ID in the URL. ```javascript app.get('/session_status', async (req, res) => { const session = await stripe.checkout.sessions.retrieve(req.query.session_id); const customer = await stripe.customers.retrieve(session.customer); res.send({ status: session.status, payment_status: session.payment_status, customer_email: customer.email }); }); ``` Handle the result according to the session status as follows: - `complete`: The payment succeeded. Use the information from the Checkout Session to render a success page. - `open`: The payment failed or was canceled. Remount Checkout so that your customer can try again. ```javascript const session = await fetch(`/session_status?session_id=${session_id}`) if (session.status == 'open') { // Remount embedded Checkout else if (session.status == 'complete') { // Show success page // Optionally use session.payment_status or session.customer_email // to customize the success page } ``` ## Redirect-based payment methods During payment, some payment methods redirect the customer to an intermediate page, such as a bank authorization page. When they complete that page, Stripe redirects them to your return page. ### Only redirect for redirect-based payment methods If you don’t want to redirect customers after payments that don’t require a redirect, set [redirect_on_completion](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-redirect_on_completion) to `if_required`. That redirects only customers who check out with redirect-based payment methods. For card payments, Checkout renders a default success state instead of redirecting. To use your own success state, pass an [onComplete](https://docs.stripe.com/js/embedded_checkout/init#embedded_checkout_init-options-onComplete) callback that destroys the Checkout instance and renders your custom success state. `onComplete` is called when the Checkout Session completes successfully, or when the [checkout.session.completed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) webhook event is sent. #### HTML + JS ```javascript const stripe = Stripe('<>'); initialize(); async function initialize() { const fetchClientSecret = async () => { const response = await fetch("/create-checkout-session", { method: "POST", }); const { clientSecret } = await response.json(); return clientSecret; }; // Example `onComplete` callback const handleComplete = async function() { // Destroy Checkout instance checkout.destroy() // Retrieve details from server (which loads Checkout Session) const details = await retrievePurchaseDetails(); // Show custom purchase summary showPurchaseSummary(details); } const checkout = await stripe.initEmbeddedCheckout({ fetchClientSecret, onComplete: handleComplete }); checkout.mount('#checkout'); } ``` #### React ```jsx const stripePromise = loadStripe('pk_test_123'); const App = ({fetchClientSecret}) => { const options = {fetchClientSecret}; const [isComplete, setIsComplete] = useState(false); const handleComplete = () => setIsComplete(true); return isComplete ? ( ) : ( ) } ``` ### Disable redirect-based payment methods If you don’t want to create a return page, create your Checkout Session with [redirect_on_completion](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-redirect_on_completion) set to `never`. This disables redirect-based payment methods: - If you use [Dynamic payment methods](https://docs.stripe.com/payments/payment-methods/dynamic-payment-methods.md), you can still manage payment methods from the Dashboard, but payment methods that require redirects aren’t eligible. - If you manually specify payment methods with [payment_method_types](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-payment_method_types), you can’t include any redirect-based payment methods. Setting `redirect_on_completion: never` removes the `return_url` requirement. For these sessions, Checkout renders a default success state instead of redirecting. You can use your own success state by passing an [onComplete](https://docs.stripe.com/js/embedded_checkout/init#embedded_checkout_init-options-onComplete) callback which destroys the Checkout instance and renders your custom success state. `onComplete` is called when the Checkout Session completes successfully, or when the [checkout.session.completed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) webhook event is sent. #### HTML + JS ```javascript const stripe = Stripe('<>'); initialize(); async function initialize() { const fetchClientSecret = async () => { const response = await fetch("/create-checkout-session", { method: "POST", }); const { clientSecret } = await response.json(); return clientSecret; }; // Example `onComplete` callback const handleComplete = async function() { // Destroy Checkout instance checkout.destroy() // Retrieve details from server (which loads Checkout Session) const details = await retrievePurchaseDetails(); // Show custom purchase summary showPurchaseSummary(details); } const checkout = await stripe.initEmbeddedCheckout({ fetchClientSecret, onComplete: handleComplete }); checkout.mount('#checkout'); } ``` #### React ```jsx const stripePromise = loadStripe('pk_test_123'); const App = ({fetchClientSecret}) => { const options = {fetchClientSecret}; const [isComplete, setIsComplete] = useState(false); const handleComplete = () => setIsComplete(true); return isComplete ? ( ) : ( ) } ``` --- # Source: https://docs.stripe.com/tax/custom.md # Collect taxes Use Stripe Tax APIs to implement tax calculations in your custom integration. Stripe Tax APIs enable you to calculate tax in custom payment flows. After your customer completes their payment, record the transaction so it appears in Stripe Tax reporting. The examples in this guide use Stripe payments APIs, but you can use the Tax API with any payment processor, or multiple payment processors. For most integrations, we recommend using the [Checkout Sessions API with Stripe Tax](https://docs.stripe.com/payments/advanced/tax.md). Alternatively, you can integrate Stripe Tax with [Payment Links](https://docs.stripe.com/payment-links.md), [Checkout](https://docs.stripe.com/checkout/quickstart.md), [Billing](https://docs.stripe.com/billing/subscriptions/build-subscriptions.md), and [Invoicing](https://docs.stripe.com/invoicing/no-code-guide.md) with no or low code setups. Stripe Tax APIs enable you to calculate tax in custom payment flows. After your customer completes their payment, record the transaction so it appears in Stripe Tax reporting. The examples in this guide use Stripe payments APIs, but you can use the Tax API with any payment processor, or multiple payment processors. If your custom payment flow uses the [Payment Intents API](https://docs.stripe.com/api/payment_intents.md), see [Calculate tax in your custom payment flows](https://docs.stripe.com/tax/payment-intent.md). This integration offers automatic liability tracking, receipts and Dashboard support. We also offer a public preview feature that lets you use the [Tax ID Element](https://docs.stripe.com/elements/tax-id-element.md) to collect tax IDs from customers. See [Collect customer tax IDs](https://docs.stripe.com/tax/custom.md#collect-customer-tax-ids) below for more information. Alternatively, you can integrate Stripe Tax with [Payment Links](https://docs.stripe.com/tax/payment-links.md), [Checkout](https://docs.stripe.com/tax/checkout.md), [Billing](https://docs.stripe.com/tax/subscriptions.md), and [Invoicing](https://docs.stripe.com/tax/invoicing.md) with no or low code setups. A diagram providing a high-level overview of the Tax API integration (See full diagram at https://docs.stripe.com/tax/custom) This video walks through a Stripe Tax API integration that uses the Payment Intents API and the Payment Element. [Watch on YouTube](https://www.youtube.com/watch?v=OfHJiC9Iek0) ## Add registrations Stripe Tax only calculates tax in jurisdictions where you’re registered to collect tax. You must [add your registrations](https://docs.stripe.com/tax/registering.md#add-a-registration) in the Dashboard. ## Optional: Collect customer address [Client-side] The tax you collect typically depends on your customer’s location. For the most accurate tax calculation, collect your customer’s full address. Before collecting an address, you can show your customer an estimate based on their [IP address](https://docs.stripe.com/tax/custom.md#ip-address). > The examples below use a simple custom address form, but you can also use the [Address Element](https://docs.stripe.com/elements/address-element.md) to collect addresses from customers with autocomplete and localization features. The form below collects a full postal address: ```html
``` You might pass the address to your server endpoint as follows: ```js const address = { line1: document.getElementById('address_line1').value, city: document.getElementById('address_city').value, state: document.getElementById('address_state').value, postal_code: document.getElementById('address_postal_code').value, country: document.getElementById('address_country').value, }; var response = fetch('/preview-cart', { method: 'POST', body: JSON.stringify({address: address}), headers: {'Content-Type': 'application/json'}, }).then(function(response) { return response.json(); }).then(function(responseJson) { // Handle errors, or display calculated tax to your customer. }); ``` The address information that’s required to calculate tax [varies by customer country](https://docs.stripe.com/tax/customer-locations.md#supported-formats): - **United States**: We require your customer’s postal code at a minimum. We recommend providing a full address for the most accurate tax calculation result. - **Canada**: We require your customer’s postal code or province. - **Other countries**: We only require your customer’s country code. ## Calculate tax [Server-side] You choose when and how often to [calculate tax](https://docs.stripe.com/api/tax/calculations/create.md). For example, you can: - Show a tax estimate [based on your customer’s IP address](https://docs.stripe.com/tax/custom.md#ip-address) when they enter your checkout flow - Recalculate tax as your customer types their billing or shipping address - Calculate the final tax amount to collect when your customer finishes typing their address Stripe [charges a fee](https://stripe.com/tax/pricing) per tax calculation API call. You can throttle tax calculation API calls to manage your costs. The examples below show how to calculate tax in a variety of scenarios. Stripe Tax only calculates tax in jurisdictions where you’re registered to collect tax. You must [add your registrations](https://docs.stripe.com/tax/registering.md#add-a-registration) in the Dashboard. #### Example - United States: tax-exclusive item This example calculates tax for a US shipping address. The line item has a price of 10 USD and uses your account’s [preset tax code](https://docs.stripe.com/tax/set-up.md#preset-tax-code). ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'shipping', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1"}], "customer_details": { "address": { "line1": "920 5th Ave", "city": "Seattle", "state": "WA", "postal_code": "98104", "country": "US", }, "address_source": "shipping", }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', ], ], 'customer_details' => [ 'address' => [ 'line1' => '920 5th Ave', 'city' => 'Seattle', 'state' => 'WA', 'postal_code' => '98104', 'country' => 'US', ], 'address_source' => 'shipping', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setLine1("920 5th Ave") .setCity("Seattle") .setState("WA") .setPostalCode("98104") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.SHIPPING) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'shipping', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ Line1: stripe.String("920 5th Ave"), City: stripe.String("Seattle"), State: stripe.String("WA"), PostalCode: stripe.String("98104"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceShipping), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1" }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Line1 = "920 5th Ave", City = "Seattle", State = "WA", PostalCode = "98104", Country = "US", }, AddressSource = "shipping", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` #### Example - United States: multiple items with shipping This example has multiple tax-exclusive line items, and a 5 USD shipping cost. ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_code]"=txcd_99999999 \ -d "line_items[1][amount]"=5000 \ -d "line_items[1][reference]"=L2 \ -d "line_items[1][tax_code]"=txcd_99999999 \ -d "line_items[2][amount]"=9999 \ -d "line_items[2][reference]"=L3 \ -d "line_items[2][tax_code]"=txcd_99999999 \ -d "shipping_cost[amount]"=500 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_code]"=txcd_99999999 \ -d "line_items[1][amount]"=5000 \ -d "line_items[1][reference]"=L2 \ -d "line_items[1][tax_code]"=txcd_99999999 \ -d "line_items[2][amount]"=9999 \ -d "line_items[2][reference]"=L3 \ -d "line_items[2][tax_code]"=txcd_99999999 \ -d "shipping_cost[amount]"=500 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', tax_code: 'txcd_99999999', }, { amount: 5000, reference: 'L2', tax_code: 'txcd_99999999', }, { amount: 9999, reference: 'L3', tax_code: 'txcd_99999999', }, ], shipping_cost: {amount: 500}, customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'shipping', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [ {"amount": 1000, "reference": "L1", "tax_code": "txcd_99999999"}, {"amount": 5000, "reference": "L2", "tax_code": "txcd_99999999"}, {"amount": 9999, "reference": "L3", "tax_code": "txcd_99999999"}, ], "shipping_cost": {"amount": 500}, "customer_details": { "address": { "line1": "920 5th Ave", "city": "Seattle", "state": "WA", "postal_code": "98104", "country": "US", }, "address_source": "shipping", }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', 'tax_code' => 'txcd_99999999', ], [ 'amount' => 5000, 'reference' => 'L2', 'tax_code' => 'txcd_99999999', ], [ 'amount' => 9999, 'reference' => 'L3', 'tax_code' => 'txcd_99999999', ], ], 'shipping_cost' => ['amount' => 500], 'customer_details' => [ 'address' => [ 'line1' => '920 5th Ave', 'city' => 'Seattle', 'state' => 'WA', 'postal_code' => '98104', 'country' => 'US', ], 'address_source' => 'shipping', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .setTaxCode("txcd_99999999") .build() ) .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(5000L) .setReference("L2") .setTaxCode("txcd_99999999") .build() ) .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(9999L) .setReference("L3") .setTaxCode("txcd_99999999") .build() ) .setShippingCost( CalculationCreateParams.ShippingCost.builder().setAmount(500L).build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setLine1("920 5th Ave") .setCity("Seattle") .setState("WA") .setPostalCode("98104") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.SHIPPING) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', tax_code: 'txcd_99999999', }, { amount: 5000, reference: 'L2', tax_code: 'txcd_99999999', }, { amount: 9999, reference: 'L3', tax_code: 'txcd_99999999', }, ], shipping_cost: { amount: 500, }, customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'shipping', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), TaxCode: stripe.String("txcd_99999999"), }, &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(5000), Reference: stripe.String("L2"), TaxCode: stripe.String("txcd_99999999"), }, &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(9999), Reference: stripe.String("L3"), TaxCode: stripe.String("txcd_99999999"), }, }, ShippingCost: &stripe.TaxCalculationCreateShippingCostParams{Amount: stripe.Int64(500)}, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ Line1: stripe.String("920 5th Ave"), City: stripe.String("Seattle"), State: stripe.String("WA"), PostalCode: stripe.String("98104"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceShipping), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1", TaxCode = "txcd_99999999", }, new Stripe.Tax.CalculationLineItemOptions { Amount = 5000, Reference = "L2", TaxCode = "txcd_99999999", }, new Stripe.Tax.CalculationLineItemOptions { Amount = 9999, Reference = "L3", TaxCode = "txcd_99999999", }, }, ShippingCost = new Stripe.Tax.CalculationShippingCostOptions { Amount = 500 }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Line1 = "920 5th Ave", City = "Seattle", State = "WA", PostalCode = "98104", Country = "US", }, AddressSource = "shipping", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` #### Example - United States: item with quantity In New York, clothing isn’t subject to sales tax if each item is less than 110 USD. This example has a clothing line item with a total price of 150 USD and a quantity of 3. This means that each item of clothing is 50 USD and sales tax is exempt. ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=15000 \ -d "line_items[0][quantity]"=3 \ -d "line_items[0][reference]"=Clothing \ -d "line_items[0][tax_code]"=txcd_30011000 \ -d "shipping_cost[amount]"=500 \ -d "customer_details[address][state]"=NY \ -d "customer_details[address][postal_code]"=10001 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=15000 \ -d "line_items[0][quantity]"=3 \ -d "line_items[0][reference]"=Clothing \ -d "line_items[0][tax_code]"=txcd_30011000 \ -d "shipping_cost[amount]"=500 \ -d "customer_details[address][state]"=NY \ -d "customer_details[address][postal_code]"=10001 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 15000, quantity: 3, reference: 'Clothing', tax_code: 'txcd_30011000', }, ], shipping_cost: {amount: 500}, customer_details: { address: { state: 'NY', postal_code: '10001', country: 'US', }, address_source: 'shipping', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [ { "amount": 15000, "quantity": 3, "reference": "Clothing", "tax_code": "txcd_30011000", }, ], "shipping_cost": {"amount": 500}, "customer_details": { "address": {"state": "NY", "postal_code": "10001", "country": "US"}, "address_source": "shipping", }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 15000, 'quantity' => 3, 'reference' => 'Clothing', 'tax_code' => 'txcd_30011000', ], ], 'shipping_cost' => ['amount' => 500], 'customer_details' => [ 'address' => [ 'state' => 'NY', 'postal_code' => '10001', 'country' => 'US', ], 'address_source' => 'shipping', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(15000L) .setQuantity(3L) .setReference("Clothing") .setTaxCode("txcd_30011000") .build() ) .setShippingCost( CalculationCreateParams.ShippingCost.builder().setAmount(500L).build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setState("NY") .setPostalCode("10001") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.SHIPPING) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 15000, quantity: 3, reference: 'Clothing', tax_code: 'txcd_30011000', }, ], shipping_cost: { amount: 500, }, customer_details: { address: { state: 'NY', postal_code: '10001', country: 'US', }, address_source: 'shipping', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(15000), Quantity: stripe.Int64(3), Reference: stripe.String("Clothing"), TaxCode: stripe.String("txcd_30011000"), }, }, ShippingCost: &stripe.TaxCalculationCreateShippingCostParams{Amount: stripe.Int64(500)}, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ State: stripe.String("NY"), PostalCode: stripe.String("10001"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceShipping), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 15000, Quantity = 3, Reference = "Clothing", TaxCode = "txcd_30011000", }, }, ShippingCost = new Stripe.Tax.CalculationShippingCostOptions { Amount = 500 }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { State = "NY", PostalCode = "10001", Country = "US", }, AddressSource = "shipping", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` #### Example - Europe: tax-inclusive item This example calculates tax for a billing address in Ireland, where tax is typically included in prices for non-business customers. The line item has a price of 29.99 EUR and uses tax code `txcd_10302000` (ebook). ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=eur \ -d "line_items[0][amount]"=2999 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=inclusive \ -d "line_items[0][tax_code]"=txcd_10302000 \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing ``` ```cli stripe tax calculations create \ --currency=eur \ -d "line_items[0][amount]"=2999 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=inclusive \ -d "line_items[0][tax_code]"=txcd_10302000 \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'eur', line_items: [ { amount: 2999, reference: 'L1', tax_behavior: 'inclusive', tax_code: 'txcd_10302000', }, ], customer_details: { address: {country: 'IE'}, address_source: 'billing', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "eur", "line_items": [ { "amount": 2999, "reference": "L1", "tax_behavior": "inclusive", "tax_code": "txcd_10302000", }, ], "customer_details": {"address": {"country": "IE"}, "address_source": "billing"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'eur', 'line_items' => [ [ 'amount' => 2999, 'reference' => 'L1', 'tax_behavior' => 'inclusive', 'tax_code' => 'txcd_10302000', ], ], 'customer_details' => [ 'address' => ['country' => 'IE'], 'address_source' => 'billing', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("eur") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(2999L) .setReference("L1") .setTaxBehavior(CalculationCreateParams.LineItem.TaxBehavior.INCLUSIVE) .setTaxCode("txcd_10302000") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setCountry("IE") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.BILLING) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'eur', line_items: [ { amount: 2999, reference: 'L1', tax_behavior: 'inclusive', tax_code: 'txcd_10302000', }, ], customer_details: { address: { country: 'IE', }, address_source: 'billing', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyEUR), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(2999), Reference: stripe.String("L1"), TaxBehavior: stripe.String("inclusive"), TaxCode: stripe.String("txcd_10302000"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{Country: stripe.String("IE")}, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceBilling), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "eur", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 2999, Reference = "L1", TaxBehavior = "inclusive", TaxCode = "txcd_10302000", }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Country = "IE" }, AddressSource = "billing", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` #### Example - Europe: multiple items with shipping This example calculates tax for a shipping address in Ireland, where tax is typically included in prices for non-business customers. The item being shipped has a price of 59.99 EUR, and a shipping cost of 5 EUR. Since both amounts are tax-inclusive, the customer always pays 64.99 EUR. ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=eur \ -d "line_items[0][amount]"=5999 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=inclusive \ -d "line_items[0][tax_code]"=txcd_99999999 \ -d "shipping_cost[amount]"=500 \ -d "shipping_cost[tax_behavior]"=inclusive \ -d "customer_details[address][line1]"="123 Some House" \ -d "customer_details[address][city]"=Dublin \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=shipping ``` ```cli stripe tax calculations create \ --currency=eur \ -d "line_items[0][amount]"=5999 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=inclusive \ -d "line_items[0][tax_code]"=txcd_99999999 \ -d "shipping_cost[amount]"=500 \ -d "shipping_cost[tax_behavior]"=inclusive \ -d "customer_details[address][line1]"="123 Some House" \ -d "customer_details[address][city]"=Dublin \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=shipping ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'eur', line_items: [ { amount: 5999, reference: 'L1', tax_behavior: 'inclusive', tax_code: 'txcd_99999999', }, ], shipping_cost: { amount: 500, tax_behavior: 'inclusive', }, customer_details: { address: { line1: '123 Some House', city: 'Dublin', country: 'IE', }, address_source: 'shipping', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "eur", "line_items": [ { "amount": 5999, "reference": "L1", "tax_behavior": "inclusive", "tax_code": "txcd_99999999", }, ], "shipping_cost": {"amount": 500, "tax_behavior": "inclusive"}, "customer_details": { "address": {"line1": "123 Some House", "city": "Dublin", "country": "IE"}, "address_source": "shipping", }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'eur', 'line_items' => [ [ 'amount' => 5999, 'reference' => 'L1', 'tax_behavior' => 'inclusive', 'tax_code' => 'txcd_99999999', ], ], 'shipping_cost' => [ 'amount' => 500, 'tax_behavior' => 'inclusive', ], 'customer_details' => [ 'address' => [ 'line1' => '123 Some House', 'city' => 'Dublin', 'country' => 'IE', ], 'address_source' => 'shipping', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("eur") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(5999L) .setReference("L1") .setTaxBehavior(CalculationCreateParams.LineItem.TaxBehavior.INCLUSIVE) .setTaxCode("txcd_99999999") .build() ) .setShippingCost( CalculationCreateParams.ShippingCost.builder() .setAmount(500L) .setTaxBehavior(CalculationCreateParams.ShippingCost.TaxBehavior.INCLUSIVE) .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setLine1("123 Some House") .setCity("Dublin") .setCountry("IE") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.SHIPPING) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'eur', line_items: [ { amount: 5999, reference: 'L1', tax_behavior: 'inclusive', tax_code: 'txcd_99999999', }, ], shipping_cost: { amount: 500, tax_behavior: 'inclusive', }, customer_details: { address: { line1: '123 Some House', city: 'Dublin', country: 'IE', }, address_source: 'shipping', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyEUR), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(5999), Reference: stripe.String("L1"), TaxBehavior: stripe.String("inclusive"), TaxCode: stripe.String("txcd_99999999"), }, }, ShippingCost: &stripe.TaxCalculationCreateShippingCostParams{ Amount: stripe.Int64(500), TaxBehavior: stripe.String(stripe.TaxCalculationShippingCostTaxBehaviorInclusive), }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ Line1: stripe.String("123 Some House"), City: stripe.String("Dublin"), Country: stripe.String("IE"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceShipping), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "eur", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 5999, Reference = "L1", TaxBehavior = "inclusive", TaxCode = "txcd_99999999", }, }, ShippingCost = new Stripe.Tax.CalculationShippingCostOptions { Amount = 500, TaxBehavior = "inclusive", }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Line1 = "123 Some House", City = "Dublin", Country = "IE", }, AddressSource = "shipping", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` #### Example - Ship-from address With this beta feature, taxes are levied based on the ship-from address, if you provide a ship-from address in certain states (such as Illinois) and the shipment contains physical goods. If the shipment contains both physical goods and services, taxes are applied to both based on the ship-from address. This example calculates tax based on where the order ships from in Naperville, IL, instead of the business location (outside Illinois) and the ship-to address in Springfield, IL. ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=exclusive \ -d "line_items[0][tax_code]"=txcd_99999999 \ -d "shipping_cost[amount]"=500 \ -d "shipping_cost[tax_behavior]"=exclusive \ -d "customer_details[address][city]"=Springfield \ -d "customer_details[address][state]"=IL \ -d "customer_details[address][postal_code]"=62704 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=billing \ -d "ship_from_details[address][city]"=Naperville \ -d "ship_from_details[address][state]"=IL \ -d "ship_from_details[address][postal_code]"=60540 \ -d "ship_from_details[address][country]"=US ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=exclusive \ -d "line_items[0][tax_code]"=txcd_99999999 \ -d "shipping_cost[amount]"=500 \ -d "shipping_cost[tax_behavior]"=exclusive \ -d "customer_details[address][city]"=Springfield \ -d "customer_details[address][state]"=IL \ -d "customer_details[address][postal_code]"=62704 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=billing \ -d "ship_from_details[address][city]"=Naperville \ -d "ship_from_details[address][state]"=IL \ -d "ship_from_details[address][postal_code]"=60540 \ -d "ship_from_details[address][country]"=US ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', tax_behavior: 'exclusive', tax_code: 'txcd_99999999', }, ], shipping_cost: { amount: 500, tax_behavior: 'exclusive', }, customer_details: { address: { city: 'Springfield', state: 'IL', postal_code: '62704', country: 'US', }, address_source: 'billing', }, ship_from_details: { address: { city: 'Naperville', state: 'IL', postal_code: '60540', country: 'US', }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [ { "amount": 1000, "reference": "L1", "tax_behavior": "exclusive", "tax_code": "txcd_99999999", }, ], "shipping_cost": {"amount": 500, "tax_behavior": "exclusive"}, "customer_details": { "address": { "city": "Springfield", "state": "IL", "postal_code": "62704", "country": "US", }, "address_source": "billing", }, "ship_from_details": { "address": { "city": "Naperville", "state": "IL", "postal_code": "60540", "country": "US", }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', 'tax_behavior' => 'exclusive', 'tax_code' => 'txcd_99999999', ], ], 'shipping_cost' => [ 'amount' => 500, 'tax_behavior' => 'exclusive', ], 'customer_details' => [ 'address' => [ 'city' => 'Springfield', 'state' => 'IL', 'postal_code' => '62704', 'country' => 'US', ], 'address_source' => 'billing', ], 'ship_from_details' => [ 'address' => [ 'city' => 'Naperville', 'state' => 'IL', 'postal_code' => '60540', 'country' => 'US', ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .setTaxBehavior(CalculationCreateParams.LineItem.TaxBehavior.EXCLUSIVE) .setTaxCode("txcd_99999999") .build() ) .setShippingCost( CalculationCreateParams.ShippingCost.builder() .setAmount(500L) .setTaxBehavior(CalculationCreateParams.ShippingCost.TaxBehavior.EXCLUSIVE) .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setCity("Springfield") .setState("IL") .setPostalCode("62704") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.BILLING) .build() ) .setShipFromDetails( CalculationCreateParams.ShipFromDetails.builder() .setAddress( CalculationCreateParams.ShipFromDetails.Address.builder() .setCity("Naperville") .setState("IL") .setPostalCode("60540") .setCountry("US") .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', tax_behavior: 'exclusive', tax_code: 'txcd_99999999', }, ], shipping_cost: { amount: 500, tax_behavior: 'exclusive', }, customer_details: { address: { city: 'Springfield', state: 'IL', postal_code: '62704', country: 'US', }, address_source: 'billing', }, ship_from_details: { address: { city: 'Naperville', state: 'IL', postal_code: '60540', country: 'US', }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), TaxBehavior: stripe.String("exclusive"), TaxCode: stripe.String("txcd_99999999"), }, }, ShippingCost: &stripe.TaxCalculationCreateShippingCostParams{ Amount: stripe.Int64(500), TaxBehavior: stripe.String(stripe.TaxCalculationShippingCostTaxBehaviorExclusive), }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ City: stripe.String("Springfield"), State: stripe.String("IL"), PostalCode: stripe.String("62704"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceBilling), }, ShipFromDetails: &stripe.TaxCalculationCreateShipFromDetailsParams{ Address: &stripe.AddressParams{ City: stripe.String("Naperville"), State: stripe.String("IL"), PostalCode: stripe.String("60540"), Country: stripe.String("US"), }, }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1", TaxBehavior = "exclusive", TaxCode = "txcd_99999999", }, }, ShippingCost = new Stripe.Tax.CalculationShippingCostOptions { Amount = 500, TaxBehavior = "exclusive", }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { City = "Springfield", State = "IL", PostalCode = "62704", Country = "US", }, AddressSource = "billing", }, }; options.AddExtraParam("ship_from_details[address][city]", "Naperville"); options.AddExtraParam("ship_from_details[address][state]", "IL"); options.AddExtraParam("ship_from_details[address][postal_code]", "60540"); options.AddExtraParam("ship_from_details[address][country]", "US"); var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` The [calculation response](https://docs.stripe.com/api/tax/calculations/object.md) contains amounts you can display to your customer, and use to take payment: | Attribute | Description | | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [amount_total](https://docs.stripe.com/api/tax/calculations/object.md#tax_calculation_object-amount_total) | The grand total after calculating tax. Use this to set the PaymentIntent [amount](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-amount) to charge your customer. | | [tax_amount_exclusive](https://docs.stripe.com/api/tax/calculations/object.md#tax_calculation_object-tax_amount_exclusive) | The amount of tax added on top of your line item amounts and shipping cost. This tax amount increases the `amount_total`. Use this to show your customer the amount of tax added to the transaction subtotal. | | [tax_amount_inclusive](https://docs.stripe.com/api/tax/calculations/object.md#tax_calculation_object-tax_amount_inclusive) | The amount of tax that’s included in your line item amounts and shipping cost (if using tax-inclusive pricing). This tax amount doesn’t increase the `amount_total`. Use this to show your customer the tax included in the total they’re paying. | | [tax_breakdown](https://docs.stripe.com/api/tax/calculations/object.md#tax_calculation_object-tax_breakdown) | A list of tax amounts broken out by country or state tax rate. Use this to show your customer the specific taxes you’re collecting. | ### Handle customer location errors The calculation returns the `customer_tax_location_invalid` error code, if your customer’s address is invalid or isn’t precise enough to calculate tax: ```json { "error": { "doc_url": "https://docs.stripe.com/error-codes#customer-tax-location-invalid","code": "customer_tax_location_invalid", "message": "We could not determine the customer's tax location based on the provided customer address.", "param": "customer_details[address]", "type": "invalid_request_error" } } ``` If you receive this error, prompt your customer to check the address they entered and fix any typos. ### Use calculation with another processor If you process transactions outside of Stripe, you can skip the following steps and apply the calculation to your externally-processed transactions. ## Create tax transaction [Server-side] Creating a tax transaction records the tax you’ve collected from your customer, so that later you can [download exports and generate reports](https://docs.stripe.com/tax/reports.md) to help with filing your taxes. You can [create a transaction](https://docs.stripe.com/api/tax/transactions/create_from_calculation.md) from a calculation until the [expires_at](https://docs.stripe.com/api/tax/calculations/object.md#tax_calculation_object-expires_at) timestamp, 90 days after it’s created. Attempting to use it after this time returns an error. > The transaction is considered effective on the date when `create_from_calculation` is called, and tax amounts won’t be recalculated. When creating a tax transaction, you must provide a unique `reference` for the tax transaction and each line item. The references appear in tax exports to help you reconcile the tax you collected with the orders in your system. For example, a tax transaction with reference `pi_123456789`, line item references `L1` and `L2`, and a shipping cost, looks like this in the itemized tax exports: | ID | line_item_id | type | currency | transaction_date | | ------------ | ------------ | -------- | -------- | ------------------- | | pi_123456789 | L1 | external | usd | 2023-02-23 17:01:16 | | pi_123456789 | L2 | external | usd | 2023-02-23 17:01:16 | | pi_123456789 | shipping | external | usd | 2023-02-23 17:01:16 | When your customer pays, use the calculation ID to record the tax collected. You can do this in two ways: - If your server has an endpoint where your customer submits their order, you can create the tax transaction after the order is successfully submitted. - Listen for the [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) webhook event. Retrieve the calculation ID from the PaymentIntent `metadata`. The example below creates a transaction and uses the PaymentIntent ID as the unique reference: ```curl curl https://api.stripe.com/v1/tax/transactions/create_from_calculation \ -u "<>:" \ -d calculation={{TAX_CALCULATION}} \ -d reference="{{PAYMENTINTENT_ID}}" \ -d "expand[]"=line_items ``` ```cli stripe tax transactions create_from_calculation \ --calculation={{TAX_CALCULATION}} \ --reference="{{PAYMENTINTENT_ID}}" \ -d "expand[0]"=line_items ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") transaction = client.v1.tax.transactions.create_from_calculation({ calculation: '{{TAX_CALCULATION}}', reference: '{{PAYMENTINTENT_ID}}', expand: ['line_items'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. transaction = client.v1.tax.transactions.create_from_calculation({ "calculation": "{{TAX_CALCULATION}}", "reference": "{{PAYMENTINTENT_ID}}", "expand": ["line_items"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $transaction = $stripe->tax->transactions->createFromCalculation([ 'calculation' => '{{TAX_CALCULATION}}', 'reference' => '{{PAYMENTINTENT_ID}}', 'expand' => ['line_items'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); TransactionCreateFromCalculationParams params = TransactionCreateFromCalculationParams.builder() .setCalculation("{{TAX_CALCULATION}}") .setReference("{{PAYMENTINTENT_ID}}") .addExpand("line_items") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Transaction transaction = client.v1().tax().transactions().createFromCalculation(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const transaction = await stripe.tax.transactions.createFromCalculation({ calculation: '{{TAX_CALCULATION}}', reference: '{{PAYMENTINTENT_ID}}', expand: ['line_items'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxTransactionCreateFromCalculationParams{ Calculation: stripe.String("{{TAX_CALCULATION}}"), Reference: stripe.String("{{PAYMENTINTENT_ID}}"), } params.AddExpand("line_items") result, err := sc.V1TaxTransactions.CreateFromCalculation(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.TransactionCreateFromCalculationOptions { Calculation = "{{TAX_CALCULATION}}", Reference = "{{PAYMENTINTENT_ID}}", Expand = new List { "line_items" }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Transactions; Stripe.Tax.Transaction transaction = service.CreateFromCalculation(options); ``` Store the [tax transaction ID](https://docs.stripe.com/api/tax/transactions/object.md#tax_transaction_object-id) to record refunds later. You can store the transaction ID in your database or in the PaymentIntent’s metadata: ```curl curl https://api.stripe.com/v1/payment_intents/{{PAYMENTINTENT_ID}} \ -u "<>:" \ -d "metadata[tax_transaction]"={{TAX_TRANSACTION}} ``` ```cli stripe payment_intents update {{PAYMENTINTENT_ID}} \ -d "metadata[tax_transaction]"={{TAX_TRANSACTION}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.update( '{{PAYMENTINTENT_ID}}', {metadata: {tax_transaction: '{{TAX_TRANSACTION}}'}}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.update( "{{PAYMENTINTENT_ID}}", {"metadata": {"tax_transaction": "{{TAX_TRANSACTION}}"}}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->update( '{{PAYMENTINTENT_ID}}', ['metadata' => ['tax_transaction' => '{{TAX_TRANSACTION}}']] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentUpdateParams params = PaymentIntentUpdateParams.builder() .putMetadata("tax_transaction", "{{TAX_TRANSACTION}}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().update("{{PAYMENTINTENT_ID}}", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.update( '{{PAYMENTINTENT_ID}}', { metadata: { tax_transaction: '{{TAX_TRANSACTION}}', }, } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentUpdateParams{} params.AddMetadata("tax_transaction", "{{TAX_TRANSACTION}}") result, err := sc.V1PaymentIntents.Update( context.TODO(), "{{PAYMENTINTENT_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentUpdateOptions { Metadata = new Dictionary { { "tax_transaction", "{{TAX_TRANSACTION}}" }, }, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Update("{{PAYMENTINTENT_ID}}", options); ``` ## Record refunds [Server-side] After creating a tax transaction to record a sale to your customer, you might need to record refunds. These are also represented as tax transactions, with `type=reversal`. Reversal transactions offset an earlier transaction by having amounts with opposite signs. For example, a transaction that recorded a sale for 50 USD might later have a full reversal of -50 USD. When you issue a refund (using Stripe or outside of Stripe), you must create a reversal tax transaction with a unique `reference`. Common strategies include: - Append a suffix to the original reference. For example, if the original transaction has reference `pi_123456789`, then create the reversal transaction with reference `pi_123456789-refund`. - Use the ID of the [Stripe refund](https://docs.stripe.com/api/refunds/object.md) or a refund ID from your system. For example, `re_3MoslRBUZ691iUZ41bsYVkOg` or `myRefund_456`. Choose the approach that works best for how you reconcile your customer orders with your [tax exports](https://docs.stripe.com/tax/reports.md). ### Fully refund a sale When you fully refund a sale in your system, create a reversal transaction with `mode=full`. In the example below, `tax_1MEFAAI6rIcR421eB1YOzACZ` is the tax transaction that records the sale to your customer: ```curl curl https://api.stripe.com/v1/tax/transactions/create_reversal \ -u "<>:" \ -d mode=full \ -d original_transaction=tax_1MEFAAI6rIcR421eB1YOzACZ \ -d reference=pi_123456789-cancel \ -d "expand[]"=line_items ``` ```cli stripe tax transactions create_reversal \ --mode=full \ --original-transaction=tax_1MEFAAI6rIcR421eB1YOzACZ \ --reference=pi_123456789-cancel \ -d "expand[0]"=line_items ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") transaction = client.v1.tax.transactions.create_reversal({ mode: 'full', original_transaction: 'tax_1MEFAAI6rIcR421eB1YOzACZ', reference: 'pi_123456789-cancel', expand: ['line_items'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. transaction = client.v1.tax.transactions.create_reversal({ "mode": "full", "original_transaction": "tax_1MEFAAI6rIcR421eB1YOzACZ", "reference": "pi_123456789-cancel", "expand": ["line_items"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $transaction = $stripe->tax->transactions->createReversal([ 'mode' => 'full', 'original_transaction' => 'tax_1MEFAAI6rIcR421eB1YOzACZ', 'reference' => 'pi_123456789-cancel', 'expand' => ['line_items'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); TransactionCreateReversalParams params = TransactionCreateReversalParams.builder() .setMode(TransactionCreateReversalParams.Mode.FULL) .setOriginalTransaction("tax_1MEFAAI6rIcR421eB1YOzACZ") .setReference("pi_123456789-cancel") .addExpand("line_items") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Transaction transaction = client.v1().tax().transactions().createReversal(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const transaction = await stripe.tax.transactions.createReversal({ mode: 'full', original_transaction: 'tax_1MEFAAI6rIcR421eB1YOzACZ', reference: 'pi_123456789-cancel', expand: ['line_items'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxTransactionCreateReversalParams{ Mode: stripe.String("full"), OriginalTransaction: stripe.String("tax_1MEFAAI6rIcR421eB1YOzACZ"), Reference: stripe.String("pi_123456789-cancel"), } params.AddExpand("line_items") result, err := sc.V1TaxTransactions.CreateReversal(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.TransactionCreateReversalOptions { Mode = "full", OriginalTransaction = "tax_1MEFAAI6rIcR421eB1YOzACZ", Reference = "pi_123456789-cancel", Expand = new List { "line_items" }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Transactions; Stripe.Tax.Transaction transaction = service.CreateReversal(options); ``` This returns the full reversal transaction that’s created: ```json { "id": "tax_1MEFtXI6rIcR421e0KTGXvCK", "object": "tax.transaction", "created": 1670866467, "currency": "eur", "customer": null, "customer_details": { "address": { "city": null, "country": "IE", "line1": null, "line2": null, "postal_code": null, "state": null }, "address_source": "billing", "ip_address": null, "tax_ids": [], "taxability_override": "none" }, "line_items": { "object": "list", "data": [ { "id": "tax_li_MyCIgTuP9F9mEU", "object": "tax.transaction_line_item", "amount": -4999, "amount_tax": -1150, "livemode": false, "metadata": { }, "quantity": 1, "reference": "L1", "reversal": { "original_line_item": "tax_li_MyBXPByrSUwm6r" }, "tax_behavior": "exclusive", "tax_code": "txcd_10000000", "type": "reversal" }, { "id": "tax_li_MyCIUNXExXmJKU", "object": "tax.transaction_line_item", "amount": -1090, "amount_tax": -90, "livemode": false, "metadata": { }, "quantity": 1, "reference": "L2", "reversal": { "original_line_item": "tax_li_MyBX3Wu3qd2mXj" }, "tax_behavior": "exclusive", "tax_code": "txcd_10000000", "type": "reversal" } ], "has_more": false, "total_count": 2, "url": "/v1/tax/transactions/tax_1MEFtXI6rIcR421e0KTGXvCK/line_items" }, "livemode": false, "metadata": { }, "reference": "pi_123456789-cancel", "reversal": { "original_transaction": "tax_1MEFAAI6rIcR421eB1YOzACZ" }, "shipping_cost": null, "tax_date": 1670863654, "type": "reversal" } ``` Fully reversing a transaction doesn’t affect previous partial reversals. When you record a full reversal, make sure you [fully reverse](https://docs.stripe.com/tax/custom.md#reversals-void-refund) any previous partial reversals for the same transaction to avoid duplicate refunds. ### Partially refund a sale After [issuing a refund](https://docs.stripe.com/api/refunds/create.md) to your customer, create a reversal tax transaction with `mode=partial`. This allows you to record a partial refund by providing the line item amounts refunded. You can create up to 30 partial reversals for each sale. Reversing more than the amount of tax you collected returns an error. The example below records a refund of only the first line item in the original transaction: ```curl curl https://api.stripe.com/v1/tax/transactions/create_reversal \ -u "<>:" \ -d mode=partial \ -d original_transaction=tax_1MEFAAI6rIcR421eB1YOzACZ \ -d reference=pi_123456789-refund_1 \ -d "line_items[0][original_line_item]"=tax_li_MyBXPByrSUwm6r \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][amount]"=-4999 \ -d "line_items[0][amount_tax]"=-1150 \ -d "metadata[refund]"="{{REFUND_ID}}" \ --data-urlencode "metadata[refund_reason]"="Refunded line 1 of pi_123456789 (customer was unhappy)" \ -d "expand[0]"=line_items ``` ```cli stripe tax transactions create_reversal \ --mode=partial \ --original-transaction=tax_1MEFAAI6rIcR421eB1YOzACZ \ --reference=pi_123456789-refund_1 \ -d "line_items[0][original_line_item]"=tax_li_MyBXPByrSUwm6r \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][amount]"=-4999 \ -d "line_items[0][amount_tax]"=-1150 \ -d "metadata[refund]"="{{REFUND_ID}}" \ -d "metadata[refund_reason]"="Refunded line 1 of pi_123456789 (customer was unhappy)" \ -d "expand[0]"=line_items ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") transaction = client.v1.tax.transactions.create_reversal({ mode: 'partial', original_transaction: 'tax_1MEFAAI6rIcR421eB1YOzACZ', reference: 'pi_123456789-refund_1', line_items: [ { original_line_item: 'tax_li_MyBXPByrSUwm6r', reference: 'L1', amount: -4999, amount_tax: -1150, }, ], metadata: { refund: '{{REFUND_ID}}', refund_reason: 'Refunded line 1 of pi_123456789 (customer was unhappy)', }, expand: ['line_items'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. transaction = client.v1.tax.transactions.create_reversal({ "mode": "partial", "original_transaction": "tax_1MEFAAI6rIcR421eB1YOzACZ", "reference": "pi_123456789-refund_1", "line_items": [ { "original_line_item": "tax_li_MyBXPByrSUwm6r", "reference": "L1", "amount": -4999, "amount_tax": -1150, }, ], "metadata": { "refund": "{{REFUND_ID}}", "refund_reason": "Refunded line 1 of pi_123456789 (customer was unhappy)", }, "expand": ["line_items"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $transaction = $stripe->tax->transactions->createReversal([ 'mode' => 'partial', 'original_transaction' => 'tax_1MEFAAI6rIcR421eB1YOzACZ', 'reference' => 'pi_123456789-refund_1', 'line_items' => [ [ 'original_line_item' => 'tax_li_MyBXPByrSUwm6r', 'reference' => 'L1', 'amount' => -4999, 'amount_tax' => -1150, ], ], 'metadata' => [ 'refund' => '{{REFUND_ID}}', 'refund_reason' => 'Refunded line 1 of pi_123456789 (customer was unhappy)', ], 'expand' => ['line_items'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); TransactionCreateReversalParams params = TransactionCreateReversalParams.builder() .setMode(TransactionCreateReversalParams.Mode.PARTIAL) .setOriginalTransaction("tax_1MEFAAI6rIcR421eB1YOzACZ") .setReference("pi_123456789-refund_1") .addLineItem( TransactionCreateReversalParams.LineItem.builder() .setOriginalLineItem("tax_li_MyBXPByrSUwm6r") .setReference("L1") .setAmount(-4999L) .setAmountTax(-1150L) .build() ) .putMetadata("refund", "{{REFUND_ID}}") .putMetadata( "refund_reason", "Refunded line 1 of pi_123456789 (customer was unhappy)" ) .addExpand("line_items") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Transaction transaction = client.v1().tax().transactions().createReversal(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const transaction = await stripe.tax.transactions.createReversal({ mode: 'partial', original_transaction: 'tax_1MEFAAI6rIcR421eB1YOzACZ', reference: 'pi_123456789-refund_1', line_items: [ { original_line_item: 'tax_li_MyBXPByrSUwm6r', reference: 'L1', amount: -4999, amount_tax: -1150, }, ], metadata: { refund: '{{REFUND_ID}}', refund_reason: 'Refunded line 1 of pi_123456789 (customer was unhappy)', }, expand: ['line_items'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxTransactionCreateReversalParams{ Mode: stripe.String("partial"), OriginalTransaction: stripe.String("tax_1MEFAAI6rIcR421eB1YOzACZ"), Reference: stripe.String("pi_123456789-refund_1"), LineItems: []*stripe.TaxTransactionCreateReversalLineItemParams{ &stripe.TaxTransactionCreateReversalLineItemParams{ OriginalLineItem: stripe.String("tax_li_MyBXPByrSUwm6r"), Reference: stripe.String("L1"), Amount: stripe.Int64(-4999), AmountTax: stripe.Int64(-1150), }, }, } params.AddMetadata("refund", "{{REFUND_ID}}") params.AddMetadata( "refund_reason", "Refunded line 1 of pi_123456789 (customer was unhappy)") params.AddExpand("line_items") result, err := sc.V1TaxTransactions.CreateReversal(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.TransactionCreateReversalOptions { Mode = "partial", OriginalTransaction = "tax_1MEFAAI6rIcR421eB1YOzACZ", Reference = "pi_123456789-refund_1", LineItems = new List { new Stripe.Tax.TransactionLineItemOptions { OriginalLineItem = "tax_li_MyBXPByrSUwm6r", Reference = "L1", Amount = -4999, AmountTax = -1150, }, }, Metadata = new Dictionary { { "refund", "{{REFUND_ID}}" }, { "refund_reason", "Refunded line 1 of pi_123456789 (customer was unhappy)" }, }, Expand = new List { "line_items" }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Transactions; Stripe.Tax.Transaction transaction = service.CreateReversal(options); ``` This returns the partial reversal transaction that’s created: ```json { "id": "tax_1MEFACI6rIcR421eHrjXCSmD", "object": "tax.transaction", "created": 1670863656, "currency": "eur", ... "line_items": { "object": "list", "data": [ { "id": "tax_li_MyBXC98AhtaR37", "object": "tax.transaction_line_item", "amount": -4999, "amount_tax": -1150, "livemode": false, "metadata": { }, "quantity": 1, "reference": "L1", "reversal": { "original_line_item": "tax_li_MyBXPByrSUwm6r" }, "tax_behavior": "exclusive", "tax_code": "txcd_10000000", "type": "reversal" } ], "has_more": false, "total_count": 1, "url": "/v1/tax/transactions/tax_1MEFACI6rIcR421eHrjXCSmD/line_items" }, "livemode": false, "metadata": { "refund": "{{REFUND_ID}}", "description": "Refunding pi_123456789 (customer was unhappy)" }, "reference": "pi_123456789-refund_1", "reversal": { "original_transaction": "tax_1MEFAAI6rIcR421eB1YOzACZ" }, "shipping_cost": null, "tax_date": 1670863654, "type": "reversal" } ``` For each line item reversed, you must provide the `amount` and `amount_tax` reversed. The `amount` is tax-inclusive if the original calculation line item was tax-inclusive. How `amount` and `amount_tax` are determined depends on your situation: - If your transactions always have a single line item, use [full reversals](https://docs.stripe.com/tax/custom.md#reversals-full) instead. - If you always refund entire line items, use the original transaction line item `amount` and `amount_tax`, but with negative signs. - If you refund parts of line items, you must calculate the amounts refunded. For example, for a sale transaction with `amount=5000` and `amount_tax=500`, after refunding half the line item, you create a partial reversal with line item `amount=-2500` and `amount_tax=-250`. #### Tax reports with partial refunds If you refund a tax amount such that the total tax is no longer proportional to the subtotal, your tax reporting can be unreliable. It won’t automatically adjust the taxable and nontaxable amounts, and won’t reflect the reason for the tax reversal (such as product exempt, customer exempt, or reverse charge). We recommend not refunding partial line item tax amounts. Instead, fully reverse the transaction and create a new one with appropriate inputs for an accurate tax calculation. ### Partially refund a sale by a flat amount Alternatively, you can create a reversal with `mode=partial` by specifying a flat after-tax amount to refund. The amount distributes across each line item and shipping cost proportionally, depending on the remaining amount left to refund on each. In the example below, the transaction has two line items: one 10 USD item and one 20 USD item, both taxed at 10%. The total amount of the transaction is 33.00 USD. A refund for a flat 16.50 USD is recorded: ```curl curl https://api.stripe.com/v1/tax/transactions/create_reversal \ -u "<>:" \ -d mode=partial \ -d original_transaction=tax_1NVcKqBUZ691iUZ4xMZtcGYt \ -d reference=pi_234567890-refund_1 \ -d flat_amount=-1650 \ -d "metadata[refund]"="{{REFUND_ID}}" \ --data-urlencode "metadata[refund_reason]"="Refunded $16.50 of pi_234567890 (customer was unhappy)" \ -d "expand[]"=line_items ``` ```cli stripe tax transactions create_reversal \ --mode=partial \ --original-transaction=tax_1NVcKqBUZ691iUZ4xMZtcGYt \ --reference=pi_234567890-refund_1 \ --flat-amount=-1650 \ -d "metadata[refund]"="{{REFUND_ID}}" \ -d "metadata[refund_reason]"="Refunded $16.50 of pi_234567890 (customer was unhappy)" \ -d "expand[0]"=line_items ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") transaction = client.v1.tax.transactions.create_reversal({ mode: 'partial', original_transaction: 'tax_1NVcKqBUZ691iUZ4xMZtcGYt', reference: 'pi_234567890-refund_1', flat_amount: -1650, metadata: { refund: '{{REFUND_ID}}', refund_reason: 'Refunded $16.50 of pi_234567890 (customer was unhappy)', }, expand: ['line_items'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. transaction = client.v1.tax.transactions.create_reversal({ "mode": "partial", "original_transaction": "tax_1NVcKqBUZ691iUZ4xMZtcGYt", "reference": "pi_234567890-refund_1", "flat_amount": -1650, "metadata": { "refund": "{{REFUND_ID}}", "refund_reason": "Refunded $16.50 of pi_234567890 (customer was unhappy)", }, "expand": ["line_items"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $transaction = $stripe->tax->transactions->createReversal([ 'mode' => 'partial', 'original_transaction' => 'tax_1NVcKqBUZ691iUZ4xMZtcGYt', 'reference' => 'pi_234567890-refund_1', 'flat_amount' => -1650, 'metadata' => [ 'refund' => '{{REFUND_ID}}', 'refund_reason' => 'Refunded $16.50 of pi_234567890 (customer was unhappy)', ], 'expand' => ['line_items'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); TransactionCreateReversalParams params = TransactionCreateReversalParams.builder() .setMode(TransactionCreateReversalParams.Mode.PARTIAL) .setOriginalTransaction("tax_1NVcKqBUZ691iUZ4xMZtcGYt") .setReference("pi_234567890-refund_1") .setFlatAmount(-1650L) .putMetadata("refund", "{{REFUND_ID}}") .putMetadata( "refund_reason", "Refunded $16.50 of pi_234567890 (customer was unhappy)" ) .addExpand("line_items") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Transaction transaction = client.v1().tax().transactions().createReversal(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const transaction = await stripe.tax.transactions.createReversal({ mode: 'partial', original_transaction: 'tax_1NVcKqBUZ691iUZ4xMZtcGYt', reference: 'pi_234567890-refund_1', flat_amount: -1650, metadata: { refund: '{{REFUND_ID}}', refund_reason: 'Refunded $16.50 of pi_234567890 (customer was unhappy)', }, expand: ['line_items'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxTransactionCreateReversalParams{ Mode: stripe.String("partial"), OriginalTransaction: stripe.String("tax_1NVcKqBUZ691iUZ4xMZtcGYt"), Reference: stripe.String("pi_234567890-refund_1"), FlatAmount: stripe.Int64(-1650), } params.AddMetadata("refund", "{{REFUND_ID}}") params.AddMetadata( "refund_reason", "Refunded $16.50 of pi_234567890 (customer was unhappy)") params.AddExpand("line_items") result, err := sc.V1TaxTransactions.CreateReversal(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.TransactionCreateReversalOptions { Mode = "partial", OriginalTransaction = "tax_1NVcKqBUZ691iUZ4xMZtcGYt", Reference = "pi_234567890-refund_1", FlatAmount = -1650, Metadata = new Dictionary { { "refund", "{{REFUND_ID}}" }, { "refund_reason", "Refunded $16.50 of pi_234567890 (customer was unhappy)" }, }, Expand = new List { "line_items" }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Transactions; Stripe.Tax.Transaction transaction = service.CreateReversal(options); ``` This returns the partial reversal transaction that’s created: ```json { "id": "tax_1NVcQYBUZ691iUZ4SBPukGa6", "object": "tax.transaction", "created": 1689780994, "currency": "usd", ... "line_items": { "object": "list", "data": [ { "id": "tax_li_OICqymcWjlbevq", "object": "tax.transaction_line_item", "amount": -500, "amount_tax": -50, "livemode": false, "metadata": {}, "product": null, "quantity": 1, "reference": "refund_li_1", "reversal": { "original_line_item": "tax_li_OICmRXkFuWr8Df" }, "tax_behavior": "exclusive", "tax_code": "txcd_10103000", "type": "reversal" }, { "id": "tax_li_OICq2H1qHjwyzX", "object": "tax.transaction_line_item", "amount": -1000, "amount_tax": -100, "livemode": false, "metadata": {}, "product": null, "quantity": 1, "reference": "refund_li_2", "reversal": { "original_line_item": "tax_li_OICmxhnSJxF7rY" }, "tax_behavior": "exclusive", "tax_code": "txcd_10103000", "type": "reversal" } ], "has_more": false, "total_count": 2, "url": "/v1/tax/transactions/tax_1NVcQYBUZ691iUZ4SBPukGa6/line_items" }, "livemode": false, "metadata": { "refund": "{{REFUND_ID}}", "description": "Refunding pi_234567890 (customer was unhappy)" }, "reference": "pi_234567890-refund_1", "reversal": { "original_transaction": "tax_1NVcKqBUZ691iUZ4xMZtcGYt" }, "shipping_cost": null, "tax_date": 1670863654, "type": "reversal" } ``` For each line item and shipping cost in the original transaction, the refunded amounts and tax are calculated as follows: 1. First, we calculate the total remaining funds in the transaction available to refund. Because this transaction hasn’t had any other reversals recorded, the total amount is 33.00 USD. 1. Next, we calculate the total amount to refund for each line item. We base this calculation on the proportion of the item’s total available amount to refund versus the total remaining amount of the transaction. For example, the 10 USD item, which has 11.00 USD total remaining to refund, represents 33.33% of the transaction’s remaining total, so the total amount to refund is `-16.50 USD * 33.33% = -5.50 USD`. 1. Finally, the total amount to refund is divided between `amount` and `amount_tax`. We also do this proportionally, depending on how much tax is available to refund in the line item compared to the total funds left to refund. Using the 10 USD item example, tax (1.00 USD) represents 9.09% of the total remaining to refund (11.00 USD), so the `amount_tax` is `-5.50 USD * 9.09% = -0.50 USD`. The flat amount distributes according to what’s *left* to refund in the transaction, not what was originally recorded. For example, instead of recording a refund for a flat 16.50 USD, you first record a partial reversal for the total amount of the 10 USD item: ```curl curl https://api.stripe.com/v1/tax/transactions/create_reversal \ -u "<>:" \ -d mode=partial \ -d original_transaction=tax_1NVcKqBUZ691iUZ4xMZtcGYt \ -d reference=pi_234567890-refund_1 \ -d "line_items[0][original_line_item]"=tax_li_OICmRXkFuWr8Df \ -d "line_items[0][reference]"=partial_refund_l1 \ -d "line_items[0][amount]"=-1000 \ -d "line_items[0][amount_tax]"=-100 \ -d "metadata[refund]"="{{REFUND_ID}}" \ --data-urlencode "metadata[refund_reason]"="Refunded line 1 of pi_234567890 (customer was unhappy)" \ -d "expand[0]"=line_items ``` ```cli stripe tax transactions create_reversal \ --mode=partial \ --original-transaction=tax_1NVcKqBUZ691iUZ4xMZtcGYt \ --reference=pi_234567890-refund_1 \ -d "line_items[0][original_line_item]"=tax_li_OICmRXkFuWr8Df \ -d "line_items[0][reference]"=partial_refund_l1 \ -d "line_items[0][amount]"=-1000 \ -d "line_items[0][amount_tax]"=-100 \ -d "metadata[refund]"="{{REFUND_ID}}" \ -d "metadata[refund_reason]"="Refunded line 1 of pi_234567890 (customer was unhappy)" \ -d "expand[0]"=line_items ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") transaction = client.v1.tax.transactions.create_reversal({ mode: 'partial', original_transaction: 'tax_1NVcKqBUZ691iUZ4xMZtcGYt', reference: 'pi_234567890-refund_1', line_items: [ { original_line_item: 'tax_li_OICmRXkFuWr8Df', reference: 'partial_refund_l1', amount: -1000, amount_tax: -100, }, ], metadata: { refund: '{{REFUND_ID}}', refund_reason: 'Refunded line 1 of pi_234567890 (customer was unhappy)', }, expand: ['line_items'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. transaction = client.v1.tax.transactions.create_reversal({ "mode": "partial", "original_transaction": "tax_1NVcKqBUZ691iUZ4xMZtcGYt", "reference": "pi_234567890-refund_1", "line_items": [ { "original_line_item": "tax_li_OICmRXkFuWr8Df", "reference": "partial_refund_l1", "amount": -1000, "amount_tax": -100, }, ], "metadata": { "refund": "{{REFUND_ID}}", "refund_reason": "Refunded line 1 of pi_234567890 (customer was unhappy)", }, "expand": ["line_items"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $transaction = $stripe->tax->transactions->createReversal([ 'mode' => 'partial', 'original_transaction' => 'tax_1NVcKqBUZ691iUZ4xMZtcGYt', 'reference' => 'pi_234567890-refund_1', 'line_items' => [ [ 'original_line_item' => 'tax_li_OICmRXkFuWr8Df', 'reference' => 'partial_refund_l1', 'amount' => -1000, 'amount_tax' => -100, ], ], 'metadata' => [ 'refund' => '{{REFUND_ID}}', 'refund_reason' => 'Refunded line 1 of pi_234567890 (customer was unhappy)', ], 'expand' => ['line_items'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); TransactionCreateReversalParams params = TransactionCreateReversalParams.builder() .setMode(TransactionCreateReversalParams.Mode.PARTIAL) .setOriginalTransaction("tax_1NVcKqBUZ691iUZ4xMZtcGYt") .setReference("pi_234567890-refund_1") .addLineItem( TransactionCreateReversalParams.LineItem.builder() .setOriginalLineItem("tax_li_OICmRXkFuWr8Df") .setReference("partial_refund_l1") .setAmount(-1000L) .setAmountTax(-100L) .build() ) .putMetadata("refund", "{{REFUND_ID}}") .putMetadata( "refund_reason", "Refunded line 1 of pi_234567890 (customer was unhappy)" ) .addExpand("line_items") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Transaction transaction = client.v1().tax().transactions().createReversal(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const transaction = await stripe.tax.transactions.createReversal({ mode: 'partial', original_transaction: 'tax_1NVcKqBUZ691iUZ4xMZtcGYt', reference: 'pi_234567890-refund_1', line_items: [ { original_line_item: 'tax_li_OICmRXkFuWr8Df', reference: 'partial_refund_l1', amount: -1000, amount_tax: -100, }, ], metadata: { refund: '{{REFUND_ID}}', refund_reason: 'Refunded line 1 of pi_234567890 (customer was unhappy)', }, expand: ['line_items'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxTransactionCreateReversalParams{ Mode: stripe.String("partial"), OriginalTransaction: stripe.String("tax_1NVcKqBUZ691iUZ4xMZtcGYt"), Reference: stripe.String("pi_234567890-refund_1"), LineItems: []*stripe.TaxTransactionCreateReversalLineItemParams{ &stripe.TaxTransactionCreateReversalLineItemParams{ OriginalLineItem: stripe.String("tax_li_OICmRXkFuWr8Df"), Reference: stripe.String("partial_refund_l1"), Amount: stripe.Int64(-1000), AmountTax: stripe.Int64(-100), }, }, } params.AddMetadata("refund", "{{REFUND_ID}}") params.AddMetadata( "refund_reason", "Refunded line 1 of pi_234567890 (customer was unhappy)") params.AddExpand("line_items") result, err := sc.V1TaxTransactions.CreateReversal(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.TransactionCreateReversalOptions { Mode = "partial", OriginalTransaction = "tax_1NVcKqBUZ691iUZ4xMZtcGYt", Reference = "pi_234567890-refund_1", LineItems = new List { new Stripe.Tax.TransactionLineItemOptions { OriginalLineItem = "tax_li_OICmRXkFuWr8Df", Reference = "partial_refund_l1", Amount = -1000, AmountTax = -100, }, }, Metadata = new Dictionary { { "refund", "{{REFUND_ID}}" }, { "refund_reason", "Refunded line 1 of pi_234567890 (customer was unhappy)" }, }, Expand = new List { "line_items" }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Transactions; Stripe.Tax.Transaction transaction = service.CreateReversal(options); ``` After this, you record a 16.50 USD flat amount reversal: ```curl curl https://api.stripe.com/v1/tax/transactions/create_reversal \ -u "<>:" \ -d mode=partial \ -d original_transaction=tax_1NVcKqBUZ691iUZ4xMZtcGYt \ -d reference=pi_234567890-refund_2 \ -d flat_amount=-1650 \ -d "metadata[refund]"="{{REFUND_ID}}" \ --data-urlencode "metadata[refund_reason]"="Refunded $16.50 of pi_234567890 (customer was still unhappy)" \ -d "expand[]"=line_items ``` ```cli stripe tax transactions create_reversal \ --mode=partial \ --original-transaction=tax_1NVcKqBUZ691iUZ4xMZtcGYt \ --reference=pi_234567890-refund_2 \ --flat-amount=-1650 \ -d "metadata[refund]"="{{REFUND_ID}}" \ -d "metadata[refund_reason]"="Refunded $16.50 of pi_234567890 (customer was still unhappy)" \ -d "expand[0]"=line_items ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") transaction = client.v1.tax.transactions.create_reversal({ mode: 'partial', original_transaction: 'tax_1NVcKqBUZ691iUZ4xMZtcGYt', reference: 'pi_234567890-refund_2', flat_amount: -1650, metadata: { refund: '{{REFUND_ID}}', refund_reason: 'Refunded $16.50 of pi_234567890 (customer was still unhappy)', }, expand: ['line_items'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. transaction = client.v1.tax.transactions.create_reversal({ "mode": "partial", "original_transaction": "tax_1NVcKqBUZ691iUZ4xMZtcGYt", "reference": "pi_234567890-refund_2", "flat_amount": -1650, "metadata": { "refund": "{{REFUND_ID}}", "refund_reason": "Refunded $16.50 of pi_234567890 (customer was still unhappy)", }, "expand": ["line_items"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $transaction = $stripe->tax->transactions->createReversal([ 'mode' => 'partial', 'original_transaction' => 'tax_1NVcKqBUZ691iUZ4xMZtcGYt', 'reference' => 'pi_234567890-refund_2', 'flat_amount' => -1650, 'metadata' => [ 'refund' => '{{REFUND_ID}}', 'refund_reason' => 'Refunded $16.50 of pi_234567890 (customer was still unhappy)', ], 'expand' => ['line_items'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); TransactionCreateReversalParams params = TransactionCreateReversalParams.builder() .setMode(TransactionCreateReversalParams.Mode.PARTIAL) .setOriginalTransaction("tax_1NVcKqBUZ691iUZ4xMZtcGYt") .setReference("pi_234567890-refund_2") .setFlatAmount(-1650L) .putMetadata("refund", "{{REFUND_ID}}") .putMetadata( "refund_reason", "Refunded $16.50 of pi_234567890 (customer was still unhappy)" ) .addExpand("line_items") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Transaction transaction = client.v1().tax().transactions().createReversal(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const transaction = await stripe.tax.transactions.createReversal({ mode: 'partial', original_transaction: 'tax_1NVcKqBUZ691iUZ4xMZtcGYt', reference: 'pi_234567890-refund_2', flat_amount: -1650, metadata: { refund: '{{REFUND_ID}}', refund_reason: 'Refunded $16.50 of pi_234567890 (customer was still unhappy)', }, expand: ['line_items'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxTransactionCreateReversalParams{ Mode: stripe.String("partial"), OriginalTransaction: stripe.String("tax_1NVcKqBUZ691iUZ4xMZtcGYt"), Reference: stripe.String("pi_234567890-refund_2"), FlatAmount: stripe.Int64(-1650), } params.AddMetadata("refund", "{{REFUND_ID}}") params.AddMetadata( "refund_reason", "Refunded $16.50 of pi_234567890 (customer was still unhappy)") params.AddExpand("line_items") result, err := sc.V1TaxTransactions.CreateReversal(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.TransactionCreateReversalOptions { Mode = "partial", OriginalTransaction = "tax_1NVcKqBUZ691iUZ4xMZtcGYt", Reference = "pi_234567890-refund_2", FlatAmount = -1650, Metadata = new Dictionary { { "refund", "{{REFUND_ID}}" }, { "refund_reason", "Refunded $16.50 of pi_234567890 (customer was still unhappy)" }, }, Expand = new List { "line_items" }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Transactions; Stripe.Tax.Transaction transaction = service.CreateReversal(options); ``` This returns the partial reversal transaction: ```json { "id": "tax_1NVxFIBUZ691iUZ4saOIloxB", "object": "tax.transaction", "created": 1689861020, "currency": "usd", ... "line_items": { "object": "list", "data": [ { "id": "tax_li_OIYM8xd8BzrATd", "object": "tax.transaction_line_item", "amount": 0, "amount_tax": 0, "livemode": false, "metadata": {}, "product": null, "quantity": 1, "reference": "refund_li_1", "reversal": { "original_line_item": "tax_li_OICmRXkFuWr8Df" }, "tax_behavior": "exclusive", "tax_code": "txcd_10103000", "type": "reversal" }, { "id": "tax_li_OIYMNBH6s8oQj9", "object": "tax.transaction_line_item", "amount": -1500, "amount_tax": -150, "livemode": false, "metadata": {}, "product": null, "quantity": 1, "reference": "refund_li_2", "reversal": { "original_line_item": "tax_li_OICmxhnSJxF7rY" }, "tax_behavior": "exclusive", "tax_code": "txcd_10103000", "type": "reversal" } ], "has_more": false, "total_count": 2, "url": "/v1/tax/transactions/tax_1NVxFIBUZ691iUZ4saOIloxB/line_items" }, "livemode": false, "metadata": {}, "reference": "pi_234567890-refund_2", "reversal": { "original_transaction": "tax_1NVcKqBUZ691iUZ4xMZtcGYt" }, "shipping_cost": null, "tax_date": 1670863654, "type": "reversal" } ``` Because the total amount remaining in the transaction is now 22.00 USD and the 10 USD item is completely refunded, the 16.50 USD distributes entirely to the 20 USD item. The 16.50 USD then distributes, using the logic from step 3, into `amount = -15.00 USD` and `amount_tax = -1.50 USD`. Meanwhile, the 10 USD item in the transaction records a refund of 0 USD. ### Undo a partial refund Tax transactions are immutable, but you can cancel a partial refund by creating a [full reversal](https://docs.stripe.com/api/tax/transactions/create_reversal.md#tax_transaction_create_reversal-mode). You might need to do this when: - The payment [refund fails](https://docs.stripe.com/refunds.md#failed-refunds) and you haven’t provided the good or service to your customer - The wrong order is refunded or the wrong amounts are refunded - The original sale is fully refunded and the partial refunds are no longer valid In the example below, `tax_1MEFACI6rIcR421eHrjXCSmD` is the transaction that represents the partial refund: ```curl curl https://api.stripe.com/v1/tax/transactions/create_reversal \ -u "<>:" \ -d mode=full \ -d original_transaction=tax_1MEFACI6rIcR421eHrjXCSmD \ -d reference=pi_123456789-refund_1-cancel \ -d "metadata[refund_reason]"="User called to cancel because they selected the wrong item" \ -d "expand[]"=line_items ``` ```cli stripe tax transactions create_reversal \ --mode=full \ --original-transaction=tax_1MEFACI6rIcR421eHrjXCSmD \ --reference=pi_123456789-refund_1-cancel \ -d "metadata[refund_reason]"="User called to cancel because they selected the wrong item" \ -d "expand[0]"=line_items ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") transaction = client.v1.tax.transactions.create_reversal({ mode: 'full', original_transaction: 'tax_1MEFACI6rIcR421eHrjXCSmD', reference: 'pi_123456789-refund_1-cancel', metadata: {refund_reason: 'User called to cancel because they selected the wrong item'}, expand: ['line_items'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. transaction = client.v1.tax.transactions.create_reversal({ "mode": "full", "original_transaction": "tax_1MEFACI6rIcR421eHrjXCSmD", "reference": "pi_123456789-refund_1-cancel", "metadata": { "refund_reason": "User called to cancel because they selected the wrong item", }, "expand": ["line_items"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $transaction = $stripe->tax->transactions->createReversal([ 'mode' => 'full', 'original_transaction' => 'tax_1MEFACI6rIcR421eHrjXCSmD', 'reference' => 'pi_123456789-refund_1-cancel', 'metadata' => [ 'refund_reason' => 'User called to cancel because they selected the wrong item', ], 'expand' => ['line_items'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); TransactionCreateReversalParams params = TransactionCreateReversalParams.builder() .setMode(TransactionCreateReversalParams.Mode.FULL) .setOriginalTransaction("tax_1MEFACI6rIcR421eHrjXCSmD") .setReference("pi_123456789-refund_1-cancel") .putMetadata( "refund_reason", "User called to cancel because they selected the wrong item" ) .addExpand("line_items") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Transaction transaction = client.v1().tax().transactions().createReversal(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const transaction = await stripe.tax.transactions.createReversal({ mode: 'full', original_transaction: 'tax_1MEFACI6rIcR421eHrjXCSmD', reference: 'pi_123456789-refund_1-cancel', metadata: { refund_reason: 'User called to cancel because they selected the wrong item', }, expand: ['line_items'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxTransactionCreateReversalParams{ Mode: stripe.String("full"), OriginalTransaction: stripe.String("tax_1MEFACI6rIcR421eHrjXCSmD"), Reference: stripe.String("pi_123456789-refund_1-cancel"), } params.AddMetadata( "refund_reason", "User called to cancel because they selected the wrong item") params.AddExpand("line_items") result, err := sc.V1TaxTransactions.CreateReversal(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.TransactionCreateReversalOptions { Mode = "full", OriginalTransaction = "tax_1MEFACI6rIcR421eHrjXCSmD", Reference = "pi_123456789-refund_1-cancel", Metadata = new Dictionary { { "refund_reason", "User called to cancel because they selected the wrong item" }, }, Expand = new List { "line_items" }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Transactions; Stripe.Tax.Transaction transaction = service.CreateReversal(options); ``` This returns the full reversal transaction that’s created: ```json { "id": "tax_1MEFADI6rIcR421e94fNTOCK", "object": "tax.transaction", "created": 1670863657, "currency": "eur", ... "line_items": { "object": "list", "data": [ { "id": "tax_li_MyBXMOlwenCyFB", "object": "tax.transaction_line_item", "amount": 4999, "amount_tax": 1150, "livemode": false, "metadata": { }, "quantity": 1, "reference": "L1", "reversal": { "original_line_item": "tax_li_MyBXC98AhtaR37" }, "tax_behavior": "exclusive", "tax_code": "txcd_10000000", "type": "reversal" } ], "has_more": false, "total_count": 1, "url": "/v1/tax/transactions/tax_1MEFADI6rIcR421e94fNTOCK/line_items" }, "livemode": false, "metadata": { "refund_reason": "User called to cancel because they picked the wrong item" }, "reference": "pi_123456789-refund_1-cancel", "reversal": { "original_transaction": "tax_1MEFACI6rIcR421eHrjXCSmD" }, "shipping_cost": null, "tax_date": 1670863654, "type": "reversal" } ``` ## Testing Use *sandboxes* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes), which is identical in response structure to live mode, to confirm your integration works correctly before going live. > In testing environments, calculations aren’t guaranteed to return up-to-date taxation results. You’re limited to 1,000 tax calculations per day. If you need a higher limit, contact [Stripe support](https://support.stripe.com/contact). For guidance on automated testing and strategies to avoid rate limits in testing environments, see [Automated testing](https://docs.stripe.com/automated-testing.md). ## View tax transactions You can view all tax transactions for your account on the [Tax Transactions](https://dashboard.stripe.com/test/tax/transactions) page in the Dashboard. Click an individual transaction to see a detailed breakdown of calculated tax by jurisdiction, and by the individual products included in the transaction. > The Tax Transactions page only includes *transactions* and not *calculations*. If you expect to see a calculation and can’t find it on this page, verify that you successfully [created a tax transaction](https://docs.stripe.com/tax/custom.md#tax-transaction) from the calculation. ## Optional: Integration examples You can calculate tax for your customer before collecting payment method details and [creating a PaymentIntent](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=paymentintents#web-create-intent). For example, you can display a shopping cart total when the customer provides their postal code. In the example below, your server defines a `/preview-cart` endpoint, where the customer’s address is sent from your client-side form. The server combines the cart’s line items and the customer’s address to calculate tax. #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const express = require('express'); const app = express(); // Parse the request body as JSON. app.use(express.json()); app.post('/preview-cart', async (req, res) => { const cart = ...; // Load the cart/order from your system // Convert each cart item to a Stripe line item object const lineItems = cart.items.map( cartItem => ({ reference: cartItem.id, amount: cartItem.unitPrice * cartItem.quantity, quantity: cartItem.quantity }) ); // Get the customer's address from the request body const address = req.body.address; // Create a tax calculation using the Stripe API const calculation = await stripe.tax.calculations.create({ currency: cart.currency, line_items: lineItems, customer_details: { address: { line1: address.line1, city: address.city, state: address.state, postal_code: address.postal_code, country: address.country, }, address_source: "billing" }, expand: ['line_items.data.tax_breakdown'] }); // Return the tax amount as a JSON response res.json({ tax_amount: calculation.tax_amount_exclusive }); }); app.listen(4242, () => { console.log('Running on port 4242'); }); ``` #### Java ```java package com.stripe.sample; import static spark.Spark.post; import static spark.Spark.port; import static spark.Spark.staticFiles; import com.stripe.Stripe; import com.stripe.exception.StripeException; import com.stripe.model.tax.Calculation; import com.stripe.param.tax.CalculationCreateParams; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Server { public static void main(String[] args) throws StripeException { port(4242); // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; post("/preview-cart", (request, response) -> { var cart = ...; // Load the cart/order from your system // Convert each cart item to a Stripe line item object List lineItems = cart.getItems().stream() .map(cartItem -> CalculationCreateParams.LineItem .builder() .setReference(cartItem.id()) .setAmount(cartItem.unitPrice() * cartItem.quantity()) .setQuantity(cartItem.quantity()) .build()).collect(Collectors.toList()); // Get the customer's address from the request body var userAddress = ...; // Convert the customer's address to a Stripe customer address object CalculationCreateParams.CustomerDetails.Address address = CalculationCreateParams.CustomerDetails.Address .builder() .setLine1(userAddress.getLine1()) .setLine2(userAddress.getLine2()) .setCity(userAddress.getCity()) .setCountry(userAddress.getCountry()) .setPostalCode(userAddress.getPostalCode()) .build(); // Create a tax calculation using the Stripe API CalculationCreateParams params = CalculationCreateParams .builder() .setCurrency(cart.getCurrency()) .addAllLineItem(lineItems) .setCustomerDetails( CalculationCreateParams.CustomerDetails .builder() .setAddress(address) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.BILLING) .build() ) .addExpand("line_items.data.tax_breakdown") .build(); Calculation calculation = Calculation.create(params); // Return the tax amount as a JSON response return Map.of( "tax_amount", calculation.getTaxAmountExclusive() ); } } } ``` #### Ruby ```ruby require 'stripe' require 'sinatra' # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' set :static, true set :port, 4242 post '/preview-cart' do payload = JSON.parse(request.body.read) # Parse the request body as JSON. cart = ... # Load the cart/order from your system # Convert each cart item to a Stripe line item object line_items = cart.items.map do |cart_item| { reference: cart_item.id, amount: cart_item.unit_price * cart_item.quantity, quantity: cart_item.quantity } end # Get the customer's address from the request body address = payload['address'] # Create a tax calculation using the Stripe API calculation = Stripe::Tax::Calculation.create({ currency: cart.currency, line_items: line_items, customer_details: { address: { line1: address['line1'], line2: address['line2'], city: address['city'], state: address['state'], postal_code: address['postal_code'], country: address['country'], }, address_source: 'billing', }, expand: ['line_items.data.tax_breakdown'], }) # Return the tax amount as a JSON response { tax_amount: calculation.tax_amount_exclusive }.to_json end ``` #### PHP ```php >'); $app->post('/preview-cart', function($request, $response) { $cart = ...; // Load the cart/order from your system // Convert each cart item to a Stripe line item object $lineItems = array_map(fn($cartItem) => [ 'reference' => $cartItem->id, 'amount' => $cartItem->quantity * $cartItem->unitPrice, 'quantity' => $cartItem->quantity, ], $cart->getItems()); // Get the customer's address from the request body $address = $request->getParsedBody()['address']; // Create a tax calculation using the Stripe API $calculation = $stripe->tax->calculations->create([ 'currency' => $cart->currency, 'line_items' => $line_items, 'customer_details' => [ 'address' => [ 'line1' => $address['line1'], 'line2' => $address['line2'], 'city' => $address['city'], 'state' => $address['state'], 'postal_code' => $address['postal_code'], 'country' => $address['country'], ], 'address_source' => 'billing', ], 'expand' => ['line_items.data.tax_breakdown'], ]); # Return the tax amount as a JSON response return $response->withJson([ 'tax_amount' => $calculation->tax_amount_exclusive ]); }); ``` #### Python ```python from flask import Flask, request import stripe # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' app = Flask(__name__, static_url_path='', static_folder='public') @app.route('/preview-cart', methods=['POST']) def preview_cart(): # Load the cart/order from your system cart = ... # Convert each cart item to a Stripe line item object line_items = [{ 'reference': cart_item.id, 'amount': cart_item.unit_price * cart_item.quantity, 'quantity': cart_item.quantity } for cart_item in cart.items] # Get the customer's address from the request body address = request.json['address'] # Create a tax calculation using the Stripe API calculation = stripe.tax.Calculation.create( currency=cart.currency, line_items=line_items, customer_details={ 'address': { 'line1': address.get('line1', ''), 'line2': address.get('line2', ''), 'city': address.get('city', ''), 'state': address.get('state', ''), 'postal_code': address.get('postal_code', ''), 'country': address.get('country', ''), }, 'address_source': 'billing' }, expand=['line_items.data.tax_breakdown'] ) # Return the tax amount as a JSON response return { 'tax_amount': calculation['tax_amount_exclusive'] } if __name__ == '__main__': app.run(port=4242) ``` #### Go ```go package main import ( "log" "encoding/json" "io/ioutil" "net/http" "github.com/stripe/stripe-go/v74" "github.com/stripe/stripe-go/v74/tax/calculation" "github.com/stripe/stripe-go/v74" ) func main() { // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" http.Handle("/", http.FileServer(http.Dir("public"))) http.HandleFunc("/preview-cart", previewCart) addr := "localhost:4242" log.Printf("Listening on %s", addr) log.Fatal(http.ListenAndServe(addr, nil)) } type RequestBody struct { Address map[string]string `json:"address"` } func previewCart(w http.ResponseWriter, r *http.Request) { cart := ... // Load the cart/order from your system // Convert each cart item to a Stripe line item object var lineItems []*stripe.TaxCalculationLineItemParams for _, cartItem := range cart.Items { item := &stripe.TaxCalculationLineItemParams{ Amount: stripe.Int64(cartItem.UnitPrice * cartItem.Quantity), Reference: stripe.String(cartItem.Id), Quantity: stripe.Int64(cartItem.Quantity), } lineItems = append(lineItems, item) } // Get the customer's address from the request body body, err := ioutil.ReadAll(r.Body) if err != nil { panic(err) } var parsedBody RequestBody err = json.Unmarshal([]byte(body), &parsedBody) if err != nil { http.Error(w, "Invalid address parameter", http.StatusBadRequest) return } address := parsedBody.Address // Create a tax calculation using the Stripe API params := &stripe.TaxCalculationParams{ Currency: stripe.String(cart.Currency), LineItems: lineItems, CustomerDetails: &stripe.TaxCalculationCustomerDetailsParams{ Address: &stripe.AddressParams{ Line1: stripe.String(address["line1"]), Line2: stripe.String(address["line2"]), City: stripe.String(address["city"]), State: stripe.String(address["state"]), PostalCode: stripe.String(address["postal_code"]), Country: stripe.String(address["country"]), }, AddressSource: stripe.String(string(stripe.TaxCalculationCustomerDetailsAddressSourceBilling)), }, }; params.AddExpand("line_items.data.tax_breakdown") result, _ := calculation.New(params); // Return the tax amount as a JSON response data := map[string]interface{}{ "tax_amount": result.TaxAmountExclusive, } json.NewEncoder(w).Encode(data) } ``` #### .NET ```dotnet using System.Collections.Generic; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Stripe; using Stripe.Tax; namespace server.Controllers { public class Program { public static void Main(string[] args) { WebHost.CreateDefaultBuilder(args) .UseUrls("http://0.0.0.0:4242") .UseWebRoot("public") .UseStartup() .Build() .Run(); } } public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc().AddNewtonsoftJson(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); app.UseRouting(); app.UseStaticFiles(); app.UseEndpoints(endpoints => endpoints.MapControllers()); } } [Route("preview-cart")] [ApiController] public class PreviewCartController : Controller { [HttpPost] public ActionResult Preview([FromBody] Address address) { var cart = ...; // Load the cart/order from your system // Convert each cart item to a Stripe line item object var lineItems = new List(); foreach (var cartItem in cart.Items) { lineItems.Add(new CalculationLineItemOptions { Reference = cartItem.Id, Amount = cartItem.Quantity * cartItem.UnitPrice, Quantity = cartItem.Quantity }); } // Create a tax calculation using the Stripe API var options = new CalculationCreateOptions { Currency = cart.Currency, LineItems = LineItems, CustomerDetails = new CalculationCustomerDetailsOptions { Address = new AddressOptions { Line1 = address.Line1, Line2 = address.Line2, City = address.City, State = address.State, PostalCode = address.PostalCode, Country = address.Country, }, AddressSource = "billing", }, Expand = new List { "line_items.data.tax_breakdown" }, }; var service = new CalculationService(); var calculation = service.Create(options); // Return the tax amount as a JSON response var preview = new Dictionary { { "tax_amount", calculation.TaxAmountExclusive }, }; return Json(preview); } } } ``` When you’re ready to take payment, create a PaymentIntent from the tax calculation result. Store the tax calculation ID in the PaymentIntent’s [metadata](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-metadata) or in your own database, so you can create a tax transaction when your customer completes payment. The example below shows a server endpoint that calculates tax, creates (or updates) a PaymentIntent, and returns the result to the client. You can then display the tax to your customer. Use the `client_secret` to [take the payment](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=paymentintents#web-collect-payment-details). #### Node.js ```javascript // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const express = require('express'); const app = express(); // Parse the request body as JSON. app.use(express.json()); app.post('/calculate-cart', async (req, res) => { const cart = ...; // Load the cart/order from your system // Create a tax calculation using the Stripe API const calculation = await stripe.tax.calculations.create(...); let paymentIntent; // Update the PaymentIntent if one already exists for this cart. if (cart.paymentIntent) { paymentIntent = await stripe.paymentIntents.update(cart.paymentIntent, { amount: calculation.amount_total, metadata: {tax_calculation: calculation.id}, }); } else { paymentIntent = await stripe.paymentIntents.create({ currency: cart.currency, amount: calculation.amount_total, metadata: {tax_calculation: calculation.id}, // In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. automatic_payment_methods: {enabled: true}, }); } // Store PaymentIntent ID in cart or customer session. cart.paymentIntent = paymentIntent.id; // Return calculated amounts and PaymentIntent secret to the client. res.json({ total: calculation.amount_total, tax_amount: calculation.tax_amount_exclusive, client_secret: paymentIntent.client_secret }); }); app.listen(4242, () => { console.log('Running on port 4242'); }); ``` #### Java ```java package com.stripe.sample; import static spark.Spark.post; import static spark.Spark.port; import static spark.Spark.staticFiles; import com.stripe.Stripe; import com.stripe.exception.StripeException; import com.stripe.model.PaymentIntent; import com.stripe.model.tax.Calculation; import com.stripe.param.PaymentIntentCreateParams; import com.stripe.param.PaymentIntentUpdateParams; import com.stripe.param.tax.CalculationCreateParams; public class Server { public static void main(String[] args) throws StripeException { port(4242); // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys Stripe.apiKey = "<>"; post("/calculate-cart", (request, response) -> { var cart = ...; // Load the cart/order from your system // Create a tax calculation using the Stripe API CalculationCreateParams params = ...; Calculation calculation = Calculation.create(params); PaymentIntent paymentIntent; // Update the PaymentIntent if one already exists for this cart. if (cart.paymentIntent != null){ paymentIntent = PaymentIntent.retrieve(cart.paymentIntent); PaymentIntentUpdateParams params = PaymentIntentUpdateParams.builder() .setAmount(calculation.getAmountTotal()) .putMetadata("tax_calculation", calculation.getId()) .build(); paymentIntent = paymentIntent.update(params); } else { PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(calculation.getAmountTotal()) .setCurrency(cart.getCurrency()) // In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. .setAutomaticPaymentMethods( PaymentIntentCreateParams.AutomaticPaymentMethods.builder() .setEnabled(true) .build() ) .putMetadata("tax_calculation", calculation.getId()) .build(); paymentIntent = PaymentIntent.create(params); } // Store PaymentIntent ID in cart or customer session. cart.setPaymentIntent(paymentIntent.getId()); return Map.of( "total", calculation.getAmountTotal(), "tax_amount", calculation.getTaxAmountExclusive(), "client_secret", paymentIntent.getClientSecret() ); }); } } ``` #### Ruby ```ruby require 'stripe' require 'sinatra' # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = '<>' set :static, true set :port, 4242 post '/calculate-cart' do cart = ... # Load the cart/order from your system # Create a tax calculation using the Stripe API calculation = Stripe::Tax::Calculation.create(...) # Update the PaymentIntent if one already exists for this cart. if cart.payment_intent.present? payment_intent = Stripe::PaymentIntent.update( cart.payment_intent, { amount: calculation.amount_total, metadata: {tax_calculation: calculation.id}, }, ) else payment_intent = Stripe::PaymentIntent.create({ amount: calculation.amount_total, currency: cart.currency, # In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. automatic_payment_methods: {enabled: true}, metadata: {tax_calculation: calculation.id}, }) end # Store PaymentIntent ID in cart or customer session. cart.payment_intent = payment_intent.id # Return calculated amounts and PaymentIntent secret to the client. result = { total: calculation.amount_total, tax_amount: calculation.tax_amount_exclusive, client_secret: payment_intent.client_secret } result.to_json end ``` #### PHP ```php >'); $app->post('/calculate-cart', function($request, $response) { $cart = $body['cart']; // Load the cart/order from your system // Create a tax calculation using the Stripe API $calculation = $stripe->tax->calculations->create(...) // Update the PaymentIntent if one already exists for this cart. if ($cart->paymentIntent) { $paymentIntent = $stripe->paymentIntents->update($cart->paymentIntent, [ 'amount' => $calculation->amount_total, 'metadata' => [ 'tax_calculation' => $calculation->id ] ]); } else { $paymentIntent = $stripe->paymentIntents->create([ 'amount' => $calculation->amount_total, 'currency' => $cart->currency, // In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. 'automatic_payment_methods' => [ 'enabled' => true, ], 'metadata' => [ 'tax_calculation' => $calculation->id ] ]); } // Store PaymentIntent ID in cart or customer session. $cart->paymentIntent = $paymentIntent->id; // Return calculated amounts and PaymentIntent secret to the client. return $response->withJson([ 'total' => $calculation->amount_total, 'tax_amount' => $calculation->tax_amount_exclusive, 'client_secret' => $calculation->client_secret ]); }); ``` #### Python ```python import os from flask import Flask, request import stripe # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys stripe.api_key = '<>' app = Flask(__name__, static_url_path='', static_folder='public') @app.route('/calculate-cart', methods=['POST']) def calculate_cart(): # Load the cart/order from your system cart = ... # Create a tax calculation using the Stripe API calculation = stripe.tax.Calculation.create( #... ) payment_intent = None # Update the PaymentIntent if one already exists for this cart. if cart.payment_intent: payment_intent = stripe.PaymentIntent.modify( cart.payment_intent, amount=calculation.amount_total, metadata={"tax_calculation": calculation.id}, ) else: payment_intent = stripe.PaymentIntent.create( amount=calculation.amount_total, currency=cart.currency, # In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. automatic_payment_methods={"enabled": True}, metadata={"tax_calculation": calculation.id}, ) # Store PaymentIntent ID in cart or customer session. cart.payment_intent = payment_intent.id # Return calculated amounts and PaymentIntent secret to the client. return { 'total': calculation.amount_total, 'tax_amount': calculation.tax_amount_exclusive, 'client_secret': payment_intent.client_secret } if __name__ == '__main__': app.run(port=4242) ``` #### Go ```go package main import ( "log" "encoding/json" "net/http" "github.com/stripe/stripe-go/v74" "github.com/stripe/stripe-go/v74/paymentintent" "github.com/stripe/stripe-go/v74/tax/calculation" ) func main() { // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys stripe.Key = "<>" http.Handle("/", http.FileServer(http.Dir("public"))) http.HandleFunc("/calculate-cart", calculateCart) addr := "localhost:4242" log.Printf("Listening on %s", addr) log.Fatal(http.ListenAndServe(addr, nil)) } func calculateCart(w http.ResponseWriter, r *http.Request) { cart := ... // Load the cart/order from your system // Create a tax calculation using the Stripe API calculation, _ := calculation.New(...); // Update the PaymentIntent if one already exists for this cart. if cart.PaymentIntent != nil { params := &stripe.PaymentIntentParams{ Amount: &calculation.AmountTotal, } params.AddMetadata("tax_calculation", calculation.ID) pi, _ := paymentintent.Update(cart.PaymentIntent, params,) } else { params := &stripe.PaymentIntentParams{ Currency: stripe.String(string(cart.Currency)), Amount: &calculation.AmountTotal, // In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. AutomaticPaymentMethods: &stripe.PaymentIntentAutomaticPaymentMethodsParams{ Enabled: stripe.Bool(true), }, } params.AddMetadata("tax_calculation", calculation.ID) pi, _ := paymentintent.New(params) } // Store PaymentIntent ID in cart or customer session. cart.SetPaymentIntent(pi.ID) result := map[string]interface{}{ "total": calculation.AmountTotal, "tax_amount": calculation.TaxAmountExclusive, "client_secret": pi.ClientSecret, } json.NewEncoder(w).Encode(result) } ``` #### .NET ```dotnet using System.Collections.Generic; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Stripe; using Stripe.Tax; namespace server.Controllers { public class Program { public static void Main(string[] args) { WebHost.CreateDefaultBuilder(args) .UseUrls("http://0.0.0.0:4242") .UseWebRoot("public") .UseStartup() .Build() .Run(); } } public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc().AddNewtonsoftJson(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeConfiguration.ApiKey = "<>"; if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); app.UseRouting(); app.UseStaticFiles(); app.UseEndpoints(endpoints => endpoints.MapControllers()); } } [Route("calculate-cart")] [ApiController] public class CalculateCartController : Controller { [HttpPost] public ActionResult Calculate([FromBody] Address address) { var cart = ...; // load cart from your system // Create a tax calculation using the Stripe API var taxService = new CalculationService(); var calculation = taxService.Create(...); var paymentService = new PaymentIntentService(); PaymentIntent paymentIntent; // Update the PaymentIntent if one already exists for this cart. if (cart.PaymentIntent != null) { var options = new PaymentIntentUpdateOptions { Amount = calculation.AmountTotal, Metadata = new Dictionary { { "tax_calculation", calculation.Id }, }, }; paymentIntent = paymentService.Update(cart.PaymentIntent, options); } else { var options = new PaymentIntentCreateOptions { Amount = calculation.AmountTotal, Currency = cart.Currency, // In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default. AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions { Enabled = true, }, Metadata = new Dictionary { { "tax_calculation", calculation.Id }, }, }; paymentIntent = paymentService.Create(options); } // Store PaymentIntent ID in cart or customer session. cart.PaymentIntent = paymentIntent.Id; var result = new Dictionary { { "total", calculation.AmountTotal }, { "tax_amount", calculation.TaxAmountExclusive }, { "client_secret", paymentIntent.ClientSecret }, }; return Json(result); } } } ``` If your integration uses the Payment Element, [fetch updates from the server](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=elements&api-integration=paymentintents#fetch-updates) after updating the PaymentIntent. ## Optional: Calculate tax on shipping costs [Server-side] To calculate tax on shipping costs, use the `shipping_cost` parameter: ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping \ -d "shipping_cost[amount]"=500 \ -d "shipping_cost[tax_code]"=txcd_92010001 ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping \ -d "shipping_cost[amount]"=500 \ -d "shipping_cost[tax_code]"=txcd_92010001 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'shipping', }, shipping_cost: { amount: 500, tax_code: 'txcd_92010001', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1"}], "customer_details": { "address": { "line1": "920 5th Ave", "city": "Seattle", "state": "WA", "postal_code": "98104", "country": "US", }, "address_source": "shipping", }, "shipping_cost": {"amount": 500, "tax_code": "txcd_92010001"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', ], ], 'customer_details' => [ 'address' => [ 'line1' => '920 5th Ave', 'city' => 'Seattle', 'state' => 'WA', 'postal_code' => '98104', 'country' => 'US', ], 'address_source' => 'shipping', ], 'shipping_cost' => [ 'amount' => 500, 'tax_code' => 'txcd_92010001', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setLine1("920 5th Ave") .setCity("Seattle") .setState("WA") .setPostalCode("98104") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.SHIPPING) .build() ) .setShippingCost( CalculationCreateParams.ShippingCost.builder() .setAmount(500L) .setTaxCode("txcd_92010001") .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'shipping', }, shipping_cost: { amount: 500, tax_code: 'txcd_92010001', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ Line1: stripe.String("920 5th Ave"), City: stripe.String("Seattle"), State: stripe.String("WA"), PostalCode: stripe.String("98104"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceShipping), }, ShippingCost: &stripe.TaxCalculationCreateShippingCostParams{ Amount: stripe.Int64(500), TaxCode: stripe.String("txcd_92010001"), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1" }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Line1 = "920 5th Ave", City = "Seattle", State = "WA", PostalCode = "98104", Country = "US", }, AddressSource = "shipping", }, ShippingCost = new Stripe.Tax.CalculationShippingCostOptions { Amount = 500, TaxCode = "txcd_92010001", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` Pass the ID of an existing [ShippingRate](https://docs.stripe.com/api/shipping_rates/object.md) to use its `amount`, `tax_code`, and `tax_behavior`: ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping \ -d "shipping_cost[shipping_rate]"=shr_1Mlh8YI6rIcR421eUr9SJzAD ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping \ -d "shipping_cost[shipping_rate]"=shr_1Mlh8YI6rIcR421eUr9SJzAD ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'shipping', }, shipping_cost: {shipping_rate: 'shr_1Mlh8YI6rIcR421eUr9SJzAD'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1"}], "customer_details": { "address": { "line1": "920 5th Ave", "city": "Seattle", "state": "WA", "postal_code": "98104", "country": "US", }, "address_source": "shipping", }, "shipping_cost": {"shipping_rate": "shr_1Mlh8YI6rIcR421eUr9SJzAD"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', ], ], 'customer_details' => [ 'address' => [ 'line1' => '920 5th Ave', 'city' => 'Seattle', 'state' => 'WA', 'postal_code' => '98104', 'country' => 'US', ], 'address_source' => 'shipping', ], 'shipping_cost' => ['shipping_rate' => 'shr_1Mlh8YI6rIcR421eUr9SJzAD'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setLine1("920 5th Ave") .setCity("Seattle") .setState("WA") .setPostalCode("98104") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.SHIPPING) .build() ) .setShippingCost( CalculationCreateParams.ShippingCost.builder() .setShippingRate("shr_1Mlh8YI6rIcR421eUr9SJzAD") .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'shipping', }, shipping_cost: { shipping_rate: 'shr_1Mlh8YI6rIcR421eUr9SJzAD', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ Line1: stripe.String("920 5th Ave"), City: stripe.String("Seattle"), State: stripe.String("WA"), PostalCode: stripe.String("98104"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceShipping), }, ShippingCost: &stripe.TaxCalculationCreateShippingCostParams{ ShippingRate: stripe.String("shr_1Mlh8YI6rIcR421eUr9SJzAD"), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1" }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Line1 = "920 5th Ave", City = "Seattle", State = "WA", PostalCode = "98104", Country = "US", }, AddressSource = "shipping", }, ShippingCost = new Stripe.Tax.CalculationShippingCostOptions { ShippingRate = "shr_1Mlh8YI6rIcR421eUr9SJzAD", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` ## Optional: Estimate taxes with an IP address [Server-side] If you provide your customer’s [IP address](https://docs.stripe.com/api/tax/calculations/create.md#calculate_tax-customer_details-ip_address), we geolocate it and use that location as your customer’s location. Use this to show your customer a tax estimate before they provide their postal address. > Because the location of an IP address might be some distance from the actual customer location, we recommend against using an IP address to determine the *final* amount of tax to collect. ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[ip_address]"="127.0.0.1" ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[ip_address]"="127.0.0.1" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: {ip_address: '127.0.0.1'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1"}], "customer_details": {"ip_address": "127.0.0.1"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', ], ], 'customer_details' => ['ip_address' => '127.0.0.1'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder().setIpAddress("127.0.0.1").build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { ip_address: '127.0.0.1', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ IPAddress: stripe.String("127.0.0.1"), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1" }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { IpAddress = "127.0.0.1", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` ## Optional: Collect customer tax IDs [Server-side] In some cases, such as the cross-border supply of services, your customer might need to account for tax on a [reverse charge](https://docs.stripe.com/tax/zero-tax.md#reverse-charges) basis. Instead of collecting the tax, you must issue an invoice with the text, “Tax to be paid on reverse charge basis.” This informs your customer that they’re responsible for any tax on their purchase. Provide your customer’s [tax IDs](https://docs.stripe.com/api/tax/calculations/create.md#calculate_tax-customer_details-tax_ids) to automatically determine when reverse charge applies: ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing \ -d "customer_details[tax_ids][0][type]"=eu_vat \ -d "customer_details[tax_ids][0][value]"=DE123456789 ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing \ -d "customer_details[tax_ids][0][type]"=eu_vat \ -d "customer_details[tax_ids][0][value]"=DE123456789 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: {country: 'IE'}, address_source: 'billing', tax_ids: [ { type: 'eu_vat', value: 'DE123456789', }, ], }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1"}], "customer_details": { "address": {"country": "IE"}, "address_source": "billing", "tax_ids": [{"type": "eu_vat", "value": "DE123456789"}], }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', ], ], 'customer_details' => [ 'address' => ['country' => 'IE'], 'address_source' => 'billing', 'tax_ids' => [ [ 'type' => 'eu_vat', 'value' => 'DE123456789', ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setCountry("IE") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.BILLING) .addTaxId( CalculationCreateParams.CustomerDetails.TaxId.builder() .setType(CalculationCreateParams.CustomerDetails.TaxId.Type.EU_VAT) .setValue("DE123456789") .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { country: 'IE', }, address_source: 'billing', tax_ids: [ { type: 'eu_vat', value: 'DE123456789', }, ], }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{Country: stripe.String("IE")}, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceBilling), TaxIDs: []*stripe.TaxCalculationCreateCustomerDetailsTaxIDParams{ &stripe.TaxCalculationCreateCustomerDetailsTaxIDParams{ Type: stripe.String(stripe.TaxCalculationCustomerDetailsTaxIDTypeEUVAT), Value: stripe.String("DE123456789"), }, }, }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1" }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Country = "IE" }, AddressSource = "billing", TaxIds = new List { new Stripe.Tax.CalculationCustomerDetailsTaxIdOptions { Type = "eu_vat", Value = "DE123456789", }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` If you provide a tax ID with an invalid format, the calculation returns a `tax_id_invalid` error code: ```json { "error": { "code": "tax_id_invalid", "doc_url": "https://docs.stripe.com/error-codes#tax-id-invalid", "message": "Invalid value for eu_vat.", "param": "customer_details[tax_ids][0][value]", "type": "invalid_request_error" } } ``` The Tax API doesn’t automatically validate tax IDs against government databases. To validate a tax ID before calculating tax, you must use [customer tax ID validation](https://docs.stripe.com/billing/customer/tax-ids.md#validation). ## Optional: Tax-inclusive pricing [Server-side] By default, tax is calculated on top of the line item and shipping cost amounts you provide. To calculate the tax included in your prices, set the `tax_behavior` to `inclusive` for the [line item](https://docs.stripe.com/api/tax/calculations/create.md#calculate_tax-line_items-tax_behavior) or [shipping cost](https://docs.stripe.com/api/tax/calculations/create.md#calculate_tax-shipping_cost-tax_behavior). In the example below, the customer always pays 100 EUR: ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=eur \ -d "line_items[0][amount]"=10000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=inclusive \ -d "line_items[0][tax_code]"=txcd_10103000 \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing ``` ```cli stripe tax calculations create \ --currency=eur \ -d "line_items[0][amount]"=10000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=inclusive \ -d "line_items[0][tax_code]"=txcd_10103000 \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'eur', line_items: [ { amount: 10000, reference: 'L1', tax_behavior: 'inclusive', tax_code: 'txcd_10103000', }, ], customer_details: { address: {country: 'IE'}, address_source: 'billing', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "eur", "line_items": [ { "amount": 10000, "reference": "L1", "tax_behavior": "inclusive", "tax_code": "txcd_10103000", }, ], "customer_details": {"address": {"country": "IE"}, "address_source": "billing"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'eur', 'line_items' => [ [ 'amount' => 10000, 'reference' => 'L1', 'tax_behavior' => 'inclusive', 'tax_code' => 'txcd_10103000', ], ], 'customer_details' => [ 'address' => ['country' => 'IE'], 'address_source' => 'billing', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("eur") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(10000L) .setReference("L1") .setTaxBehavior(CalculationCreateParams.LineItem.TaxBehavior.INCLUSIVE) .setTaxCode("txcd_10103000") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setCountry("IE") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.BILLING) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'eur', line_items: [ { amount: 10000, reference: 'L1', tax_behavior: 'inclusive', tax_code: 'txcd_10103000', }, ], customer_details: { address: { country: 'IE', }, address_source: 'billing', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyEUR), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(10000), Reference: stripe.String("L1"), TaxBehavior: stripe.String("inclusive"), TaxCode: stripe.String("txcd_10103000"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{Country: stripe.String("IE")}, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceBilling), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "eur", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 10000, Reference = "L1", TaxBehavior = "inclusive", TaxCode = "txcd_10103000", }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Country = "IE" }, AddressSource = "billing", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` The response returns the tax included: ```json { ... "amount_total": 10000, ... "tax_amount_exclusive": 0,"tax_amount_inclusive": 1870, "tax_breakdown": [ { "amount": 1870, "inclusive": true, "tax_rate_details": { "country": "IE", "percentage_decimal": "23.0", "state": null, "tax_type": "vat" }, "taxability_reason": "standard_rated", "taxable_amount": 8130 } ], ... } ``` ## Optional: Use an existing Product object [Server-side] You can provide a [Product](https://docs.stripe.com/api/products/object.md) object for each line item. If the product has a [tax_code](https://docs.stripe.com/api/products/object.md#product_object-tax_code), we use it as the line item’s `tax_code`, if it’s not already populated. We don’t use other product values, including the `tax_behavior` and `price`, during tax calculation. ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][product]"="{{PRODUCT_ID}}" \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][product]"="{{PRODUCT_ID}}" \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', product: '{{PRODUCT_ID}}', }, ], customer_details: { address: {country: 'IE'}, address_source: 'billing', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1", "product": "{{PRODUCT_ID}}"}], "customer_details": {"address": {"country": "IE"}, "address_source": "billing"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', 'product' => '{{PRODUCT_ID}}', ], ], 'customer_details' => [ 'address' => ['country' => 'IE'], 'address_source' => 'billing', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .setProduct("{{PRODUCT_ID}}") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setCountry("IE") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.BILLING) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', product: '{{PRODUCT_ID}}', }, ], customer_details: { address: { country: 'IE', }, address_source: 'billing', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), Product: stripe.String("{{PRODUCT_ID}}"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{Country: stripe.String("IE")}, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceBilling), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1", Product = "{{PRODUCT_ID}}", }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Country = "IE" }, AddressSource = "billing", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` ## Optional: Use an existing Customer object [Server-side] If you provide a [Customer](https://docs.stripe.com/api/customers/object.md) object, we automatically copy and use the customer’s address and tax IDs for the calculation: - If the customer `shipping` is present, it’s copied to `customer_details.address`. - Otherwise, if the customer `address` is present, it’s copied to `customer_details.address`. - Otherwise, if the customer `tax.ip_address` is present, it’s copied to `customer_details.ip_address`. - Otherwise, if the customer `tax.tax_exempt` is present, it’s copied to `customer_details.taxability_override`. The customer’s [tax IDs](https://docs.stripe.com/api/customer_tax_ids.md) are copied to `customer_details.tax_ids`. ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d customer="{{CUSTOMER_ID}}" ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ --customer="{{CUSTOMER_ID}}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer: '{{CUSTOMER_ID}}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1"}], "customer": "{{CUSTOMER_ID}}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', ], ], 'customer' => '{{CUSTOMER_ID}}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .build() ) .setCustomer("{{CUSTOMER_ID}}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer: '{{CUSTOMER_ID}}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), }, }, Customer: stripe.String("{{CUSTOMER_ID}}"), } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1" }, }, Customer = "{{CUSTOMER_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` ## Optional: Override customer taxability [Server-side] You don’t need to collect tax in certain cases, such as when your customer is tax-exempt. You can provide the tax exemption to Stripe Tax using the [taxability_override](https://docs.stripe.com/api/tax/calculations/create.md#calculate_tax-customer_details-taxability_override) parameter. To provide the customer taxability override to your calculations: ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=billing \ -d "customer_details[taxability_override]"=customer_exempt ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=billing \ -d "customer_details[taxability_override]"=customer_exempt ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'billing', taxability_override: 'customer_exempt', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1"}], "customer_details": { "address": { "line1": "920 5th Ave", "city": "Seattle", "state": "WA", "postal_code": "98104", "country": "US", }, "address_source": "billing", "taxability_override": "customer_exempt", }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', ], ], 'customer_details' => [ 'address' => [ 'line1' => '920 5th Ave', 'city' => 'Seattle', 'state' => 'WA', 'postal_code' => '98104', 'country' => 'US', ], 'address_source' => 'billing', 'taxability_override' => 'customer_exempt', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setLine1("920 5th Ave") .setCity("Seattle") .setState("WA") .setPostalCode("98104") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.BILLING) .setTaxabilityOverride( CalculationCreateParams.CustomerDetails.TaxabilityOverride.CUSTOMER_EXEMPT ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'billing', taxability_override: 'customer_exempt', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ Line1: stripe.String("920 5th Ave"), City: stripe.String("Seattle"), State: stripe.String("WA"), PostalCode: stripe.String("98104"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceBilling), TaxabilityOverride: stripe.String(stripe.TaxCalculationCustomerDetailsTaxabilityOverrideCustomerExempt), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1" }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Line1 = "920 5th Ave", City = "Seattle", State = "WA", PostalCode = "98104", Country = "US", }, AddressSource = "billing", TaxabilityOverride = "customer_exempt", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` ### Reverse charge Some regions, such as the European Union, implement a “reverse charge” scheme where the customer is responsible for accounting for tax if they’re purchasing as a business. For Stripe Tax to apply the correct tax treatment, we recommend you collect [Tax IDs](https://docs.stripe.com/tax/custom.md#tax-ids) from your customers. Sometimes you might not have your customer’s tax IDs, or you’ve separately determined that the reverse charge scheme applies. In these types of scenarios, you can use `taxability_override` to force Stripe Tax to apply the reverse charge scheme. To provide the customer taxability override to your calculations: ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=eur \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing \ -d "customer_details[taxability_override]"=reverse_charge ``` ```cli stripe tax calculations create \ --currency=eur \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing \ -d "customer_details[taxability_override]"=reverse_charge ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'eur', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: {country: 'IE'}, address_source: 'billing', taxability_override: 'reverse_charge', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "eur", "line_items": [{"amount": 1000, "reference": "L1"}], "customer_details": { "address": {"country": "IE"}, "address_source": "billing", "taxability_override": "reverse_charge", }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'eur', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', ], ], 'customer_details' => [ 'address' => ['country' => 'IE'], 'address_source' => 'billing', 'taxability_override' => 'reverse_charge', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("eur") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setCountry("IE") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.BILLING) .setTaxabilityOverride( CalculationCreateParams.CustomerDetails.TaxabilityOverride.REVERSE_CHARGE ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'eur', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { country: 'IE', }, address_source: 'billing', taxability_override: 'reverse_charge', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyEUR), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{Country: stripe.String("IE")}, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceBilling), TaxabilityOverride: stripe.String(stripe.TaxCalculationCustomerDetailsTaxabilityOverrideReverseCharge), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "eur", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1" }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Country = "IE" }, AddressSource = "billing", TaxabilityOverride = "reverse_charge", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` ## Optional: Specify a ship-from location [Server-side] If you ship goods from a location other than your main place of business, you can provide that address for tax calculations. To provide a ship-from location, use the `ship_from_details` parameter. In this example, the user is based in Florida, their customer is based in Springfield, IL, and the user is shipping the goods from Naperville, IL: ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=exclusive \ -d "line_items[0][tax_code]"=txcd_99999999 \ -d "customer_details[address][city]"=Springfield \ -d "customer_details[address][state]"=IL \ -d "customer_details[address][postal_code]"=62704 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=billing \ -d "ship_from_details[address][city]"=Naperville \ -d "ship_from_details[address][state]"=IL \ -d "ship_from_details[address][postal_code]"=60540 \ -d "ship_from_details[address][country]"=US ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=exclusive \ -d "line_items[0][tax_code]"=txcd_99999999 \ -d "customer_details[address][city]"=Springfield \ -d "customer_details[address][state]"=IL \ -d "customer_details[address][postal_code]"=62704 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=billing \ -d "ship_from_details[address][city]"=Naperville \ -d "ship_from_details[address][state]"=IL \ -d "ship_from_details[address][postal_code]"=60540 \ -d "ship_from_details[address][country]"=US ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', tax_behavior: 'exclusive', tax_code: 'txcd_99999999', }, ], customer_details: { address: { city: 'Springfield', state: 'IL', postal_code: '62704', country: 'US', }, address_source: 'billing', }, ship_from_details: { address: { city: 'Naperville', state: 'IL', postal_code: '60540', country: 'US', }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [ { "amount": 1000, "reference": "L1", "tax_behavior": "exclusive", "tax_code": "txcd_99999999", }, ], "customer_details": { "address": { "city": "Springfield", "state": "IL", "postal_code": "62704", "country": "US", }, "address_source": "billing", }, "ship_from_details": { "address": { "city": "Naperville", "state": "IL", "postal_code": "60540", "country": "US", }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', 'tax_behavior' => 'exclusive', 'tax_code' => 'txcd_99999999', ], ], 'customer_details' => [ 'address' => [ 'city' => 'Springfield', 'state' => 'IL', 'postal_code' => '62704', 'country' => 'US', ], 'address_source' => 'billing', ], 'ship_from_details' => [ 'address' => [ 'city' => 'Naperville', 'state' => 'IL', 'postal_code' => '60540', 'country' => 'US', ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .setTaxBehavior(CalculationCreateParams.LineItem.TaxBehavior.EXCLUSIVE) .setTaxCode("txcd_99999999") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setCity("Springfield") .setState("IL") .setPostalCode("62704") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.BILLING) .build() ) .setShipFromDetails( CalculationCreateParams.ShipFromDetails.builder() .setAddress( CalculationCreateParams.ShipFromDetails.Address.builder() .setCity("Naperville") .setState("IL") .setPostalCode("60540") .setCountry("US") .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', tax_behavior: 'exclusive', tax_code: 'txcd_99999999', }, ], customer_details: { address: { city: 'Springfield', state: 'IL', postal_code: '62704', country: 'US', }, address_source: 'billing', }, ship_from_details: { address: { city: 'Naperville', state: 'IL', postal_code: '60540', country: 'US', }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), TaxBehavior: stripe.String("exclusive"), TaxCode: stripe.String("txcd_99999999"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ City: stripe.String("Springfield"), State: stripe.String("IL"), PostalCode: stripe.String("62704"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceBilling), }, ShipFromDetails: &stripe.TaxCalculationCreateShipFromDetailsParams{ Address: &stripe.AddressParams{ City: stripe.String("Naperville"), State: stripe.String("IL"), PostalCode: stripe.String("60540"), Country: stripe.String("US"), }, }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1", TaxBehavior = "exclusive", TaxCode = "txcd_99999999", }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { City = "Springfield", State = "IL", PostalCode = "62704", Country = "US", }, AddressSource = "billing", }, }; options.AddExtraParam("ship_from_details[address][city]", "Naperville"); options.AddExtraParam("ship_from_details[address][state]", "IL"); options.AddExtraParam("ship_from_details[address][postal_code]", "60540"); options.AddExtraParam("ship_from_details[address][country]", "US"); var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` The response returns the calculated tax based on the shipping origin of the order (Naperville, IL) instead of the destination (Springfield, IL) or the seller’s business origin: ```json { ... "amount_total": 1078, ... "tax_amount_exclusive": 78, ... "tax_breakdown": [ { "amount": 78, "inclusive": true,"tax_rate_details": { "country": "US", "percentage_decimal": "7.75", "state": "IL", "tax_type": "sales_tax" }, "taxability_reason": "standard_rated", "taxable_amount": 1000 } ], ... } ``` To learn more about how we calculate taxes in these scenarios, see the [Stripe Tax documentation](https://docs.stripe.com/tax/calculating.md). ## Optional: Calculate the retail delivery fee [Server-side] Stripe Tax supports calculating the retail delivery fee in Minnesota and Colorado. After you add a tax registration of the `state_retail_delivery_fee` type in the supported states, the retail delivery fee gets calculated on tax calculations. ```curl curl https://api.stripe.com/v1/tax/registrations \ -u "<>:" \ -d country=US \ -d "country_options[us][state]"=CO \ -d "country_options[us][type]"=state_retail_delivery_fee \ -d active_from=now ``` ```cli stripe tax registrations create \ --country=US \ -d "country_options[us][state]"=CO \ -d "country_options[us][type]"=state_retail_delivery_fee \ --active-from=now ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") registration = client.v1.tax.registrations.create({ country: 'US', country_options: { us: { state: 'CO', type: 'state_retail_delivery_fee', }, }, active_from: 'now', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. registration = client.v1.tax.registrations.create({ "country": "US", "country_options": {"us": {"state": "CO", "type": "state_retail_delivery_fee"}}, "active_from": "now", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $registration = $stripe->tax->registrations->create([ 'country' => 'US', 'country_options' => [ 'us' => [ 'state' => 'CO', 'type' => 'state_retail_delivery_fee', ], ], 'active_from' => 'now', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); RegistrationCreateParams params = RegistrationCreateParams.builder() .setCountry("US") .setCountryOptions( RegistrationCreateParams.CountryOptions.builder() .setUs( RegistrationCreateParams.CountryOptions.Us.builder() .setState("CO") .setType( RegistrationCreateParams.CountryOptions.Us.Type.STATE_RETAIL_DELIVERY_FEE ) .build() ) .build() ) .setActiveFrom(RegistrationCreateParams.ActiveFrom.NOW) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Registration registration = client.v1().tax().registrations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const registration = await stripe.tax.registrations.create({ country: 'US', country_options: { us: { state: 'CO', type: 'state_retail_delivery_fee', }, }, active_from: 'now', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxRegistrationCreateParams{ Country: stripe.String("US"), CountryOptions: &stripe.TaxRegistrationCreateCountryOptionsParams{ US: &stripe.TaxRegistrationCreateCountryOptionsUSParams{ State: stripe.String("CO"), Type: stripe.String(stripe.TaxRegistrationCountryOptionsUSTypeStateRetailDeliveryFee), }, }, ActiveFromNow: stripe.Bool(true), } result, err := sc.V1TaxRegistrations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.RegistrationCreateOptions { Country = "US", CountryOptions = new Stripe.Tax.RegistrationCountryOptionsOptions { Us = new Stripe.Tax.RegistrationCountryOptionsUsOptions { State = "CO", Type = "state_retail_delivery_fee", }, }, ActiveFrom = Stripe.Tax.RegistrationActiveFrom.Now, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Registrations; Stripe.Tax.Registration registration = service.Create(options); ``` To calculate the retail delivery fee, call the tax calculations API using a [physical item product tax code](https://docs.stripe.com/tax/tax-codes.md?type=physical), such as `txcd_30011000`, which represents Clothing and Footwear. Not all physical items trigger calculation of the retail delivery fee. Refer to the state’s documentation for when the tax applies: - [Retail Delivery Fee—Colorado](https://docs.stripe.com/tax/supported-countries/united-states/colorado.md#other-taxes) - [Retail Delivery Fee—Minnesota](https://docs.stripe.com/tax/supported-countries/united-states/minnesota.md#other-taxes) ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=exclusive \ -d "line_items[0][tax_code]"=txcd_30011000 \ -d "shipping_cost[amount]"=400 \ -d "customer_details[address][line1]"="1437 Bannock St Room 451" \ -d "customer_details[address][city]"=Springfield \ -d "customer_details[address][state]"=CO \ -d "customer_details[address][postal_code]"=80202 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_behavior]"=exclusive \ -d "line_items[0][tax_code]"=txcd_30011000 \ -d "shipping_cost[amount]"=400 \ -d "customer_details[address][line1]"="1437 Bannock St Room 451" \ -d "customer_details[address][city]"=Springfield \ -d "customer_details[address][state]"=CO \ -d "customer_details[address][postal_code]"=80202 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', tax_behavior: 'exclusive', tax_code: 'txcd_30011000', }, ], shipping_cost: {amount: 400}, customer_details: { address: { line1: '1437 Bannock St Room 451', city: 'Springfield', state: 'CO', postal_code: '80202', country: 'US', }, address_source: 'shipping', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [ { "amount": 1000, "reference": "L1", "tax_behavior": "exclusive", "tax_code": "txcd_30011000", }, ], "shipping_cost": {"amount": 400}, "customer_details": { "address": { "line1": "1437 Bannock St Room 451", "city": "Springfield", "state": "CO", "postal_code": "80202", "country": "US", }, "address_source": "shipping", }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', 'tax_behavior' => 'exclusive', 'tax_code' => 'txcd_30011000', ], ], 'shipping_cost' => ['amount' => 400], 'customer_details' => [ 'address' => [ 'line1' => '1437 Bannock St Room 451', 'city' => 'Springfield', 'state' => 'CO', 'postal_code' => '80202', 'country' => 'US', ], 'address_source' => 'shipping', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .setTaxBehavior(CalculationCreateParams.LineItem.TaxBehavior.EXCLUSIVE) .setTaxCode("txcd_30011000") .build() ) .setShippingCost( CalculationCreateParams.ShippingCost.builder().setAmount(400L).build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setLine1("1437 Bannock St Room 451") .setCity("Springfield") .setState("CO") .setPostalCode("80202") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.SHIPPING) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', tax_behavior: 'exclusive', tax_code: 'txcd_30011000', }, ], shipping_cost: { amount: 400, }, customer_details: { address: { line1: '1437 Bannock St Room 451', city: 'Springfield', state: 'CO', postal_code: '80202', country: 'US', }, address_source: 'shipping', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), TaxBehavior: stripe.String("exclusive"), TaxCode: stripe.String("txcd_30011000"), }, }, ShippingCost: &stripe.TaxCalculationCreateShippingCostParams{Amount: stripe.Int64(400)}, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ Line1: stripe.String("1437 Bannock St Room 451"), City: stripe.String("Springfield"), State: stripe.String("CO"), PostalCode: stripe.String("80202"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceShipping), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1", TaxBehavior = "exclusive", TaxCode = "txcd_30011000", }, }, ShippingCost = new Stripe.Tax.CalculationShippingCostOptions { Amount = 400 }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Line1 = "1437 Bannock St Room 451", City = "Springfield", State = "CO", PostalCode = "80202", Country = "US", }, AddressSource = "shipping", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` The response returns the calculated tax with the retail delivery fee for Colorado. It’s an additional entry in the `tax_breakdown` object, with`tax_breakdown.tax_rate_details.rate_type` set to `flat_amount`: ```json { ... "amount_total": 2165, ... "tax_amount_exclusive": 165, ... "tax_breakdown": [ { "amount": 88, "inclusive": false, "tax_rate_details": { "percentage_decimal": "8.81", "rate_type": "percentage", "tax_type": "sales_tax", ... }, "taxability_reason": "standard_rated", "taxable_amount": 1000 }, ... { "amount": 29, "inclusive": false,"tax_rate_details": { "flat_amount": { "amount": 29, "currency": "usd" }, "percentage_decimal": "0.0", "rate_type": "flat_amount", "tax_type": "retail_delivery_fee", ... }, "taxability_reason": "standard_rated", "taxable_amount": 1000 } ], ... } ``` ## Optional: Detailed line item tax breakdowns [Server-side] The top-level [tax_breakdown](https://docs.stripe.com/api/tax/calculations/object.md#tax_calculation_object-tax_breakdown) is always returned and provides a simple breakdown that’s suitable for displaying a list of taxes at checkout or on a receipt. You can use the [taxability_reason](https://docs.stripe.com/api/tax/calculations/object.md#tax_calculation_object-line_items-data-tax_breakdown-taxability_reason) to understand why tax isn’t applied while building your integration. For example, `not_collecting` doesn’t collect tax in the country or state where tax would be due. Adding [tax registrations](https://docs.stripe.com/tax/set-up.md#add-registrations) to your account settings tells Stripe where you’re collecting tax. If you added registration for Washington, the taxability reason displayed in your result is `standard_rated`, which indicates that the product is taxed at the standard rate. Expand the line item [tax_breakdown](https://docs.stripe.com/api/tax/calculations/object.md#tax_calculation_object-line_items-data-tax_breakdown) attribute to get a detailed breakdown, including local taxes and attributes that explain the reason for each tax. - The `tax_type` field from [tax_rate_details](https://docs.stripe.com/api/tax/calculations/object.md#tax_calculation_object-line_items-data-tax_breakdown-tax_rate_details) is a high-level tax type indication that might not always match the type returned in reports and transaction exports. For example, it doesn’t distinguish between US sales tax and US use tax. - Use the `display_name` field from [tax_rate_details](https://docs.stripe.com/api/tax/calculations/object.md#tax_calculation_object-line_items-data-tax_breakdown-tax_rate_details) in your Checkout flow to show all of the taxes. The taxes are localized based on customer location and product tax information. For example, if VAT is applied for Germany because the customer is in Germany and the product is taxed at the destination, such as [txcd_10103001: Software as a service (SaaS) for business use](https://docs.stripe.com/tax/tax-codes.md?tax_code=txcd_10103001), we show `Umsatzsteuer (USt)`, which is the German representation for VAT. If VAT is applied for France because the head office address is set to France and the product is taxed at the origin, such as [txcd_20030000: General - Services](https://docs.stripe.com/tax/tax-codes.md?tax_code=txcd_20030000), we show `Taxe sur la valeur ajoutée (TVA)`, which is the French representation of VAT. ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping \ -d "expand[0]"="line_items.data.tax_breakdown" ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][line1]"="920 5th Ave" \ -d "customer_details[address][city]"=Seattle \ -d "customer_details[address][state]"=WA \ -d "customer_details[address][postal_code]"=98104 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping \ -d "expand[0]"="line_items.data.tax_breakdown" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'shipping', }, expand: ['line_items.data.tax_breakdown'], }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1"}], "customer_details": { "address": { "line1": "920 5th Ave", "city": "Seattle", "state": "WA", "postal_code": "98104", "country": "US", }, "address_source": "shipping", }, "expand": ["line_items.data.tax_breakdown"], }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', ], ], 'customer_details' => [ 'address' => [ 'line1' => '920 5th Ave', 'city' => 'Seattle', 'state' => 'WA', 'postal_code' => '98104', 'country' => 'US', ], 'address_source' => 'shipping', ], 'expand' => ['line_items.data.tax_breakdown'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setLine1("920 5th Ave") .setCity("Seattle") .setState("WA") .setPostalCode("98104") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.SHIPPING) .build() ) .addExpand("line_items.data.tax_breakdown") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { line1: '920 5th Ave', city: 'Seattle', state: 'WA', postal_code: '98104', country: 'US', }, address_source: 'shipping', }, expand: ['line_items.data.tax_breakdown'], }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ Line1: stripe.String("920 5th Ave"), City: stripe.String("Seattle"), State: stripe.String("WA"), PostalCode: stripe.String("98104"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceShipping), }, } params.AddExpand("line_items.data.tax_breakdown") result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1" }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Line1 = "920 5th Ave", City = "Seattle", State = "WA", PostalCode = "98104", Country = "US", }, AddressSource = "shipping", }, Expand = new List { "line_items.data.tax_breakdown" }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` ```json { ... "tax_breakdown": [ { "amount": 103, "inclusive": false, "tax_rate_details": { "country": "US", "percentage_decimal": "10.25", "state": "WA", "tax_type": "sales_tax" },"taxability_reason": "standard_rated", "taxable_amount": 1000 } ], "line_items": { "object": "list", "data": [ { "id": "tax_li_O84jA8hvV7ZyAa", "object": "tax.calculation_line_item", "amount": 1000, "amount_tax": 103, "product": null, "quantity": 1, "reference": "L1", "tax_behavior": "exclusive", "tax_breakdown": [ { "amount": 65, "jurisdiction": { "country": "US", "display_name": "Washington", "level": "state", "state": "WA" }, "sourcing": "destination", "tax_rate_details": { "display_name": "Retail Sales and Use Tax", "percentage_decimal": "6.5", "tax_type": "sales_tax" },"taxability_reason": "standard_rated", "taxable_amount": 1000 }, { "amount": 0, "jurisdiction": { "country": "US", "display_name": "KING", "level": "county", "state": "WA" }, "sourcing": "destination", "tax_rate_details": null,"taxability_reason": "not_subject_to_tax", "taxable_amount": 0 }, { "amount": 22, "jurisdiction": { "country": "US", "display_name": "SEATTLE", "level": "city", "state": "WA" }, "sourcing": "destination", "tax_rate_details": { "display_name": "Local Sales and Use Tax", "percentage_decimal": "2.2", "tax_type": "sales_tax" },"taxability_reason": "standard_rated", "taxable_amount": 1000 }, { "amount": 14, "jurisdiction": { "country": "US", "display_name": "REGIONAL TRANSIT AUTHORITY", "level": "district", "state": "WA" }, "sourcing": "destination", "tax_rate_details": { "display_name": "Local Sales and Use Tax", "percentage_decimal": "1.4", "tax_type": "sales_tax" },"taxability_reason": "standard_rated", "taxable_amount": 1000 }, { "amount": 2, "jurisdiction": { "country": "US", "display_name": "SEATTLE TRANSPORTATION BENEFIT DISTRICT", "level": "district", "state": "WA" }, "sourcing": "destination", "tax_rate_details": { "display_name": "Local Sales and Use Tax", "percentage_decimal": "0.15", "tax_type": "sales_tax" },"taxability_reason": "standard_rated", "taxable_amount": 1000 } ], "tax_code": "txcd_10000000" } ], "has_more": false, "total_count": 1, "url": "/v1/tax/calculations/taxcalc_1NLoZvBUZ691iUZ4z4cTW6tQ/line_items" }, ... } ``` ## Optional: Troubleshoot common errors [Server-side] Follow the steps below to troubleshoot errors in your tax integration. ### Resolve invalid tax code errors If you receive an `Invalid tax code` error, refer to the [Product tax codes](https://docs.stripe.com/tax/tax-codes.md) for a list of available tax codes. Then, follow these steps to resolve the issue: 1. **Check the tax code**: Make sure you’re using a valid tax code from the [list of available tax codes](https://docs.stripe.com/tax/tax-codes.md). Common mistakes include: - Using an empty string or `null` as the tax code - Misspelling the tax code - Using a non-existent tax code 1. **Update your code**: Make sure you pass a valid tax code when creating a `TaxCalculation`. For example: ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_code]"=txcd_10000000 \ -d "customer_details[address][line1]"="354 Oyster Point Blvd" \ -d "customer_details[address][city]"="South San Francisco" \ -d "customer_details[address][state]"=CA \ -d "customer_details[address][postal_code]"=94080 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "line_items[0][tax_code]"=txcd_10000000 \ -d "customer_details[address][line1]"="354 Oyster Point Blvd" \ -d "customer_details[address][city]"="South San Francisco" \ -d "customer_details[address][state]"=CA \ -d "customer_details[address][postal_code]"=94080 \ -d "customer_details[address][country]"=US \ -d "customer_details[address_source]"=shipping ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', tax_code: 'txcd_10000000', }, ], customer_details: { address: { line1: '354 Oyster Point Blvd', city: 'South San Francisco', state: 'CA', postal_code: '94080', country: 'US', }, address_source: 'shipping', }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1", "tax_code": "txcd_10000000"}], "customer_details": { "address": { "line1": "354 Oyster Point Blvd", "city": "South San Francisco", "state": "CA", "postal_code": "94080", "country": "US", }, "address_source": "shipping", }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', 'tax_code' => 'txcd_10000000', ], ], 'customer_details' => [ 'address' => [ 'line1' => '354 Oyster Point Blvd', 'city' => 'South San Francisco', 'state' => 'CA', 'postal_code' => '94080', 'country' => 'US', ], 'address_source' => 'shipping', ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .setTaxCode("txcd_10000000") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setLine1("354 Oyster Point Blvd") .setCity("South San Francisco") .setState("CA") .setPostalCode("94080") .setCountry("US") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.SHIPPING) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', tax_code: 'txcd_10000000', }, ], customer_details: { address: { line1: '354 Oyster Point Blvd', city: 'South San Francisco', state: 'CA', postal_code: '94080', country: 'US', }, address_source: 'shipping', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), TaxCode: stripe.String("txcd_10000000"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{ Line1: stripe.String("354 Oyster Point Blvd"), City: stripe.String("South San Francisco"), State: stripe.String("CA"), PostalCode: stripe.String("94080"), Country: stripe.String("US"), }, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceShipping), }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1", TaxCode = "txcd_10000000", }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Line1 = "354 Oyster Point Blvd", City = "South San Francisco", State = "CA", PostalCode = "94080", Country = "US", }, AddressSource = "shipping", }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` 1. **Use the default tax code**: Stripe Tax uses a default tax code for calculations when a specific tax code isn’t provided for a product or in a tax calculation request. You can view and update the default value in your tax settings. Use the API to update the default tax code: ```curl curl https://api.stripe.com/v1/tax/settings \ -u "<>:" \ -d "defaults[tax_code]"=txcd_10000000 ``` ```cli stripe tax settings update \ -d "defaults[tax_code]"=txcd_10000000 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") settings = client.v1.tax.settings.update({defaults: {tax_code: 'txcd_10000000'}}) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. settings = client.v1.tax.settings.update({"defaults": {"tax_code": "txcd_10000000"}}) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $settings = $stripe->tax->settings->update([ 'defaults' => ['tax_code' => 'txcd_10000000'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SettingsUpdateParams params = SettingsUpdateParams.builder() .setDefaults( SettingsUpdateParams.Defaults.builder().setTaxCode("txcd_10000000").build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Settings settings = client.v1().tax().settings().update(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const settings = await stripe.tax.settings.update({ defaults: { tax_code: 'txcd_10000000', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxSettingsUpdateParams{ Defaults: &stripe.TaxSettingsUpdateDefaultsParams{ TaxCode: stripe.String("txcd_10000000"), }, } result, err := sc.V1TaxSettings.Update(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.SettingsUpdateOptions { Defaults = new Stripe.Tax.SettingsDefaultsOptions { TaxCode = "txcd_10000000" }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Settings; Stripe.Tax.Settings settings = service.Update(options); ``` 1. **Review your product catalog**: If you use tax codes associated with products in your Stripe product catalog, make sure the tax codes are correctly assigned to your products. 1. **Check for data inconsistencies**: Make sure the tax code is correctly passed from your database or front end to your server-side code that makes the API call to Stripe. For more accurate tax calculations, use the most specific tax code that applies to your product or service. If you’re unsure which tax code to use, consult the [tax codes documentation](https://docs.stripe.com/tax/tax-codes.md). If you continue to experience issues, review the [Tax Settings API documentation](https://docs.stripe.com/api/tax/settings.md). ## Collect customer tax IDs Displaying a customer’s tax ID and legal business name on *invoices* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) is a common requirement. You can use the [Tax ID Element](https://docs.stripe.com/elements/tax-id-element.md) to collect this information. This feature is in [public preview](https://docs.stripe.com/release-phases.md). > #### Disclaimer > > The Payment Intents API is designed to collect business tax IDs, which might have formats similar to personal tax IDs in certain jurisdictions. You must make sure that only business tax IDs, as designated for this field, are provided when using this feature. ### Enable the beta The Tax ID Element with the Payment Intents API requires you to enable the `elements_tax_id_1` beta. Add the beta to your Stripe.js initialization: ```javascript const stripe = Stripe('<>', { betas: ['elements_tax_id_1'], }); ``` ### Create a CustomerSession (optional) If you want to save tax IDs to a *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) and redisplay them for returning customers, you need to create a [CustomerSession](https://docs.stripe.com/api/customer_sessions.md). The CustomerSession provides secure, temporary access to customer data without exposing your secret API key to the client. If you don’t use CustomerSession, the Tax ID Element still works but without save and redisplay functionality. You can use [getValue](https://docs.stripe.com/js/elements_object/get_value_tax_id_element) to read the tax ID values from the element and handle them manually. First, create or retrieve a Customer: ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ --data-urlencode email="customer@example.com" \ -d name="Jenny Rosen" ``` ```cli stripe customers create \ --email="customer@example.com" \ --name="Jenny Rosen" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer = client.v1.customers.create({ email: 'customer@example.com', name: 'Jenny Rosen', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer = client.v1.customers.create({ "email": "customer@example.com", "name": "Jenny Rosen", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $customer = $stripe->customers->create([ 'email' => 'customer@example.com', 'name' => 'Jenny Rosen', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CustomerCreateParams params = CustomerCreateParams.builder() .setEmail("customer@example.com") .setName("Jenny Rosen") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Customer customer = client.v1().customers().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const customer = await stripe.customers.create({ email: 'customer@example.com', name: 'Jenny Rosen', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerCreateParams{ Email: stripe.String("customer@example.com"), Name: stripe.String("Jenny Rosen"), } result, err := sc.V1Customers.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CustomerCreateOptions { Email = "customer@example.com", Name = "Jenny Rosen", }; var client = new StripeClient("<>"); var service = client.V1.Customers; Customer customer = service.Create(options); ``` Create a CustomerSession with the Tax ID Element component enabled: ```curl curl https://api.stripe.com/v1/customer_sessions \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "components[tax_id_element][enabled]"=true \ -d "components[tax_id_element][features][tax_id_redisplay]"=enabled \ -d "components[tax_id_element][features][tax_id_save]"=enabled ``` ```cli stripe customer_sessions create \ --customer="{{CUSTOMER_ID}}" \ -d "components[tax_id_element][enabled]"=true \ -d "components[tax_id_element][features][tax_id_redisplay]"=enabled \ -d "components[tax_id_element][features][tax_id_save]"=enabled ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer_session = client.v1.customer_sessions.create({ customer: '{{CUSTOMER_ID}}', components: { tax_id_element: { enabled: true, features: { tax_id_redisplay: 'enabled', tax_id_save: 'enabled', }, }, }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys # This example uses the beta SDK. See https://github.com/stripe/stripe-python#public-preview-sdks client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer_session = client.v1.customer_sessions.create({ "customer": "{{CUSTOMER_ID}}", "components": { "tax_id_element": { "enabled": True, "features": {"tax_id_redisplay": "enabled", "tax_id_save": "enabled"}, }, }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-php#public-preview-sdks $stripe = new \Stripe\StripeClient('<>'); $customerSession = $stripe->customerSessions->create([ 'customer' => '{{CUSTOMER_ID}}', 'components' => [ 'tax_id_element' => [ 'enabled' => true, 'features' => [ 'tax_id_redisplay' => 'enabled', 'tax_id_save' => 'enabled', ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-java#public-preview-sdks StripeClient client = new StripeClient("<>"); CustomerSessionCreateParams params = CustomerSessionCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .setComponents( CustomerSessionCreateParams.Components.builder() .setTaxIdElement( CustomerSessionCreateParams.Components.TaxIdElement.builder() .setEnabled(true) .setFeatures( CustomerSessionCreateParams.Components.TaxIdElement.Features.builder() .setTaxIdRedisplay( CustomerSessionCreateParams.Components.TaxIdElement.Features.TaxIdRedisplay.ENABLED ) .setTaxIdSave( CustomerSessionCreateParams.Components.TaxIdElement.Features.TaxIdSave.ENABLED ) .build() ) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. CustomerSession customerSession = client.v1().customerSessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-node#public-preview-sdks const stripe = require('stripe')('<>'); const customerSession = await stripe.customerSessions.create({ customer: '{{CUSTOMER_ID}}', components: { tax_id_element: { enabled: true, features: { tax_id_redisplay: 'enabled', tax_id_save: 'enabled', }, }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-go#public-preview-sdks sc := stripe.NewClient("<>") params := &stripe.CustomerSessionCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), Components: &stripe.CustomerSessionCreateComponentsParams{ TaxIDElement: &stripe.CustomerSessionCreateComponentsTaxIDElementParams{ Enabled: stripe.Bool(true), Features: &stripe.CustomerSessionCreateComponentsTaxIDElementFeaturesParams{ TaxIDRedisplay: stripe.String("enabled"), TaxIDSave: stripe.String("enabled"), }, }, }, } result, err := sc.V1CustomerSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys // This example uses the beta SDK. See https://github.com/stripe/stripe-dotnet#public-preview-sdks var options = new CustomerSessionCreateOptions { Customer = "{{CUSTOMER_ID}}", Components = new CustomerSessionComponentsOptions { TaxIdElement = new CustomerSessionComponentsTaxIdElementOptions { Enabled = true, Features = new CustomerSessionComponentsTaxIdElementFeaturesOptions { TaxIdRedisplay = "enabled", TaxIdSave = "enabled", }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.CustomerSessions; CustomerSession customerSession = service.Create(options); ``` The CustomerSession returns a `client_secret` that you’ll pass to the client side. ### Create a PaymentIntent or SetupIntent Create a [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) or [SetupIntent](https://docs.stripe.com/api/setup_intents.md) on your server. When using CustomerSession, include the `customer` parameter to enable tax ID save and redisplay functionality: ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d customer="{{CUSTOMER_ID}}" ``` ```cli stripe payment_intents create \ --amount=1099 \ --currency=usd \ --customer="{{CUSTOMER_ID}}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 1099, "currency": "usd", "customer": "{{CUSTOMER_ID}}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 1099, 'currency' => 'usd', 'customer' => '{{CUSTOMER_ID}}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") .setCustomer("{{CUSTOMER_ID}}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(1099), Currency: stripe.String(stripe.CurrencyUSD), Customer: stripe.String("{{CUSTOMER_ID}}"), } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", Customer = "{{CUSTOMER_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` > You don’t need to include any tax-ID-specific parameters when creating the PaymentIntent or SetupIntent. The Tax ID Element automatically handles tax ID collection and saves it to the Customer when a CustomerSession with the appropriate permissions is present. ### Initialize Elements Create an Elements instance using the `clientSecret` from your PaymentIntent or SetupIntent. To enable saving tax IDs to a Customer and redisplaying them for returning customers, include the `customerSessionClientSecret`: ```javascript const stripe = Stripe('<>', { betas: ['elements_tax_id_1'], }); // Fetch the clientSecret from your server const {clientSecret} = await fetch('/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, }).then((res) => res.json()); // Fetch the customerSessionClientSecret from your server const {customerSessionClientSecret} = await fetch('/create-customer-session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, }).then((res) => res.json()); const elements = stripe.elements({ clientSecret,customerSessionClientSecret, appearance: { /* ... */ } }); ``` ### Create and mount the Tax ID Element Create an instance of the Tax ID Element and mount it to your page: ```html
``` ```javascript const taxIdElement = elements.create('taxId', { visibility: 'auto', // 'auto' | 'always' | 'never' }); taxIdElement.mount('#tax-id-element'); ``` You can customize the Tax ID Element with options such as `visibility`, `fields`, and `validation`. See [Create a Tax ID Element](https://docs.stripe.com/js/elements_object/create_tax_id_element) for more details. ### Use with Address Element (optional) When you use the Tax ID Element with the [Address Element](https://docs.stripe.com/elements/address-element.md), Stripe automatically determines the tax ID type and element visibility based on the customer’s address. ### Complete the payment When the customer submits the payment form, call [confirmPayment](https://docs.stripe.com/js/payment_intents/confirm_payment) or [confirmSetup](https://docs.stripe.com/js/setup_intents/confirm_setup). Stripe automatically includes the tax ID information and saves it to the Customer if the payment succeeds: ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', async (event) => { event.preventDefault(); const {error} = await stripe.confirmPayment({ elements, confirmParams: { return_url: 'https://example.com/order/complete', }, }); if (error) { // Handle error console.error(error.message); } // Customer gets redirected to return_url if successful }); ``` You can also use [getValue](https://docs.stripe.com/js/elements_object/get_value_tax_id_element) on the client side to read the tax ID values before submitting the payment. ### Test your integration In testing environments, you can enter any alphanumeric string that is in the correct format of a supported tax ID type (for example, `DE123456789` for `eu_vat`). For a full list of example tax IDs you can reference our [Customer Tax ID guide](https://docs.stripe.com/billing/customer/tax-ids.md#supported-tax-id). You can also use our [test tax IDs](https://docs.stripe.com/connect/testing.md#test-business-tax-ids) to test various verification state flows. ### Tax ID validation During payment or setup confirmation, Stripe verifies that the provided tax IDs are formatted correctly, but not that they’re valid. You’re responsible for ensuring the validity of customer information. To help, Stripe automatically performs asynchronous validation against government databases for [European Value Added Tax](https://docs.stripe.com/billing/customer/tax-ids.md#eu-vat) (EU VAT) and [United Kingdom Value Added Tax](https://docs.stripe.com/billing/customer/tax-ids.md#gb-vat) (GB VAT) numbers. Learn more about the [validation we perform](https://docs.stripe.com/tax/invoicing/tax-ids.md#validation), and how to consume the status of those checks. ### Supported Tax ID types The Tax ID Element supports tax ID collection in the following countries and regions: | Country | Enum | Description | Example | Impact in Tax Calculation* | | ------- | ---------- | --------------------------------------------------------------------------- | -------------------- | -------------------------- | | AE | ae_trn | United Arab Emirates TRN | 123456789012345 | Yes | | AL | al_tin | Albania Tax Identification Number | J12345678N | Yes | | AM | am_tin | Armenia Tax Identification Number | 02538904 | Yes | | AO | ao_tin | Angola Tax Identification Number | 5123456789 | No | | AT | eu_vat | European VAT number | ATU12345678 | Yes | | AU | au_abn | Australian Business Number (AU ABN) | 12345678912 | Yes | | AW | aw_tin | Aruba Tax Identification Number | 12345678 | Yes | | AZ | az_tin | Azerbaijan Tax Identification Number | 0123456789 | Yes | | BA | ba_tin | Bosnia and Herzegovina Tax Identification Number | 123456789012 | Yes | | BB | bb_tin | Barbados Tax Identification Number | 1123456789012 | No | | BD | bd_bin | Bangladesh Business Identification Number | 123456789-0123 | Yes | | BE | eu_vat | European VAT number | BE0123456789 | Yes | | BF | bf_ifu | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | 12345678A | Yes | | BG | eu_vat | European VAT number | BG0123456789 | Yes | | BH | bh_vat | Bahraini VAT Number | 123456789012345 | Yes | | BJ | bj_ifu | Benin Tax Identification Number (Identifiant Fiscal Unique) | 1234567890123 | Yes | | BS | bs_tin | Bahamas Tax Identification Number | 123.456.789 | No | | BY | by_tin | Belarus TIN Number | 123456789 | Yes | | CA | ca_bn | Canadian BN | 123456789 | No | | CA | ca_gst_hst | Canadian GST/HST number | 123456789RT0002 | Yes | | CA | ca_pst_bc | Canadian PST number (British Columbia) | PST-1234-5678 | No | | CA | ca_pst_mb | Canadian PST number (Manitoba) | 123456-7 | No | | CA | ca_pst_sk | Canadian PST number (Saskatchewan) | 1234567 | No | | CA | ca_qst | Canadian QST number (Québec) | 1234567890TQ1234 | Yes | | CD | cd_nif | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | A0123456M | No | | CH | ch_vat | Switzerland VAT number | CHE-123.456.789 MWST | Yes | | CL | cl_tin | Chilean TIN | 12.345.678-K | Yes | | CM | cm_niu | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | M123456789000L | No | | CR | cr_tin | Costa Rican tax ID | 1-234-567890 | No | | CV | cv_nif | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | 213456789 | No | | CY | eu_vat | European VAT number | CY12345678Z | Yes | | CZ | eu_vat | European VAT number | CZ1234567890 | Yes | | DE | eu_vat | European VAT number | DE123456789 | Yes | | DK | eu_vat | European VAT number | DK12345678 | Yes | | EC | ec_ruc | Ecuadorian RUC number | 1234567890001 | No | | EE | eu_vat | European VAT number | EE123456789 | Yes | | EG | eg_tin | Egyptian Tax Identification Number | 123456789 | Yes | | ES | es_cif | Spanish NIF number (previously Spanish CIF number) | A12345678 | No | | ES | eu_vat | European VAT number | ESA1234567Z | Yes | | ET | et_tin | Ethiopia Tax Identification Number | 1234567890 | Yes | | FI | eu_vat | European VAT number | FI12345678 | Yes | | FR | eu_vat | European VAT number | FRAB123456789 | Yes | | GB | eu_vat | Northern Ireland VAT number | XI123456789 | Yes | | GB | gb_vat | United Kingdom VAT number | GB123456789 | Yes | | GE | ge_vat | Georgian VAT | 123456789 | Yes | | GN | gn_nif | Guinea Tax Identification Number (Número de Identificação Fiscal) | 123456789 | Yes | | GR | eu_vat | European VAT number | EL123456789 | Yes | | HR | eu_vat | European VAT number | HR12345678912 | Yes | | HU | eu_vat | European VAT number | HU12345678 | Yes | | HU | hu_tin | Hungary tax number (adószám) | 12345678-1-23 | No | | IE | eu_vat | European VAT number | IE1234567AB | Yes | | IN | in_gst | Indian GST number | 12ABCDE3456FGZH | Yes | | IS | is_vat | Icelandic VAT | 123456 | Yes | | IT | eu_vat | European VAT number | IT12345678912 | Yes | | KE | ke_pin | Kenya Revenue Authority Personal Identification Number | P000111111A | No | | KG | kg_tin | Kyrgyzstan Tax Identification Number | 12345678901234 | No | | KH | kh_tin | Cambodia Tax Identification Number | 1001-123456789 | Yes | | KR | kr_brn | Korean BRN | 123-45-67890 | Yes | | KZ | kz_bin | Kazakhstani Business Identification Number | 123456789012 | Yes | | LA | la_tin | Laos Tax Identification Number | 123456789-000 | No | | LI | li_vat | Liechtensteinian VAT number | 12345 | Yes | | LT | eu_vat | European VAT number | LT123456789123 | Yes | | LU | eu_vat | European VAT number | LU12345678 | Yes | | LV | eu_vat | European VAT number | LV12345678912 | Yes | | MA | ma_vat | Morocco VAT Number | 12345678 | Yes | | MD | md_vat | Moldova VAT Number | 1234567 | Yes | | ME | me_pib | Montenegro PIB Number | 12345678 | No | | MK | mk_vat | North Macedonia VAT Number | MK1234567890123 | Yes | | MR | mr_nif | Mauritania Tax Identification Number (Número de Identificação Fiscal) | 12345678 | No | | MT | eu_vat | European VAT number | MT12345678 | Yes | | MX | mx_rfc | Mexican RFC number | ABC010203AB9 | No | | NG | ng_tin | Nigerian Tax Identification Number | 12345678-0001 | No | | NL | eu_vat | European VAT number | NL123456789B12 | Yes | | NO | no_vat | Norwegian VAT number | 123456789MVA | Yes | | NP | np_pan | Nepal PAN Number | 123456789 | Yes | | NZ | nz_gst | New Zealand GST number | 123456789 | Yes | | OM | om_vat | Omani VAT Number | OM1234567890 | Yes | | PE | pe_ruc | Peruvian RUC number | 12345678901 | Yes | | PH | ph_tin | Philippines Tax Identification Number | 123456789012 | Yes | | PL | eu_vat | European VAT number | PL1234567890 | Yes | | PL | pl_nip | Polish NIP number | 1234567890 | No | | PT | eu_vat | European VAT number | PT123456789 | Yes | | RO | eu_vat | European VAT number | RO1234567891 | Yes | | RS | rs_pib | Serbian PIB number | 123456789 | No | | RU | ru_inn | Russian INN | 1234567891 | Yes | | RU | ru_kpp | Russian KPP | 123456789 | Yes | | SA | sa_vat | Saudi Arabia VAT | 123456789012345 | Yes | | SE | eu_vat | European VAT number | SE123456789123 | Yes | | SG | sg_gst | Singaporean GST | M12345678X | Yes | | SI | eu_vat | European VAT number | SI12345678 | Yes | | SK | eu_vat | European VAT number | SK1234567891 | Yes | | SN | sn_ninea | Senegal NINEA Number | 12345672A2 | No | | SR | sr_fin | Suriname FIN Number | 1234567890 | Yes | | TH | th_vat | Thai VAT | 1234567891234 | Yes | | TJ | tj_tin | Tajikistan Tax Identification Number | 123456789 | Yes | | TR | tr_tin | Turkish Tax Identification Number | 0123456789 | Yes | | TW | tw_vat | Taiwanese VAT | 12345678 | Yes | | TZ | tz_vat | Tanzania VAT Number | 12345678A | Yes | | UA | ua_vat | Ukrainian VAT | 123456789 | Yes | | UG | ug_tin | Uganda Tax Identification Number | 1014751879 | Yes | | UY | uy_ruc | Uruguayan RUC number | 123456789012 | Yes | | UZ | uz_tin | Uzbekistan TIN Number | 123456789 | No | | UZ | uz_vat | Uzbekistan VAT Number | 123456789012 | Yes | | ZA | za_vat | South African VAT number | 4123456789 | Yes | | ZM | zm_tin | Zambia Tax Identification Number | 1004751879 | No | | ZW | zw_tin | Zimbabwe Tax Identification Number | 1234567890 | No | \*Stripe Tax won't apply tax if this tax ID is provided, in line with the relevant laws. ### Use tax IDs in calculations (optional) In some cases, such as the cross-border supply of services, your customer might need to account for tax on a [reverse charge](https://docs.stripe.com/tax/zero-tax.md#reverse-charges) basis. Instead of collecting the tax, you must issue an invoice with the text, “Tax to be paid on reverse charge basis.” When you provide your customer’s [tax IDs](https://docs.stripe.com/api/tax/calculations/create.md#calculate_tax-customer_details-tax_ids) to Stripe Tax, we automatically determine when reverse charge applies: ```curl curl https://api.stripe.com/v1/tax/calculations \ -u "<>:" \ -d currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing \ -d "customer_details[tax_ids][0][type]"=eu_vat \ -d "customer_details[tax_ids][0][value]"=DE123456789 ``` ```cli stripe tax calculations create \ --currency=usd \ -d "line_items[0][amount]"=1000 \ -d "line_items[0][reference]"=L1 \ -d "customer_details[address][country]"=IE \ -d "customer_details[address_source]"=billing \ -d "customer_details[tax_ids][0][type]"=eu_vat \ -d "customer_details[tax_ids][0][value]"=DE123456789 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") calculation = client.v1.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: {country: 'IE'}, address_source: 'billing', tax_ids: [ { type: 'eu_vat', value: 'DE123456789', }, ], }, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. calculation = client.v1.tax.calculations.create({ "currency": "usd", "line_items": [{"amount": 1000, "reference": "L1"}], "customer_details": { "address": {"country": "IE"}, "address_source": "billing", "tax_ids": [{"type": "eu_vat", "value": "DE123456789"}], }, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $calculation = $stripe->tax->calculations->create([ 'currency' => 'usd', 'line_items' => [ [ 'amount' => 1000, 'reference' => 'L1', ], ], 'customer_details' => [ 'address' => ['country' => 'IE'], 'address_source' => 'billing', 'tax_ids' => [ [ 'type' => 'eu_vat', 'value' => 'DE123456789', ], ], ], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CalculationCreateParams params = CalculationCreateParams.builder() .setCurrency("usd") .addLineItem( CalculationCreateParams.LineItem.builder() .setAmount(1000L) .setReference("L1") .build() ) .setCustomerDetails( CalculationCreateParams.CustomerDetails.builder() .setAddress( CalculationCreateParams.CustomerDetails.Address.builder() .setCountry("IE") .build() ) .setAddressSource(CalculationCreateParams.CustomerDetails.AddressSource.BILLING) .addTaxId( CalculationCreateParams.CustomerDetails.TaxId.builder() .setType(CalculationCreateParams.CustomerDetails.TaxId.Type.EU_VAT) .setValue("DE123456789") .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Calculation calculation = client.v1().tax().calculations().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const calculation = await stripe.tax.calculations.create({ currency: 'usd', line_items: [ { amount: 1000, reference: 'L1', }, ], customer_details: { address: { country: 'IE', }, address_source: 'billing', tax_ids: [ { type: 'eu_vat', value: 'DE123456789', }, ], }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TaxCalculationCreateParams{ Currency: stripe.String(stripe.CurrencyUSD), LineItems: []*stripe.TaxCalculationCreateLineItemParams{ &stripe.TaxCalculationCreateLineItemParams{ Amount: stripe.Int64(1000), Reference: stripe.String("L1"), }, }, CustomerDetails: &stripe.TaxCalculationCreateCustomerDetailsParams{ Address: &stripe.AddressParams{Country: stripe.String("IE")}, AddressSource: stripe.String(stripe.TaxCalculationCustomerDetailsAddressSourceBilling), TaxIDs: []*stripe.TaxCalculationCreateCustomerDetailsTaxIDParams{ &stripe.TaxCalculationCreateCustomerDetailsTaxIDParams{ Type: stripe.String(stripe.TaxCalculationCustomerDetailsTaxIDTypeEUVAT), Value: stripe.String("DE123456789"), }, }, }, } result, err := sc.V1TaxCalculations.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Tax.CalculationCreateOptions { Currency = "usd", LineItems = new List { new Stripe.Tax.CalculationLineItemOptions { Amount = 1000, Reference = "L1" }, }, CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions { Address = new AddressOptions { Country = "IE" }, AddressSource = "billing", TaxIds = new List { new Stripe.Tax.CalculationCustomerDetailsTaxIdOptions { Type = "eu_vat", Value = "DE123456789", }, }, }, }; var client = new StripeClient("<>"); var service = client.V1.Tax.Calculations; Stripe.Tax.Calculation calculation = service.Create(options); ``` If you provide a tax ID with an invalid format, the calculation returns a `tax_id_invalid` error code. ## See also - [Use Stripe Tax with Connect](https://docs.stripe.com/tax/connect.md) --- # Source: https://docs.stripe.com/invoicing/customer.md # Source: https://docs.stripe.com/billing/customer.md # Customers Learn how to use the Customer resource with Stripe Billing. If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. The *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) resource is a core entity within Stripe. Use it to store all of the profile, billing, and tax information required to bill a customer for *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) and one-off *invoices* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice). ## Manage customers Create a customer for every new user or business you want to bill. When creating a new customer, set a [minimum customer profile](https://docs.stripe.com/billing/customer.md#minimum-customer-profile) to help create useful invoices and enable Smart Retries (dunning). After creating and configuring this customer, use it to create a subscription and issue one-off invoices. #### Dashboard You can create and manage customers on the [Customers page](https://dashboard.stripe.com/customers) when you don’t want to use code to create a customer, or if you want to manually bill a customer with a one-off invoice. > You can also create a customer in the Dashboard during invoice creation. ### Create a customer When you create a new customer, you can set their account and billing information, such as **Email**, **Name**, and **Country**. You can also set a customer’s preferred language, currency, and other important details. You can also perform these actions on the **Customers** page: - Filter your customers. - Delete customers. - View all of your customers. - Export a list of customer data. To create a customer, complete these steps: 1. Verify that the customer doesn’t already exist. 1. Click **Add customer**, or press **N**, on the **Customers** page. 1. At a minimum, enter your customer’s **Name** and **Account email**. 1. Click **Add customer** in the dialog. ### Edit a customer To edit a customer’s profile, complete these steps: 1. Find the customer you want to modify and click the name on the **Customers** page. 1. In the account information page, select **Actions** > **Edit information**. 1. Make your changes to the customer profile. 1. Click **Update customer**. ### Delete a customer To delete a customer, complete these steps: 1. Find the customer you want to delete on the **Customers** page. 1. Click the checkbox next to your customer’s name followed by **Delete**. You can also click into the customer’s details page and select **Actions** > **Delete customer**. #### API Before billing a customer, you need to create a Customer object that you can configure with a name, email, and payment method. You can read more about this in the [integration guide](https://docs.stripe.com/billing/subscriptions/build-subscriptions.md), but here’s a basic example: ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ --data-urlencode email="jenny.rosen@example.com" \ -d payment_method=pm_card_visa \ -d "invoice_settings[default_payment_method]"=pm_card_visa ``` ```cli stripe customers create \ --email="jenny.rosen@example.com" \ --payment-method=pm_card_visa \ -d "invoice_settings[default_payment_method]"=pm_card_visa ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") customer = client.v1.customers.create({ email: 'jenny.rosen@example.com', payment_method: 'pm_card_visa', invoice_settings: {default_payment_method: 'pm_card_visa'}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer = client.v1.customers.create({ "email": "jenny.rosen@example.com", "payment_method": "pm_card_visa", "invoice_settings": {"default_payment_method": "pm_card_visa"}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $customer = $stripe->customers->create([ 'email' => 'jenny.rosen@example.com', 'payment_method' => 'pm_card_visa', 'invoice_settings' => ['default_payment_method' => 'pm_card_visa'], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CustomerCreateParams params = CustomerCreateParams.builder() .setEmail("jenny.rosen@example.com") .setPaymentMethod("pm_card_visa") .setInvoiceSettings( CustomerCreateParams.InvoiceSettings.builder() .setDefaultPaymentMethod("pm_card_visa") .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Customer customer = client.v1().customers().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const customer = await stripe.customers.create({ email: 'jenny.rosen@example.com', payment_method: 'pm_card_visa', invoice_settings: { default_payment_method: 'pm_card_visa', }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CustomerCreateParams{ Email: stripe.String("jenny.rosen@example.com"), PaymentMethod: stripe.String("pm_card_visa"), InvoiceSettings: &stripe.CustomerCreateInvoiceSettingsParams{ DefaultPaymentMethod: stripe.String("pm_card_visa"), }, } result, err := sc.V1Customers.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CustomerCreateOptions { Email = "jenny.rosen@example.com", PaymentMethod = "pm_card_visa", InvoiceSettings = new CustomerInvoiceSettingsOptions { DefaultPaymentMethod = "pm_card_visa", }, }; var client = new StripeClient("<>"); var service = client.V1.Customers; Customer customer = service.Create(options); ``` See how to [create a customer](https://docs.stripe.com/api/customers/create.md) with the API for a complete list of parameters. ## Available properties and uses The Customer resource has many useful properties you can set to customize billing. This section explains the properties you can store on the Customer, and the effects of each. ### Customer profile A basic customer profile is useful for invoice and receipt generation, and can generally act as a lightweight customer relationship management system (CRM) for your application. You can also use [affiliate and referral Stripe apps](https://marketplace.stripe.com/categories/affiliate_and_referrals) to set up and manage referral and affiliate programs with Stripe, get customer information, and automate commission adjustments from the Stripe Dashboard. #### Minimal customer profile When creating a customer, set these properties: - Email address - Customer name - Metadata with a reference to the internal customer ID of your application An [email address](https://docs.stripe.com/api/customers/object.md#customer_object-email) lets Stripe notify the customer of failed payments or when completing a payment requires further action, as part of the [Automatic Collection](https://docs.stripe.com/invoicing/automatic-collection.md) process. Store the internal customer ID of your application in the [metadata](https://docs.stripe.com/api/customers/object.md#customer_object-metadata) attribute. Like most Stripe resources, the Customer resource includes a [Metadata](https://docs.stripe.com/api/metadata.md) object hash to flexibly store contextual key-value information. To aid in auditing and support, store your internal customer ID as a key-value pair on the Customer resource. This allows you to search for the customer using your internal reference ID. Conversely, we recommend storing Stripe customer IDs against the internal customer model of your application. #### Billing and shipping addresses Use the address properties to set an [address](https://docs.stripe.com/api/customers/object.md#customer_object-address) for billing (invoicing, credit notes, and so on), and a [shipping](https://docs.stripe.com/api/customers/object.md#customer_object-shipping) address (for physical goods). While a shipping address is most relevant to businesses delivering physical goods, a billing address is useful because it displays on invoices, credit notes, and receipts—a common requirement for tax compliance. #### Email and PDF language localization Localize Stripe-generated emails and PDFs by setting the `preferred_locales` property. This property accepts an ordered list of preferred languages, sorted by preference. These preferred locale values are based on [RFC-4646](https://tools.ietf.org/html/rfc4646). Examples include “en” for English, or “fr-CA” for Canadian French. See the [Customizing invoices](https://docs.stripe.com/invoicing/customize.md#customer-language) page for more information. #### Per-customer invoice settings For further details on customizing invoice contents on a per-customer basis, see the [Customizing invoices](https://docs.stripe.com/invoicing/customize.md) page. It explains [custom fields](https://docs.stripe.com/invoicing/customize.md#custom-fields), [invoice footer](https://docs.stripe.com/invoicing/customize.md#footer-field) content, and how to [customize the invoice number](https://docs.stripe.com/invoicing/customize.md#invoice-numbering-schemes). ### Payment All payments are collected from [payment](https://docs.stripe.com/payments.md) details associated with a customer, and a customer can have multiple ways to make a payment, including: - [Payment Methods](https://docs.stripe.com/payments/payment-methods.md) - [Customer Credit Balance](https://docs.stripe.com/billing/customer.md#customer-balance) Customers are [single-currency](https://docs.stripe.com/billing/customer.md#currency), meaning after you’ve assigned a currency, invoiced the customer, or [set a customer credit balance](https://docs.stripe.com/billing/customer.md#customer-balance), you can’t change the currency. This locked status is visible in the Dashboard in a disabled **Currency** dropdown. If you need to bill a single entity with multiple currencies, create a new customer for each currency. ### Invoicing All invoicing-related resources are associated with the customer being billed. These resources include: - [Pending invoice items](https://docs.stripe.com/billing/invoices/subscription.md#adding-draft-invoice-items) - [Subscriptions](https://docs.stripe.com/billing/subscriptions/overview.md) - [Invoices](https://docs.stripe.com/invoicing/overview.md) - [Receipts](https://docs.stripe.com/receipts.md) - [Invoice settings](https://docs.stripe.com/api/customers/create.md#create_customer-invoice_settings) ### Tax info To meet tax jurisdiction requirements, you might need to include customer tax ID numbers and other information on invoices. It’s ultimately your responsibility to make sure your customer’s invoices contain the correct information. This includes [tax IDs](https://docs.stripe.com/billing/customer/tax-ids.md), [tax exemption status](https://docs.stripe.com/api/customers/create.md#create_customer-tax_exempt), and [addresses](https://docs.stripe.com/billing/customer.md#addresses). Tax IDs provide a way to store and render one or more tax ID numbers on invoices. Tax exemption status indicates whether the entity is taxable. By default, a customer’s `tax_exempt` status is set to `none`, meaning it’s a taxable billing entity. However, you can flag a customer as being responsible for paying the tax on an invoice by setting the `tax_exempt` property to `reverse`, or flag them as being tax exempt by setting the status to `exempt`. You can read more about using `tax_exempt` and `reverse` on the [Tax Rates](https://docs.stripe.com/billing/taxes/tax-rates.md#tax-exempt-and-reverse-charge) page. ## Common tasks This section explains some of the common tasks you might perform with the Customer resource. ### Create a subscription Before you can create a new subscription, you need to create a customer for billing purposes. 1. [Create the customer](https://docs.stripe.com/billing/customer.md#create). 1. Define your [product](https://docs.stripe.com/products-prices/manage-prices.md#create-product) catalog and [prices](https://docs.stripe.com/products-prices/manage-prices.md#create-price). 1. [Create a subscription](https://docs.stripe.com/billing/subscriptions/overview.md) using the customer created in step one and a price (or multiple prices) from step two. You can continue to update the customer’s details after you create the subscription until an invoice is [finalized](https://docs.stripe.com/invoicing.md). Any changes apply to the next billing period, when a new invoice is generated using the latest status of the customer when rendering PDFs, emails, and the hosted invoice page. Read the [How subscriptions work](https://docs.stripe.com/billing/subscriptions/overview.md) page for more detailed information. ### Send a one-off (manual) invoice to a customer Unlike subscription invoices, you manually issue one-off invoices and they don’t follow an automated schedule. This makes them useful for billing one-off orders or work, such as setup and installation fees, consultancy fees, or single orders for physical goods. 1. [Create the customer](https://docs.stripe.com/billing/customer.md#create). 1. [Create a new draft invoice](https://docs.stripe.com/invoicing/dashboard.md#create-invoice) by adding invoice line items with a description, quantity, unit price, and tax rate. 1. [Set the invoice payment method](https://docs.stripe.com/invoicing/dashboard.md#create-invoice). You can collect payment for an invoice either by automatically charging the payment method on file, or by emailing the invoice to the customer. 1. Finalize the invoice. See the [one-off invoices documentation](https://docs.stripe.com/invoicing/dashboard.md#create-invoice) for full details on how to create and collect payment for one-off invoices. ### Store a customer credit balance The [customer credit balance](https://docs.stripe.com/billing/customer/balance.md) feature allows you to assign credit and debit adjustments to a specific customer. The resulting balance is applied to future invoices for that customer. ### Add and validate tax ID numbers Displaying a customer’s tax ID on invoice documents is a common requirement. With Stripe, you can add one or multiple [tax IDs](https://docs.stripe.com/billing/customer/tax-ids.md) to a customer. A customer’s tax IDs are displayed in the header of invoice and credit note PDFs. See the [Tax IDs](https://docs.stripe.com/billing/customer/tax-ids.md) page for more details. ### Set the currency for a customer The `currency` property is a three-letter [ISO code for the currency](https://docs.stripe.com/currencies.md) that you charge the customer in for recurring billing purposes. You can set the currency in the Dashboard by navigating to the **Customers** > **Details** page and clicking **Update details**. After you set the currency, you can’t change it. Creating an invoice, invoice item, or credit balance for the customer also permanently sets the customer’s currency. --- # Source: https://docs.stripe.com/api/customer_balance_transactions.md # Customer Balance Transaction Each customer has a [Balance](https://docs.stripe.com/docs/api/customers/object.md#customer_object-balance) value, which denotes a debit or credit that’s automatically applied to their next invoice upon finalization. You may modify the value directly by using the [update customer API](https://docs.stripe.com/docs/api/customers/update.md), or by creating a Customer Balance Transaction, which increments or decrements the customer’s `balance` by the specified `amount`. Related guide: [Customer balance](https://docs.stripe.com/docs/billing/customer/balance.md) ## Endpoints ### Create a customer balance transaction - [POST /v1/customers/:id/balance_transactions](https://docs.stripe.com/api/customer_balance_transactions/create.md) ### Update a customer credit balance transaction - [POST /v1/customers/:id/balance_transactions/:id](https://docs.stripe.com/api/customer_balance_transactions/update.md) ### Retrieve a customer balance transaction - [GET /v1/customers/:id/balance_transactions/:id](https://docs.stripe.com/api/customer_balance_transactions/retrieve.md) ### List customer balance transactions - [GET /v1/customers/:id/balance_transactions](https://docs.stripe.com/api/customer_balance_transactions/list.md) --- # Source: https://docs.stripe.com/api/customers.md # Customers This object represents a customer of your business. Use it to [create recurring charges](https://docs.stripe.com/docs/invoicing/customer.md), [save payment](https://docs.stripe.com/docs/payments/save-during-payment.md) and contact information, and track payments that belong to the same customer. ## Endpoints ### Create a customer - [POST /v1/customers](https://docs.stripe.com/api/customers/create.md) ### Update a customer - [POST /v1/customers/:id](https://docs.stripe.com/api/customers/update.md) ### Retrieve a customer - [GET /v1/customers/:id](https://docs.stripe.com/api/customers/retrieve.md) ### List all customers - [GET /v1/customers](https://docs.stripe.com/api/customers/list.md) ### Delete a customer - [DELETE /v1/customers/:id](https://docs.stripe.com/api/customers/delete.md) ### Search customers - [GET /v1/customers/search](https://docs.stripe.com/api/customers/search.md) --- # Source: https://docs.stripe.com/payments/checkout/customization.md # Customize Checkout Customize the appearance and behavior of Checkout. Customize Checkout, including branding, legal policies, return policies, customer payment autofill, and custom domains. [Appearance](https://docs.stripe.com/payments/checkout/customization/appearance.md): Customize the look and feel of Checkout, including the branding. [Text and policies](https://docs.stripe.com/payments/checkout/customization/policies.md): Customize the support contact information, policies, and other text that your customers see. [Card brands](https://docs.stripe.com/payments/checkout/customization/card-brands.md): Customize the card brands that your customers see. [Custom domain](https://docs.stripe.com/payments/checkout/custom-domains.md): Use a custom domain with Stripe Checkout, Payment Links, and the customer portal. --- # Source: https://docs.stripe.com/invoicing/customize.md # Customize invoices Learn how to customize the content and branding of your invoices. If your Connect platform uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), use our [guide](https://docs.stripe.com/connect/use-accounts-as-customers.md) to replace `Customer` and event references in your code with the equivalent Accounts v2 API references. You can customize the content of an *invoice* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) in the following ways: - Through the API - Through the invoice editor - Through the subscription editor - Through [invoice templates](https://docs.stripe.com/invoicing/invoice-rendering-template.md) - Through account [Invoice settings](https://dashboard.stripe.com/settings/billing/invoice) You can also set a customer preferred language and include public information in your [account details](https://dashboard.stripe.com/settings/account/?support_details=true). Because you know more about your customers and your business than Stripe does, make sure your invoices include all of the required information. Your invoices must be accurate, charge the appropriate tax, and comply with all applicable laws and regulations in your region. ## Branding Stripe allows you to customize (as well as preview) email receipts, hosted invoices, invoice PDFs, and so on, in your [Branding settings](https://dashboard.stripe.com/account/branding). Icons and logos must be in JPG or PNG format, less than 512kb in size, and equal to or greater than 128px by 128px. - **Icon**—A square, digital-friendly icon or logo. - **Logo**—A non-square logo to override some uses of the icon. - **Brand color**—Used on receipts, invoices, and the customer portal. - **Accent color**—Used as a background on emails and pages. ### Apply brand settings Brand settings apply to your whole account and take effect in many places. | Setting | Emails | Checkout & Payment Links | Customer portal | Hosted Invoice Page | Invoice PDFs | | ---------------- | ---------------------- | ------------------------ | --------------- | ------------------- | ------------ | | **Icon** | Yes | Yes | Yes | Yes | Yes | | **Logo** | No | Yes | No | No | Yes | | **Brand color** | Yes | No | Yes | Yes | Yes | | **Accent color** | Yes (background color) | Yes | Yes | Yes | No | ## Invoice numbering Stripe automatically generates invoice numbers to help track and reconcile invoices. Invoice numbers have a prefix and suffix, such as `586A2E-0139` or `MYSHOP-1203`. (​​The full invoice number is always unique across your account in both schemes.) ​​Stripe supports two invoice numbering schemes: - ​​**Sequentially for each customer (customer-level)**—Uses a unique prefix for each customer and assigns invoice numbers sequentially for a given customer. - ​​**Sequentially across your account (account-level)**—Uses the same prefix for every customer and assigns invoice numbers sequentially across your entire account. Stripe chooses a default behavior based on the country your Stripe account is based in. [European Union](https://ec.europa.eu/taxation_customs/business/vat/eu-vat-rules-topic/vat-invoicing-rules_en) member countries and the [United Kingdom](https://www.gov.uk/invoicing-and-taking-payment-from-customers/invoices-what-they-must-include) typically require account level sequencing. All other countries default to customer level sequencing because it doesn’t expose the total number of invoices. When switching between schemes or updating prefixes, only future invoices use the new settings. This doesn’t impact existing invoices. > Invoice requirements vary by jurisdiction. Consult with a professional for guidance on your specific use case. You’re responsible for verifying that the invoices you issue meet local tax requirements. ### Customer level prefixes When you configure an invoice to use customer-level numbering, each invoice number begins with the customer’s unique invoice prefix. For example, if one of your customers is a business named Typographic, you might set the prefix to `TYPGRA`. The first invoice number for Typographic would be `TYPGRA-0001`, the second would be `TYPGRA-0002` and so on. ​​You can override prefixes so that you can trace invoices back to your customers. You can set prefixes on the [Customers page](https://dashboard.stripe.com/customers) in the Dashboard or with the API by using the [invoice_prefix](https://docs.stripe.com/api/customers/create.md#create_customer-invoice_prefix) parameter. Prefixes have to be between 3 and 12 characters and they can’t match any other customer prefix, including prefixes that are no longer in use. ### Account level prefixes When you configure an invoice to use account-level numbering, each invoice number starts with a common prefix and has a sequential number. For example, if your business is named Rocket Rides, you might set the prefix to `RKTRIDE`. Your first invoice would be `RKTRIDE-0001`, a second invoice to a different customer would be `RKTRIDE-0002`, another invoice to the first customer would be `RKTRIDE-0003`, and so on. Stripe automatically assigns the account-wide prefix, but you can override it to make it clearer that these invoices come from you. If you want to modify the prefix for your account, you can change it in [Invoice settings](https://dashboard.stripe.com/settings/billing/invoice). This requires that your account’s default API version is at least [2020-03-02](https://docs.stripe.com/upgrades.md#2020-03-02). Prefixes have to be between 3 and 12 characters and they can’t match any customer prefix, including prefixes that are no longer in use. > ​​You can’t use a customer prefix as an account prefix. This includes prefixes that are no longer in use. ### Connect account prefixes When creating invoices with the `on_behalf_of` parameter, Stripe uses the connected account as the merchant of record. Each merchant of record maintains its own separate invoice number sequence, which means: - Each connected account has its own invoice numbering sequence that starts at `0001`. - Invoices for the same customer from different connected accounts (specified using `on_behalf_of`) can have the same invoice number prefix and suffix. - The merchant of record determines which invoice sequence is used, not the platform account. ### Set the next invoice number By default, invoice numbers start at `0001`. If you’d like to use a different starting invoice number, however, you can change it. For example, some users—when migrating existing customers to Stripe Invoicing—want their invoice numbers to continue where their old system left off. If the user left off at invoice number `123` in their old system, Stripe allows them to resume the invoice number at `124`. ​​Set the number on the **Customer details** page or with the API by using the [next_invoice_sequence](https://docs.stripe.com/api/customers/create.md#create_customer-next_invoice_sequence) parameter. If you’re using account-level prefixes, set the next invoice number in the **Next invoice sequence** field in [Invoice settings](https://dashboard.stripe.com/settings/billing/invoice). You can only set the next invoice number to numbers greater than any numbers used on an invoice. The maximum allowed invoice number is 1,000,000,000 regardless of how you set it. Use the lowest value possible so that you don’t reach this limit. ## Invoice fields Learn more about the different Invoice fields, including memo, footer, and custom fields. To set the same value on these fields for groups of customers, you can use [Invoice Templates](https://docs.stripe.com/invoicing/invoice-rendering-template.md). ### Default memo A memo is included in invoice PDFs, invoice emails, and the [Hosted Invoice Page](https://docs.stripe.com/invoicing/hosted-invoice-page.md). Memos are commonly used as a notes section, thanking the invoiced customer for their business, or giving more context around the invoice (such as a note from the salesperson who talked to the customer). You can set a default memo field for your account in [Invoice settings](https://dashboard.stripe.com/settings/billing/invoice). ​​Any new invoices use this value. You can also specify the memo on [Invoice Templates](https://docs.stripe.com/invoicing/invoice-rendering-template.md), which replaces the default memo on invoices using a template. You can specify a different memo for a particular invoice when you create or update it in the Dashboard. You can also specify a memo using the API by calling [update invoice](https://docs.stripe.com/api/invoices/update.md#update_invoice-description) and including the `description` parameter. ### Default footer ​​Invoice PDFs can include an optional footer text block. The footer field is often used for contractual or legally required text. A common use case is displaying legally required company registration information, such as a UK Companies House registration number. Like the memo field, you can set the default footer value in [Invoice settings](https://dashboard.stripe.com/settings/billing/invoice) or specify footers on [Invoice Templates](https://docs.stripe.com/invoicing/invoice-rendering-template.md). ​​You can specify a different footer for a particular draft invoice when you create or update it in the Dashboard, or with the API by calling [update Invoice](https://docs.stripe.com/api/invoices/update.md#update_invoice-footer). If an invoice has been [finalized](https://docs.stripe.com/invoicing/integration/workflow-transitions.md#finalized), you can’t update its footer field. ### Default item prices You can issue invoices with line item prices that exclude inclusive tax. Tax-exclusive prices are only shown in the invoice PDF. That means, when using inclusive tax, the Hosted Invoice Page and invoice emails show tax-inclusive prices. You can define the settings for net prices in the Dashboard or API. - **Include inclusive tax**—The invoice PDF displays line item prices including the inclusive tax. (This is the default.) - **Exclude tax**—The invoice PDF displays line item prices excluding tax. > #### Order precedence > > If you set a default for line item prices at the customer level, it takes precedence over account-level settings. ### Custom fields Add custom fields to enhance your invoice PDF documents and help you comply with your business practice and tax reporting obligations. Custom fields allow you to provide up to four key-value pairs ​​that display in the invoice header. You can set up to four custom field key-value pairs in the [Invoice Editor](https://dashboard.stripe.com/invoices/create), with the [Invoices API](https://docs.stripe.com/api/invoices/create.md#create_invoice-custom_fields), or with [Invoice Templates](https://docs.stripe.com/invoicing/invoice-rendering-template.md). Some common uses for custom fields are: - Purchase Order (PO) numbers - Contractor numbers - Tax compliance #### Custom field inheritance You can set custom invoice fields on the [Customer](https://docs.stripe.com/api/customers/object.md#customer_object-invoice_settings-custom_fields) object. Any custom fields you set at the customer level apply to all of the draft invoices you generate for that customer. You can always modify these inherited custom fields while the invoice is still a draft. After the invoice finalizes, you can’t update the custom fields. ## PDF page size You can set the page size for your invoice PDF, including finalized invoices, to A4 (8.27 x 11.69 inches) or Letter (8.5 x 11 inches). #### Dashboard To set the page size using the Dashboard, go to the [Invoice Editor](https://dashboard.stripe.com/invoices/create), and find the **Advanced options** section. Then, in the **PDF page size** sub-section, select **A4** or **Letter**. #### API To set the page size using the API, you can [create](https://docs.stripe.com/api/invoices/create.md#create_invoice-rendering-pdf) or [update](https://docs.stripe.com/api/invoices/update.md#update_invoice-rendering-pdf) an invoice and set the `rendering["pdf"]["page_size"]` parameter with the preferred page size. The default PDF page size is A4 for customers with a Japanese locale and Letter for customers with other locales. You can set the `rendering["pdf"]["page_size"]` parameter back to `auto` to turn on this default behavior. This is an example of creating an invoice with A4 as the PDF page size: ```curl curl https://api.stripe.com/v1/invoices \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "rendering[pdf][page_size]"=a4 ``` ```cli stripe invoices create \ --customer="{{CUSTOMER_ID}}" \ -d "rendering[pdf][page_size]"=a4 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") invoice = client.v1.invoices.create({ customer: '{{CUSTOMER_ID}}', rendering: {pdf: {page_size: 'a4'}}, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. invoice = client.v1.invoices.create({ "customer": "{{CUSTOMER_ID}}", "rendering": {"pdf": {"page_size": "a4"}}, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $invoice = $stripe->invoices->create([ 'customer' => '{{CUSTOMER_ID}}', 'rendering' => ['pdf' => ['page_size' => 'a4']], ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); InvoiceCreateParams params = InvoiceCreateParams.builder() .setCustomer("{{CUSTOMER_ID}}") .setRendering( InvoiceCreateParams.Rendering.builder() .setPdf( InvoiceCreateParams.Rendering.Pdf.builder() .setPageSize(InvoiceCreateParams.Rendering.Pdf.PageSize.A4) .build() ) .build() ) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Invoice invoice = client.v1().invoices().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const invoice = await stripe.invoices.create({ customer: '{{CUSTOMER_ID}}', rendering: { pdf: { page_size: 'a4', }, }, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.InvoiceCreateParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), Rendering: &stripe.InvoiceCreateRenderingParams{ PDF: &stripe.InvoiceCreateRenderingPDFParams{ PageSize: stripe.String(stripe.InvoiceRenderingPDFPageSizeA4), }, }, } result, err := sc.V1Invoices.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new InvoiceCreateOptions { Customer = "{{CUSTOMER_ID}}", Rendering = new InvoiceRenderingOptions { Pdf = new InvoiceRenderingPdfOptions { PageSize = "a4" }, }, }; var client = new StripeClient("<>"); var service = client.V1.Invoices; Invoice invoice = service.Create(options); ``` ## Group line items To help your customers better understand your invoices (including PDFs, Hosted Invoice Page, and invoice emails), categorize, and display invoice line items under different groups. You can also hide groups of line items. If some line items are excessively detailed, you can configure it so that only their group-level subtotal is visible to your customers. ## Default payment terms Under **Default payment terms** in [Invoice settings](https://dashboard.stripe.com/settings/billing/invoice), you can select when the payment is due after you send the invoice. You can also choose whether to include a link to a payment page in the invoice email. Customers can visit this link to pay, download, and see the status of their invoice. Lastly, you can manage your accepted payment methods in this section. ## Customer preferred languages When you create a customer, use the **Language** dropdown to add their preferred language. (You can also add or edit a customer’s preferred language in the **Customer details** page or when creating an invoice.) Stripe uses the chosen language to localize invoice emails and PDFs, receipt emails and PDFs, as well as credit note PDFs. To update the language through the API, use the [preferred_locales](https://docs.stripe.com/api/customers/object.md#customer_object-preferred_locales) field. Stripe Invoicing supports the following languages: - Bulgarian - Chinese (Hong Kong) - Chinese (Simplified) - Chinese (Taiwan) - Croatian - Czech - Danish - Dutch - English (United Kingdom) - English (United States) - Estonian - Filipino - Finnish - French (Canada) - French (France) - German - Greek - Hungarian - Indonesian - Italian - Japanese - Korean - Latvian - Lithuanian - Malay (Malaysia) - Malayalam - Maltese - Norwegian - Polish - Portuguese (Brazil) - Portuguese (Portugal) - Romanian - Russian - Slovak - Slovenian - Spanish (Latin America) - Spanish (Spain) - Swedish - Thai - Turkish - Vietnamese ## Billing and shipping addresses Stripe uses a customer’s [address](https://docs.stripe.com/api/customers/object.md#customer_object-address) as the billing address on the invoice PDF. You can add or edit a customer’s address on the **Customer details** page. If you don’t set the `address` field, Stripe renders the shipping address as the billing address on the PDF. To render shipping details on the Invoice PDF, set the [shipping_details](https://docs.stripe.com/api/invoices/create.md#create_invoice-shipping_details) field. If you don’t set the `shipping_details` field, Stripe renders the shipping address from the customer’s [shipping](https://docs.stripe.com/api/customers/object.md#customer_object-shipping) field on the PDF. ## Public support information Invoices include any public information that you specified under [Public business information](https://dashboard.stripe.com/settings/public), such as your support email address or business website. Using these settings, you can also choose to include a support phone number in customer-facing documents—like invoice PDFs and emails—or default to your business address. ## See also - [Use the Dashboard](https://docs.stripe.com/invoicing/dashboard.md) - [Hosted Invoice Page](https://docs.stripe.com/invoicing/hosted-invoice-page.md) - [Send customer emails](https://docs.stripe.com/invoicing/send-email.md) --- # Source: https://docs.stripe.com/connect/dashboard.md # Manage connected accounts with the Dashboard Learn about using the Stripe Dashboard to find and manage connected accounts. You can use the Dashboard to inspect, support, and better understand your platform’s connected accounts. The Connected accounts page [displays a list of your connected accounts](https://docs.stripe.com/connect/dashboard/viewing-all-accounts.md) with basic information such as each account’s status and payment balance. You can filter and sort the list to do things such as: - View accounts that are restricted or have other issues that you can help resolve. - View your largest accounts. - View accounts based on their status. - [Review compliance information to take action on requirement updates](https://docs.stripe.com/connect/dashboard/review-compliance-information.md#requirement-updates). Use the instructions provided to make sure that your connected accounts remain [enabled](https://docs.stripe.com/connect/dashboard.md#enabled) when requirements change. For individual connected accounts, some common tasks you can do in the Dashboard include: - [Create accounts](https://docs.stripe.com/connect/dashboard/managing-individual-accounts.md#creating-accounts) - [Find individual accounts](https://docs.stripe.com/connect/dashboard/managing-individual-accounts.md#finding-accounts) - [Update account information](https://docs.stripe.com/connect/dashboard/managing-individual-accounts.md#updating-accounts) - [Send funds to accounts](https://docs.stripe.com/connect/dashboard/managing-individual-accounts.md#sending-funds) ## Status badges Status badges provide a way to understand the status of an account. You can hover over the badges to view contextual information, and you can click the [status tabs](https://docs.stripe.com/connect/dashboard/viewing-all-accounts.md#tabs-workflows) to view accounts grouped by that status. Status badges include: | Status | Description | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | (Restricted) | The account has at least one inactive capability. Additional information usually needs to be collected to enable these accounts. Click on an account to view details about any inactive capabilities and their requirements. If information is required to enable the account, it appears in an **Actions required** list at the top of the Connected account details page. | | (Restricted soon) | The account has currently due requirements with an upcoming due date. If information is required to enable the account, it appears in an **Actions required** list at the top of the Connected account details page. | | (In review) | The account is being reviewed or verified by Stripe. This occurs when: - Stripe is verifying information that was provided, such as an uploaded government-issued ID document. - Stripe is performing a watchlist check against a list of prohibited individuals and businesses. - Stripe is reviewing the account for suspected fraudulent activity. Review times vary depending on the requirement, but they typically last 24–48 hours. | | (Enabled) | The account is in good standing, with all capabilities enabled. Some enabled accounts might eventually become subject to additional requirements if they reach a certain payment volume [threshold](https://docs.stripe.com/connect/identity-verification.md#verification-requirements). These potential requirements appear in an account’s requirements as `eventually_due`, but don’t affect payments or payouts unless the account reaches the volume threshold. If that happens, the `eventually_due` requirements become `currently_due`. If an account has potential eventually due requirements: - **For v2 Accounts:** Eventually due requirements appear in the `Account`’s [requirements.entries](https://docs.stripe.com/api/v2/core/accounts/object.md#v2_account_object-requirements-entries) array with a `minimum_deadline.status` of `eventually_due`. - **For v1 Accounts:** Eventually due requirements appear in the `Account`’s [requirements.eventually_due](https://docs.stripe.com/api/accounts/object.md#account_object-requirements) array. | | (Rejected) | Your platform or Stripe rejected the connected account. Hover over the status badge to see whether your platform or Stripe rejected the account. Check the **Actions required** list at the top of the Connected account details page to see the reason the account was rejected. In general, accounts are rejected by Stripe if they’re suspected of fraudulent activity. | ## Use platform branding for connected accounts This setting only applies to new accounts created by your platform. Existing accounts aren’t affected. To apply your [platform branding settings](https://dashboard.stripe.com/settings/branding) to all new connected accounts, open [Onboarding interface](https://dashboard.stripe.com/settings/connect/onboarding-interface) in your Connect settings, click **Customize**, and enable **Copy platform branding**. When **Copy platform branding** is enabled, elements of your platform branding automatically apply to all new accounts. To update the branding settings of an existing connected account, use the Accounts API: - **Accounts v2:** Update the [configuration.merchant.branding](https://docs.stripe.com/api/v2/core/accounts/update.md#v2_update_accounts-configuration-merchant-branding) hash. - **Accounts v1:** Update the [settings.branding](https://docs.stripe.com/api/accounts/update.md#update_account-settings-branding) hash. ## See also - [Viewing all accounts](https://docs.stripe.com/connect/dashboard/viewing-all-accounts.md) - [Managing individual accounts](https://docs.stripe.com/connect/dashboard/managing-individual-accounts.md) --- # Source: https://docs.stripe.com/get-started/data-migrations.md # Migrate your customer data to Stripe Successfully migrate your customers' data to Stripe. Migrating your customer data to Stripe is a multi-step process. After you read through this guide, you’ll: - Understand the Stripe migration process. - Be able to scope the timeline for your migration. - Know the integration elements required for a successful migration. - Understand how to migrate payment details with minimal disruption to your users. If you run into issues while trying to migrate customer data, contact [Stripe support](https://support.stripe.com/contact/login?email=true&subject=Migration+to+Stripe). ## Build your integration - Develop your data migration plan, starting with new customers. Your end goal is to migrate 100% of new customers, then migrate existing customers. - Design a process for customers to update their card information. ## Learn about the migration process - Review Stripe’s [migration documentation](https://docs.stripe.com/get-started/data-migrations/pan-import.md). - Contact your previous processor to understand their migrations process. ## Plan a migration and connect with an existing processor - Identify which payment details you want to migrate. - Identify which payment methods you want to migrate. - Find out how many customer records you want to migrate. - Plan a migration timeline that considers your previous processor, your customer count, and any upcoming deadlines. - Send the Stripe Migrations team details about your previous processor, Stripe account number, number of records to be migrated, and types of payment methods that you plan to import. ## The Stripe Migrations team - Introduce your existing processor to Stripe’s Migrations team. - Complete any action items or provide any additional information requested by Stripe or your existing processor’s migrations team. ## Migrate and update - Follow communication between Stripe and your previous processor to ensure your team is prepared. - Respond to any issues identified during migration. - Look for an email from the Stripe Migration team with the JSON mapping file. - Parse JSON mapping file and update your database accordingly. - Implement a process for customers to update their card information. - Design your remapping plan, and include *subscription* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) remapping where applicable. - Begin charging existing customers on Stripe. ## PAN data If you need to transfer sensitive payment information to or from another payment processor, or even between Stripe accounts, we can help you do so in a secure and *PCI-compliant* (Any party involved in processing, transmitting, or storing credit card data must comply with the rules specified in the Payment Card Industry (PCI) Data Security Standards. PCI compliance is a shared responsibility and applies to both Stripe and your business) way. The process differs depending on the type of transfer: - [Transfer PAN data from one Stripe account to another Stripe account](https://docs.stripe.com/get-started/data-migrations/pan-copy-self-serve.md) - [Import PAN data to Stripe from another payment processor](https://docs.stripe.com/get-started/data-migrations/pan-import.md) - [Export PAN data from Stripe to another payment processor](https://docs.stripe.com/get-started/data-migrations/pan-export.md) For each type of data migration, we can only assist you if your request includes both customer records and the associated payment data. Use Stripe’s [Customer API](https://docs.stripe.com/api/customers.md) to create, update, or retrieve customer data that doesn’t include payment information. > You can perform PAN data migrations without using Stripe’s Sigma or Data Pipeline products. ## See also - [The Customer object](https://docs.stripe.com/api/customers/object.md) - [The Subscription object](https://docs.stripe.com/api/subscriptions/object.md) - [Default payment source](https://docs.stripe.com/api/customers/object.md#customer_object-default_source) - [Products and prices](https://docs.stripe.com/products-prices/overview.md) - [Billing cycle anchor](https://docs.stripe.com/api/subscriptions/create.md#create_subscription-billing_cycle_anchor) --- # Source: https://docs.stripe.com/revenue-recognition/data-reconciliation.md # Data reconciliation with Stripe reports Learn how to reconcile revenue recognition data with other financial reports. You can reconcile the cash account from Stripe Revenue Recognition and the **Balance Summary** report’s balance change from the activity section within the same month. Because revenue recognition focuses on revenue-generating activities, you must exclude fees, network costs, contributions, and financing paydowns from the **Balance Summary** report’s balance change from the activity section before reconciling. To get the cash amount in Stripe Revenue Recognition, download the balance sheet report in the summary format. The balance sheet report doesn’t take corrections into account. If you have corrections for the month that you’re attempting to reconcile reports for, you must also consider the revenue recognition corrections summary reports for all subsequent months. You must factor any corrections that would have been booked to the `original_accounting_period` of the reconciliation month into the Stripe Revenue Recognition cash amount. ## Example As an example, the balance sheet report might look like the following, with a 100 USD amount: | account | currency | net change | | ------- | -------- | ---------- | | Cash | usd | +100.00 | | Cash | eur | +15.00 | To get the cash amount in the **Balance Summary** report’s balance change from the activity section, set the currency to USD, and the report timezone to UTC. Revenue recognition and **Balance Summary** use different timestamps associated with a transaction. This discrepancy can lead to mismatches in reconciliation if a payment takes a long time to process. After downloading the report in the summary format, it might look like the following: | reporting category | currency | gross | fee | net | | -------------------------- | -------- | ------- | ------ | ------- | | `charge` | usd | +140.00 | -10.00 | +130.00 | | `refund` | usd | -40.00 | 0.00 | -40.00 | | `refund_failure` | usd | +20.00 | 0.00 | +20.00 | | `partial_capture_reversal` | usd | -20.00 | 0.00 | -20.00 | | `fee` | usd | -10.00 | 0.00 | -10.00 | | `network_cost` | usd | -10.00 | 0.00 | -10.00 | | `contribution` | usd | -10.00 | 0.00 | -10.00 | | `financing_paydown` | usd | -10.00 | 0.00 | -10.00 | | `total` | usd | +60.00 | -10.00 | +50.00 | For reports prior to March 2025, the total gross amount excludes some Stripe fees. After deducting rows for additional Stripe fees, network costs, contributions, and financing paydowns, the calculated cash amount is 100 USD. For reports on or after March 2025, the cash amount displayed in the Revenue Recognition balance sheet already accounts for Stripe fees. The net change in cash from the balance sheet is 50 USD, matching the net total amount. ## Journal entries The journal entries in the **Debits and credits** report don’t consider fees, network costs, contributions, and financing paydowns. However, you can use Stripe fees in your revenue recognition reporting to create journal entries for these items. As of March 1, 2025, journal entries in the **Debits and credits** report automatically incorporate fees, network costs, and contributions. Stripe fees for charges paid before March are not displayed to prevent showing only a portion of the total fee. As a result, discrepancies might arise when these fees are associated with charges in later periods, such as during disputes. To enable Stripe fees support in Stripe Revenue Recognition for all accounting periods and avoid the discrepancies, [contact support](https://support.stripe.com/contact/email?topic=financial_reports). With Stripe fees enabled, you can do the following to reconcile revenue recognition fees with the [Balance Summary](https://docs.stripe.com/reports/balance.md) report’s balance change from the activity section: 1. Download the **Balance change from activity** report in the summary format. Make sure you select these columns: **Reporting Category**, **Gross**, and **Fee**. 1. Calculate the total fee by summing the values in these columns: - **Gross** column: fee, network cost, and contribution - **Fee** column: total In the following example, you calculate the total fees: `-1000.00 + -0.50 + -0.40 + -1.00` to get the sum: `-1001.90`. | reporting category | gross | fee | | ------------------------- | ------------ | --------- | | `charge` | 100.00 | -4.00 | | `refund` | -100.00 | 3.00 | | `platform earning refund` | -0.10 | 0.00 | | `fee` | **-1000.00** | 0.00 | | `network cost` | **-0.50** | 0.00 | | `contribution` | **-0.40** | 0.00 | | `total` | -1001.00 | **-1.00** | If you download the **Debits and credits** report in the summary format, you can see `1001.90` debited from the Fees expense account and credited to the Cash account. The **Debits and credits** report doesn’t take corrections into account. If there were corrections issued for the month for which you’re attempting to reconcile reports, you must also consider the revenue recognition corrections summary reports for all subsequent months. Any corrections that would have been booked to the `original_accounting_period` of the reconciliation month must be factored into the Stripe Revenue Recognition cash amount. | debit | credit | amount | | ----- | ------ | ------- | | Fees | Cash | 1001.90 | --- # Source: https://docs.stripe.com/financial-accounts/connect/moving-money/out-of/debit-reversals.md # Moving money using DebitReversal objects Learn how you can retrieve funds taken out of a financial account from an external account holder. Returning the funds from a [ReceivedDebit](https://docs.stripe.com/api/treasury/received_debits.md) creates a [DebitReversal](https://docs.stripe.com/api/treasury/debit_reversals.md). You can get the funds back from a `ReceivedDebit` in only some scenarios (detailed in the following table). Whether you can return the funds of a `ReceivedDebit` depends on the network and source flow. The `reversal_details` sub-hash on the `ReceivedDebit` resource can have the following combination of values, which determines whether you can return the `ReceivedDebit` funds. | RESTRICTED REASON | DEADLINE (EPOCH TIMESTAMP) | EXAMPLE SCENARIO | | ------------------------ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `null` | 7940828047 | A `ReceivedDebit` that you can return funds from, but only until the timestamp in `deadline`. ACH `ReceivedDebits` have a deadline that determines how long you have to return them. | | `deadline_passed` | 1629480538 | A `ReceivedDebit` whose funds were returnable before the timestamp in `deadline`, but is no longer returnable using the API because the `deadline` has passed. ACH `ReceivedDebits` have a limited time of when they’re returnable using the API after they’re created. | | `already_reversed` | null | A `ReceivedDebit` that’s already been returned. It might have a non-null `deadline` value. | | `source_flow_restricted` | null | A `ReceivedDebit` that can’t be returned because its `source_flow` isn’t reversible. | ## Return deadlines You have approximately 1 business day to return ACH debits using the API after receipt. After this time, ACH debit funds might still be returnable but funds return isn’t guaranteed. Contact support to request a return of funds if the reversal deadline has passed. To create returns of `ReceivedDebit` funds produced by activity on `Issuing` cards, see the [Issuing disputes](https://docs.stripe.com/issuing/purchases/disputes.md) guide. ## Create a DebitReversal Use `POST /v1/treasury/debit_reversals` to create a `DebitReversal`. Specify the ID of the `ReceivedDebit` to reverse with the `received_debit` parameter in the body of the request. > You can’t update `DebitReversals`, so you must set any optional [metadata](https://docs.stripe.com/api/treasury/debit_reversals/object.md#debit_reversal_object-metadata) on creation. The following request creates a `DebitReversal` based on the `ReceivedDebit` ID value on the required `received_debit` parameter. The request also sets an optional metadata value. ```curl curl https://api.stripe.com/v1/treasury/debit_reversals \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d received_debit={{RECEIVED_DEBIT_ID}} \ -d "metadata[reason]"=Because ``` ```cli stripe treasury debit_reversals create \ --stripe-account {{CONNECTEDACCOUNT_ID}} \ --received-debit={{RECEIVED_DEBIT_ID}} \ -d "metadata[reason]"=Because ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") debit_reversal = client.v1.treasury.debit_reversals.create( { received_debit: '{{RECEIVED_DEBIT_ID}}', metadata: {reason: 'Because'}, }, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. debit_reversal = client.v1.treasury.debit_reversals.create( {"received_debit": "{{RECEIVED_DEBIT_ID}}", "metadata": {"reason": "Because"}}, {"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $debitReversal = $stripe->treasury->debitReversals->create( [ 'received_debit' => '{{RECEIVED_DEBIT_ID}}', 'metadata' => ['reason' => 'Because'], ], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); DebitReversalCreateParams params = DebitReversalCreateParams.builder() .setReceivedDebit("{{RECEIVED_DEBIT_ID}}") .putMetadata("reason", "Because") .build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. DebitReversal debitReversal = client.v1().treasury().debitReversals().create(params, requestOptions); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const debitReversal = await stripe.treasury.debitReversals.create( { received_debit: '{{RECEIVED_DEBIT_ID}}', metadata: { reason: 'Because', }, }, { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TreasuryDebitReversalCreateParams{ ReceivedDebit: stripe.String("{{RECEIVED_DEBIT_ID}}"), } params.AddMetadata("reason", "Because") params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result, err := sc.V1TreasuryDebitReversals.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Treasury.DebitReversalCreateOptions { ReceivedDebit = "{{RECEIVED_DEBIT_ID}}", Metadata = new Dictionary { { "reason", "Because" } }, }; var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Treasury.DebitReversals; Stripe.Treasury.DebitReversal debitReversal = service.Create(options, requestOptions); ``` If successful, the response returns the new `DebitReversal` object. ```json { "id": "{{DEBIT_REVERSAL_ID}}", "object": "debit_reversal", "amount": 1000, "currency": "usd", "financial_account": "{{FINANCIAL_ACCOUNT_ID}}", "hosted_regulatory_receipt_url": "https://payments.stripe.com/regulatory-receipt/{{URL_ID}}", "linked_flows": null, "livemode": false, "metadata": {}, "network": "ach", "received_debit": "{{RECEIVED_DEBIT_ID}}", "resolution": null, "status": "processing", "status_transitions": { "completed_at": null }, "transaction": "{{TRANSACTION_ID}}" } ``` ## Retrieve a DebitReversal Use `GET /v1/treasury/debit_reversals/{{DEBIT_REVERSAL_ID}}` to retrieve the `DebitReversal` with the associated ID. ```curl curl https://api.stripe.com/v1/treasury/debit_reversals/{{DEBIT_REVERSAL_ID}} \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" ``` ```cli stripe treasury debit_reversals retrieve {{DEBIT_REVERSAL_ID}} \ --stripe-account {{CONNECTEDACCOUNT_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") debit_reversal = client.v1.treasury.debit_reversals.retrieve( '{{DEBIT_REVERSAL_ID}}', {}, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. debit_reversal = client.v1.treasury.debit_reversals.retrieve( "{{DEBIT_REVERSAL_ID}}", options={"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $debitReversal = $stripe->treasury->debitReversals->retrieve( '{{DEBIT_REVERSAL_ID}}', [], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); DebitReversalRetrieveParams params = DebitReversalRetrieveParams.builder().build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. DebitReversal debitReversal = client.v1().treasury().debitReversals().retrieve( "{{DEBIT_REVERSAL_ID}}", params, requestOptions ); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const debitReversal = await stripe.treasury.debitReversals.retrieve( '{{DEBIT_REVERSAL_ID}}', { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TreasuryDebitReversalRetrieveParams{} params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result, err := sc.V1TreasuryDebitReversals.Retrieve( context.TODO(), "{{DEBIT_REVERSAL_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Treasury.DebitReversals; Stripe.Treasury.DebitReversal debitReversal = service.Get( "{{DEBIT_REVERSAL_ID}}", null, requestOptions); ``` If successful, the response returns the identified `DebitReversal`. #### JSON (commented) ```json { "id": "{{DEBIT_REVERSAL_ID}}", "object": "debit_reversal", "livemode": true | false, "created": "{{Timestamp}}", "financial_account": "{{FINANCIAL_ACCOUNT_ID}}", "amount": 1000, "currency": "usd", // the ReceivedDebit being returned "received_debit": "{{RECEIVED_DEBIT_ID}}", // whether funds have been returned depending on the DebitReversal outcome "resolution": null | "won", "status": "processing" | "canceled" | "completed", "status_transitions": { "processing_at": "{{Timestamp}}", "canceled_at": null | "{{Timestamp}}", "completed_at": null | "{{Timestamp}}" }, // Transaction representing balance impact of the DebitReversal "transaction": "{{TRANSACTION_ID}}", // A unique, Stripe-hosted direct link to the regulatory receipt for the DebitReversal "hosted_regulatory_receipt_url": "{{Url}}", // A map of String-String intended for users to use custom data "metadata": {} } ``` #### JSON ```json { "id": "{{DEBIT_REVERSAL_ID}}", "object": "debit_reversal", "livemode": false, "created": 123456, "financial_account": "{{FINANCIAL_ACCOUNT_ID}}", "amount": 1000, "currency": "usd", "received_debit": "{{RECEIVED_DEBIT_ID}}", "resolution": null, "status": "completed", "status_transitions": { "processing_at": 123456, "canceled_at": null, "completed_at": null }, "transaction": "{{TRANSACTION_ID}}", "hosted_regulatory_receipt_url": "https://example.com", "metadata": {} } ``` ## List DebitReversals Use `GET /v1/treasury/debit_reversals` to retrieve a list of `DebitReversals` for the financial account with the ID provided in the required `financial_account` parameter. You can filter the list by standard list parameters, `status`, or by `ReceivedDebit` ID using the `received_debit` parameter. ``` { // Standard list parameters "limit", "starting_after", "ending_before", // Filter by financial account (Required) "financial_account": "{{FINANCIAL_ACCOUNT_ID}}", // Filter by `status` "status": "processing" | "canceled" | "completed" // Filter by ReceivedDebit "received_debit": "{{RECEIVED_DEBIT_ID}}", } ``` The following request retrieves the last three [DebitReversal objects](https://docs.stripe.com/api/treasury/debit_reversals/object.md) for the identified financial account. ```curl curl -G https://api.stripe.com/v1/treasury/debit_reversals \ -u "<>:" \ -H "Stripe-Account: {{CONNECTEDACCOUNT_ID}}" \ -d financial_account="{{TREASURYFINANCIALACCOUNT_ID}}" \ -d limit=3 ``` ```cli stripe treasury debit_reversals list \ --stripe-account {{CONNECTEDACCOUNT_ID}} \ --financial-account="{{TREASURYFINANCIALACCOUNT_ID}}" \ --limit=3 ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") debit_reversals = client.v1.treasury.debit_reversals.list( { financial_account: '{{TREASURYFINANCIALACCOUNT_ID}}', limit: 3, }, {stripe_account: '{{CONNECTEDACCOUNT_ID}}'}, ) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. debit_reversals = client.v1.treasury.debit_reversals.list( {"financial_account": "{{TREASURYFINANCIALACCOUNT_ID}}", "limit": 3}, {"stripe_account": "{{CONNECTEDACCOUNT_ID}}"}, ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $debitReversals = $stripe->treasury->debitReversals->all( [ 'financial_account' => '{{TREASURYFINANCIALACCOUNT_ID}}', 'limit' => 3, ], ['stripe_account' => '{{CONNECTEDACCOUNT_ID}}'] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); DebitReversalListParams params = DebitReversalListParams.builder() .setFinancialAccount("{{TREASURYFINANCIALACCOUNT_ID}}") .setLimit(3L) .build(); RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{{CONNECTEDACCOUNT_ID}}").build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. StripeCollection stripeCollection = client.v1().treasury().debitReversals().list(params, requestOptions); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const debitReversals = await stripe.treasury.debitReversals.list( { financial_account: '{{TREASURYFINANCIALACCOUNT_ID}}', limit: 3, }, { stripeAccount: '{{CONNECTEDACCOUNT_ID}}', } ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.TreasuryDebitReversalListParams{ FinancialAccount: stripe.String("{{TREASURYFINANCIALACCOUNT_ID}}"), } params.Limit = stripe.Int64(3) params.SetStripeAccount("{{CONNECTEDACCOUNT_ID}}") result := sc.V1TreasuryDebitReversals.List(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Treasury.DebitReversalListOptions { FinancialAccount = "{{TREASURYFINANCIALACCOUNT_ID}}", Limit = 3, }; var requestOptions = new RequestOptions { StripeAccount = "{{CONNECTEDACCOUNT_ID}}", }; var client = new StripeClient("<>"); var service = client.V1.Treasury.DebitReversals; StripeList debitReversals = service.List( options, requestOptions); ``` ## Test DebitReversals To test `DebitReversals`, you must first create a [test ReceivedDebit](https://docs.stripe.com/financial-accounts/connect/moving-money/out-of/debit-reversals.md#test-received-debit). Afterwards, use `POST /v1/treasury/debit_reversals` and specify the test `ReceivedDebit` ID in the `received_debit` parameter to create a test `DebitReversal`. ## DebitReversal webhooks Stripe emits the following `DebitReversal` events to your [webhook](https://docs.stripe.com/webhooks.md) endpoint: - `treasury.debit_reversal.created` on `DebitReversal` creation. - `treasury.debit_reversal.completed` when the `DebitReversal` completes. --- # Source: https://docs.stripe.com/declines.md # Declines Learn about payment declines and how to lower your decline rate. Track your decline rate over time to identify potential fraud or integration issues. For a clearer overview of your authorization rates, analyze unique declines and exclude failed retries from your analysis. Payments can fail for a variety of reasons, including some that help prevent fraudulent transactions. Stripe works to reduce decline rates across all supported payment methods. We work with issuers and networks to improve acceptance rates, often without affecting your integration. There are three reasons why a payment might fail: - [Issuer declines](https://docs.stripe.com/declines.md#issuer-declines) - [Blocked payments](https://docs.stripe.com/declines.md#blocked-payments) - [Invalid API calls](https://docs.stripe.com/declines.md#invalid-api-calls) You need to handle each type of payment failure differently. For every failure, you can use the [Dashboard](https://dashboard.stripe.com/payments) or API to review a payment’s details. When using the API, look at the `Charge` object’s [outcome](https://docs.stripe.com/api/charges/object.md#charge_object-outcome). This attribute covers the payment failure type and provides information about its cause. Stripe handles non-card payment method declines similarly to card declines. Stripe sends you a response code that includes information about the decline, for example, if it’s due to insufficient funds, a lost or stolen card, or another reason. ## Issuer declines When your customer’s card issuer or payment provider receives a charge, their automated systems and models decide whether to authorize it. These tools analyze signals such as spending habits, account balance, and card data (expiration date, address information, and CVC). If the card issuer or payment provider declines a payment, Stripe shares with you the decline information we receive through [Stripe decline codes](https://docs.stripe.com/declines/codes.md). This information is available in the Dashboard and through the API. When issuers provide specific explanations, such as an incorrect card number or low funds, these explanations return to Stripe as [network decline codes](https://docs.stripe.com/declines/network-codes.md). ## Blocked payments *Stripe Radar* (Stripe Radar helps detect and block fraud for any type of business using machine learning that trains on data across millions of global companies. It’s built into Stripe and requires no additional setup to get started) blocks high risk payments, including those that violate your custom rules or have high risk scores. This automated fraud prevention product evaluates each payment, without requiring any action from you. When Stripe blocks a payment, it doesn’t obtain authorization from the card issuer. This precaution helps prevent potential fraudulent payments that might lead to disputes. For some card types, customers might see the card issuer’s authorization for the payment amount on their statement. However, Stripe hasn’t charged this amount or withdrawn funds. The card issuer typically removes this authorization from the customer’s statement within a few days. If a rule you configured blocks a payment you recognize as legitimate, you can lift the block by locating the payment in the [Dashboard](https://dashboard.stripe.com/payments) and clicking **Add to allow list**. This action doesn’t retry the payment. Instead, it overrides all of your other rules from blocking future payment attempts that match the list attribute. > Don’t see the **Add to allow list** button on the payment details page? [Contact Stripe](https://support.stripe.com/email) to add this feature to your Radar account. When using the API, the `outcome` of a blocked payment reflects the type of payment failure and the reason for it, along with the evaluated risk level. ```json ... outcome: { network_decline_code: null, network_advice_code: null, network_status: "not_sent_to_network", reason: "highest_risk_level", advice_code: "do_not_try_again", risk_level: "highest", seller_message: "Stripe blocked this charge as too risky.", type: "blocked" }, ... ``` For users with [IC+ pricing](https://support.stripe.com/questions/understanding-blended-interchange-pricing), Adaptive Acceptance blocks certain payments to help you avoid unnecessary network costs. For example, Adaptive Acceptance helps you avoid excessive retry penalties. Adaptive Acceptance can also help you avoid network costs by blocking payments that have low likelihood of authorization. ```json ... outcome: { network_decline_code: null, network_advice_code: null, network_status: "not_sent_to_network", reason: "low_probability_of_authorization", advice_code: "do_not_try_again", risk_level: "normal", seller_message: "Stripe blocked this payment as it is unlikely to be authorized.", type: "blocked" }, ... ``` ## Invalid API calls In the API, you might see an invalid API call like the following: ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=2000 \ -d currency=usd \ -d payment_method=pm_card_chargeDeclinedIncorrectCvc \ -d confirm=true ``` ```cli stripe payment_intents create \ --amount=2000 \ --currency=usd \ --payment-method=pm_card_chargeDeclinedIncorrectCvc \ --confirm=true ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") payment_intent = client.v1.payment_intents.create({ amount: 2000, currency: 'usd', payment_method: 'pm_card_chargeDeclinedIncorrectCvc', confirm: true, }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. payment_intent = client.v1.payment_intents.create({ "amount": 2000, "currency": "usd", "payment_method": "pm_card_chargeDeclinedIncorrectCvc", "confirm": True, }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $paymentIntent = $stripe->paymentIntents->create([ 'amount' => 2000, 'currency' => 'usd', 'payment_method' => 'pm_card_chargeDeclinedIncorrectCvc', 'confirm' => true, ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(2000L) .setCurrency("usd") .setPaymentMethod("pm_card_chargeDeclinedIncorrectCvc") .setConfirm(true) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. PaymentIntent paymentIntent = client.v1().paymentIntents().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const paymentIntent = await stripe.paymentIntents.create({ amount: 2000, currency: 'usd', payment_method: 'pm_card_chargeDeclinedIncorrectCvc', confirm: true, }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.PaymentIntentCreateParams{ Amount: stripe.Int64(2000), Currency: stripe.String(stripe.CurrencyUSD), PaymentMethod: stripe.String("pm_card_chargeDeclinedIncorrectCvc"), Confirm: stripe.Bool(true), } result, err := sc.V1PaymentIntents.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new PaymentIntentCreateOptions { Amount = 2000, Currency = "usd", PaymentMethod = "pm_card_chargeDeclinedIncorrectCvc", Confirm = true, }; var client = new StripeClient("<>"); var service = client.V1.PaymentIntents; PaymentIntent paymentIntent = service.Create(options); ``` The invalid API call generates an error response that might look like this: ```json { "error": { "code": "incorrect_cvc", "doc_url": "https://stripe.com/docs/error-codes/incorrect-cvc", "message": "Your card's security code is incorrect.", "param": "cvc", "type": "card_error" } } ``` The [outcome](https://docs.stripe.com/api.md#charge_object-outcome) of a declined payment includes the type of payment failure and the [reason](https://docs.stripe.com/api.md#charge_object-outcome-reason), based on the card network’s decline code. The reason might contain information other than the card network’s response code, for example, if a Radar rule evaluation blocked the charge. ```json ... outcome: { network_decline_code: "54", network_advice_code: "03", network_status: "declined_by_network", reason: "expired_card", advice_code: "confirm_card_data", risk_level: "normal", seller_message: "The bank returned the decline code `expired_card`.", type: "issuer_declined" }, ... ``` As you develop your Stripe integration, continuously [test](https://docs.stripe.com/testing.md) it to identify any potential bugs that might lead to invalid API calls. Invalid API calls typically don’t result in a payment appearing in your Dashboard. However, you might see the payment appear in a few cases. ```json ... outcome: { network_decline_code: null, network_advice_code: null, network_status: "not_sent_to_network", type: "invalid" }, ... ``` ## See also - [Card declines](https://docs.stripe.com/declines/card.md) - [Test declined payments](https://docs.stripe.com/testing.md#declined-payments) - [Refund and cancel payments](https://docs.stripe.com/refunds.md) - [Automate payment retries](https://docs.stripe.com/billing/revenue-recovery/smart-retries.md) --- # Source: https://docs.stripe.com/use-stripe-apps/netsuite/deposit-automation.md # Deposit automation Use the connector to automate the bank reconciliation process. To learn more and get a demo of the Stripe Connector for NetSuite, go to the [Stripe App Marketplace](https://marketplace.stripe.com/apps/netsuite-connector) and click **Install app**. The Stripe Connector for NetSuite automates the bank reconciliation process by creating bank deposits in NetSuite for all of your [Stripe payouts](https://docs.stripe.com/use-stripe-apps/netsuite/stripe-payouts-netsuite.md). The connector also automates fee calculation, the refund life cycle, the dispute life cycle, and handling of multiple currencies and subsidiaries. This means you only need to match the bank deposit record to the Stripe deposits on your bank statement, reducing the amount of manual work required each month. Every automated payment workflow that the connector supports includes deposit automation. ## How it works When you use the connector, the automated bank reconciliation process occurs daily as follows: 1. The connector creates payments and refunds for each Stripe transaction, and posts these transactions in the Undeposited Funds account in NetSuite. 1. Stripe notifies the connector that a bank transfer (Stripe payout) has successfully arrived at your bank. 1. The connector creates a bank deposit record in NetSuite that contains all of the payments, refunds, and disputes from that day’s bank deposit. 1. The connector calculates any fees for processing, currency conversion, disputes, and refunds, and includes these as separate line items that post to your specified expense accounts. 1. The connector ensures that the deposit total and deposit date match your bank statement. A diagram providing a high level overview of the deposit automation flow outlined in this doc (See full diagram at https://docs.stripe.com/use-stripe-apps/netsuite/deposit-automation) ## See also - [Charges in NetSuite](https://docs.stripe.com/use-stripe-apps/netsuite/stripe-charges-netsuite.md) - [Payouts in NetSuite](https://docs.stripe.com/use-stripe-apps/netsuite/stripe-payouts-netsuite.md) - [Disputes in NetSuite](https://docs.stripe.com/use-stripe-apps/netsuite/stripe-disputes-netsuite.md) - [Refunds in NetSuite](https://docs.stripe.com/use-stripe-apps/netsuite/stripe-refunds-netsuite.md) --- # Source: https://docs.stripe.com/billing/subscriptions/design-an-integration.md # Source: https://docs.stripe.com/connect/design-an-integration.md # Design an advanced Connect integration using the Accounts v1 API Learn about alternative configuration combinations for a Connect integration based on the Accounts v1 API. > #### Accounts v2 API integrations > > This guide only applies to existing Connect platforms that use the Accounts v1 API. If you’re a new Connect user, use the Accounts v2 API instead. See the [Interactive platform guide](https://docs.stripe.com/connect/interactive-platform-guide.md) for information about how to configure a Connect platform using the Accounts v2 API. Use this guide to explore different Connect integrations and create a list of personalized integration steps. Before starting your integration in a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment, you must [create a Stripe Account or log in](https://dashboard.stripe.com) and [onboard your platform to Connect](https://dashboard.stripe.com/settings/connect/platform-profile). ## Select properties ### Create and onboard accounts Stripe enables you to create accounts on behalf of users, called connected accounts. When using Connect, you create connected accounts for each user that receives money on your platform. #### Item 1 Send connected accounts to a Stripe-hosted onboarding flow. Stripe-hosted onboarding allows you to redirect your user to Stripe to complete the onboarding process in a co-branded interface. ![Screenshot of Connect Onboarding form](https://b.stripecdn.com/docs-statics-srv/assets/Kavholm-Seamless-Standard.78b64d90c0bf87130c8b6ba1ef53df7f.png) Best for when you want to launch quickly with the lowest integration effort: - Connected accounts leave your site and are redirected to Stripe to complete the flow. - Co-branding with Stripe and limited options to customize. - Stripe handles all of the onboarding flow logic. - Automatically supports 46+ countries and 14 languages. #### Item 2 Embed a highly themeable onboarding UI with limited Stripe branding directly into your application. Connected account users interact with the embedded component without ever leaving your application. You can integrate embedded onboarding in a few lines of code. Note: The following is a preview/demo component that behaves differently than live mode usage with real connected accounts. The actual component has more functionality than what might appear in this demo component. For example, for connected accounts without Stripe dashboard access (custom accounts), no user authentication is required in production. Best for when you want to keep users on your site with a more integrated experience and a low integration effort: - Connected accounts remain on your site. - Highly themable. Limited to no Stripe branding. - Stripe handles all the onboarding flow logic. - Automatically supports 46+ countries and 14 languages. #### Item 3 Build out each aspect of the onboarding flow by calling the corresponding Stripe APIs. You need to build custom logic in your integration to satisfy all required verification information. > #### Stripe recommendation > > Building and maintaining an API onboarding flow is resource-intensive and requires regular updates. If you want to implement a customized onboarding flow, Stripe strongly recommends that you use [embedded onboarding](https://docs.stripe.com/connect/embedded-onboarding.md). (See full diagram at https://docs.stripe.com/connect/design-an-integration) Best for when you want to have full control over the onboarding flow: - Build and maintain all onboarding flow logic yourself. Can be resource intensive and expensive to build. - You manage risk with full responsibility for negative balance liabilities on connected accounts. - You must keep your flows up to date as verification requirements change, and also build additional flows to communicate and collect such requirements from your users. Review and update onboarding requirements at least every six months to make sure you build the latest requirements into your flow. - You must build a custom form to collect bank accounts or debit cards so that connected accounts can be set up with a payout account. ### Set up dashboard flows Connected accounts need access to a dashboard to manage their account. Provide connected accounts with access to the Stripe Dashboard, the Express Dashboard, or a dashboard built using the Stripe API and embedded components. #### Item 1 Provide access to the Stripe Dashboard to connected accounts. The Stripe Dashboard provides connected accounts with a full suite of functionality, including viewing payouts, managing refunds, handling disputes, accessing reporting, and processing charges on their own. Users can sign into their Stripe Dashboard at any time and can access the Dashboard by visiting Stripe directly. Users have access to Stripe support and Stripe can reach out and communicate with users about their account. Use the Stripe Dashboard when: - Your users need access to powerful payments workflows and advanced user management features. - You prefer Stripe to manage risk of loss and take responsibility for negative balance liability on connected accounts. - You are comfortable with Stripe branding and limited platform co-branding. You can always add [embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md) to your own website in tandem with providing access to the Stripe Dashboard. #### Item 2 Provide access to the Express dashboard for connected accounts to manage their account. The Express Dashboard enables connected accounts to view their available balance, see upcoming payouts, and track their earnings in real time. Users can’t manage refunds or disputes through the Express dashboard. Users have access to Stripe support and Stripe can reach out and communicate with users about their account. Use the Express Dashboard when: - Your users are marketplace sellers that need limited access to workflows. - You primarily send payouts to these users. Users won’t manage refunds or disputes directly. - You want to fully brand the dashboard look and feel. - You are comfortable taking responsibility for negative balance liability and managing risk of loss on connected accounts. You can always add [Connect embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md) to your own website in tandem with providing access to the Stripe Dashboard. #### Item 3 Create a dashboard using Stripe APIs or embedded components to enable connected accounts to manage their account. Connected accounts won’t have access to the Stripe Dashboard or Express Dashboard. It’s up to you to provide access to these workflows by building your user’s dashboard, refunds, disputes workflows and reporting functionality. Your users might not realize that they have a Stripe account through your platform. We recommend integrating [Connect embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md) to add dashboard functionality to your platform application with a low integration effort. Embedded components are highly themable and can support connected accounts with: - Payments workflows such as viewing payments and payouts, managing refunds and responding to disputes - Payout workflows such as managing payout schedules, creating manual payouts or updating payout accounts - Reporting workflows to download and export payments and payouts - Account management workflows such as updating business information > For an account without Stripe-hosted Dashboard access where Stripe is liable for negative balances, use Connect embedded components to provide self-serve account updates. You can’t create [Account Links](https://docs.stripe.com/api/account_links.md) of type `account_update` for such accounts. ### Accept a payment You create a charge to accept a payment from a customer on behalf of your connected account. The type of charge you create: - Determines how payment funds are split among all parties involved - Impacts how the charge appears on the customer’s bank or billing statement (with your platform’s information or your user’s) - Determines which account Stripe debits for refunds and chargebacks #### Item 1 A direct charge is a customer payment made directly to a connected account. Customers directly transact with your connected account, often unaware of your platform’s existence. This charge type is best suited for platforms providing software as a service. For example, Shopify provides tools for building online storefronts, and Thinkific enables educators to sell online courses. #### Item 2 Create destination charges on your platform and immediately transfer funds to connected accounts. Customers transact with your platform for products or services provided by your connected accounts. This charge type is best suited for marketplaces such as Airbnb, a home rental marketplace or Lyft, a ridesharing app. Destination charges are created on the platform, but as part of the charge operation, funds are immediately transferred to the connected account you specified. You can decide whether some or all of those funds are transferred. Unless you’re eligible for [cross-border payouts](https://docs.stripe.com/connect/cross-border-payouts.md), your platform and the connected account you transfer funds to must be in the same region to create a Destination charge. Attempting to transfer funds across a disallowed border returns an error. #### Item 3 Create separate charges and transfers to transfer funds from one payment to multiple connected accounts, or when a specific user isn’t known at the time of charge. The charge on your platform account is decoupled from the transfers to your connected accounts. This charge type is best suited for marketplaces that need to split payments between multiple parties, such as DoorDash, a restaurant delivery platform. While separate charges and transfers provide a lot of flexibility, they require a more complex integration to manage account balances between your platform and your users. You must monitor your platform account balance carefully to make sure you have enough available funds to cover the transfer amount. Unless you’re eligible for [cross-border payouts](https://docs.stripe.com/connect/cross-border-payouts.md), your platform and the connected account you transfer funds to must be in the same region to use separate charges and transfers. Attempting to transfer funds across a disallowed border returns an error. ### Stripe fees #### Item 1 Stripe collects Stripe fees from your platform account, inclusive of processing fees. You control the processing fee amounts you bill connected accounts. Use the application fee parameter to collect processing fees from your connected accounts. #### Item 1 (See full diagram at https://docs.stripe.com/connect/design-an-integration) #### Item 2 (See full diagram at https://docs.stripe.com/connect/design-an-integration) #### Item 3 (See full diagram at https://docs.stripe.com/connect/design-an-integration) #### Item 2 Stripe collects Stripe fees directly from your connected accounts. You can collect an optional application fee when you create the direct charge. (See full diagram at https://docs.stripe.com/connect/design-an-integration) ### Pay out users When the funds from the payment settle and your user’s connected account has a positive Stripe balance, you can pay out those funds to their external account. #### Item 1 If you onboard users in your own flow using the Stripe API, you must also collect bank accounts or debit cards to set up your connected accounts with a payout account. When you’ve collected the user’s information for the payout account, attach it as an external account. Payouts are blocked if your connected account doesn’t have a verified external account. #### Item 2 #### Item 3 By default, Stripe pays out funds that have settled in your connected accounts’ balances on a daily rolling basis. If you prefer, you can configure different automatic payout schedules, trigger payouts manually instead of automatically, or pay out instantly. ### Responsibility for negative balances #### Item 1 Your platform is liable for losses incurred by negative balances on your connected accounts. Your platform is responsible for reviewing new connected accounts during onboarding and determining the risk profile of your users. Recommended for marketplaces that collect payments from buyers to payout sellers, or for advanced platforms that want full control over how risk and negative liabilities are managed on connected accounts: - Your platform must monitor connected accounts for ongoing risk of loss. - Your platform has to build flows to communicate and remediate connected accounts when you detect fraud or risk. - You have both the operational team and the engineering resources to establish processes for managing ongoing risk of loss and preventing fraud. Before creating accounts with this setup, carefully consider and acknowledge your platform responsibilities for negative balance liabilities. #### Item 2 Stripe monitors risk signals on connected accounts, implements risk interventions on connected accounts in response to observed signals, and seeks to recover negative balances from your connected accounts. For most software as a service platforms, this is the best default choice, especially for those that are new to embedding payments: - Stripe monitors your connected accounts for credit and fraud risk, as well as protection against risk of loss in the event of negative balances attributed to business risk. - Stripe handles all the end to end communications and remediations directly with your connected accounts through hosted flows or embedded components. #### Item 1 #### Required embedded components When Stripe is responsible for negative balances on your connected accounts, you must integrate embedded components for onboarding, account management, and the notification banner. Stripe uses the embedded notification banner component to notify connected accounts of outstanding requirements or other managed risk related requests. The account management component is required so your connected accounts can manage their authentication credentials and their business information. Stripe also emails your connected accounts on your behalf to manage risk and confirm ongoing compliance. You can customize and brand these email communications with your own email domain and platform branding. For any other optional components, you can also use [embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md) or build your own UI. #### Item 2 #### Item 3 ## Integration steps for your selections The following integration steps are based on the options you selected above. You can see different steps by selecting different options above or in the panel to the right of the steps. The options on this page only control the steps displayed below. They don’t affect your platform configuration. The following button generates an LLM prompt based on your selections. It only supports Stripe-hosted Dashboard and hosted onboarding. --- # Source: https://docs.stripe.com/revenue-recognition/connect/destination-charges.md # Revenue Recognition for destination charges Learn how revenue recognition works with destination charges. Revenue recognition for destination charges tracks how platform fees are recognized as revenue when using the destination charge model for Stripe Connect. With destination charges, the platform account receives the full charge amount and then transfers a portion to the connected account, keeping the platform fees as revenue. Here, we explain how revenue recognition works for both fee collection methods: - **Application fees** (`application_fee_amount`): Platform fees are collected separately and transferred back to the platform. - **Transfer amount** (`transfer_data[amount]`): Platform fees are deducted from the transfer amount to the connected account. ## Revenue collected with application_fee_amount If the destination charges [collects fees](https://docs.stripe.com/connect/destination-charges.md?fee-type=application-fee#collect-fees) with `application_fee_amount`, the charge and transfer happen immediately, and the `application_fee_amount` is immediately recognized as the revenue. In this example, the `application_fee_amount="200"` is set on the charge. - On January 15, the full charge amount of 10 USD is added to your platform account. - 10 USD is transferred to the connected account. - The 2 USD application fee is transferred back to your platform. | Account | Jan | | ------- | ----- | | Revenue | +2.00 | | Cash | +2.00 | ## Revenue collected with transfer_data[amount] If the destination charges [collect fees](https://docs.stripe.com/connect/destination-charges.md?fee-type=transfer-amount#collect-fees) with `transfer_data[amount]`, the charge and transfer happen immediately, where you subtract your platform’s fees from the charge amount, then pass the result of this calculation as the `transfer_data[amount]`. The platform’s fees are immediately recognized as revenue. In this example, the `transfer_data[amount]="800"` is set on the charge. - On January 15, the full charge amount 10 USD is added to your platform account. - 8 USD is transferred to the connected account. - The 2 USD is recognized as the revenue. | Account | Jan | | ------- | ----- | | Revenue | +2.00 | | Cash | +2.00 | ## Loss and contra revenue with issuing refunds ### When collecting fees with application_fee_amount If the destination charges [issue refunds](https://docs.stripe.com/connect/destination-charges.md#issue-refunds), by default the destination account keeps the funds that were transferred to it, leaving the platform account to cover the negative balance from the refund. The refund amount is booked as the ConnectTransferLoss. In this example, the charge collects fees with `application_fee_amount`, and it is fully refunded in February. - On January 15, the full charge amount of 10 USD is added to your platform account. - 10 USD is transferred to the connected account. - The 2 USD application fee is transferred back to your platform. - On February 21, the full charge amount 10 USD is refunded. | Account | Jan | Feb | | ------------------- | ----- | ------ | | Revenue | +2.00 | | | Cash | +2.00 | -10.00 | | ConnectTransferLoss | | +10.00 | If the platform account sets `reverse_transfer=true` and `refund_application_fee=true` when calling the refund API: - If the transfer reversal succeeded, the ConnectTransferLoss is canceled out by the transfer reversal. - The refunded application fee is booked as contra revenue. | Account | Jan | Feb | | ------- | ----- | ----- | | Revenue | +2.00 | | | Cash | +2.00 | -2.00 | | Refunds | | +2.00 | ### When collecting fees with transfer_data[amount] In this example, the charge collects fees with transfer_data[*amount*], and it’s partially refunded in February and March. - On January 15, the full charge amount of 10 USD is added to your platform account. - 8 USD is transferred to the connected account. - The 2 USD is recognized as the revenue. - On February 21, the partial charge amount 4 USD is refunded, and a proportional amount of the transfer 3.20 USD is reversed. - On March 10, the partial charge amount 6 USD is refunded, and a proportional amount of the transfer 4.80 USD is reversed. | Account | Jan | Feb | Mar | Total | | ------- | ----- | ----- | ----- | ----- | | Revenue | +2.00 | | | +2.00 | | Cash | +2.00 | -0.80 | -1.20 | | | Refunds | | +0.80 | +1.20 | +2.00 | ## Best practices for accessing the feature To use revenue recognition for destination charges, follow these best practices for setup, monitoring, and troubleshooting. ### Audit the destination charges journal entries You can select the **platform fee ID**, **platform fee refund ID**, **transfer ID**, **transfer refund ID**, and **charge destination ID** columns when downloading the CSV reports format by invoice or line item. ![Revenue recognition report columns for the destination charges](https://b.stripecdn.com/docs-statics-srv/assets/connect-destination-charges-report-columns.503bbea8698306dc3a1282676b1e0d2c.png) The month summary reports contain new items `Revenue from platform fees` and `Less refunds from platform fees`—you can find the details in the [month summary section](https://docs.stripe.com/revenue-recognition/reports/monthly-summary.md). ![Revenue recognition month summary items for the destination charges](https://b.stripecdn.com/docs-statics-srv/assets/connect-destination-charges-month-summary.6ac0f42f9d596630e5ffb95f7d84a451.png) ### Accounting period It generates corrections if the private preview is retroactively applied to transactions from past (closed) accounting periods. If you want to avoid this, reopen your books by [opening your accounting periods](https://docs.stripe.com/revenue-recognition/revenue-settings/accounting-period-control.md) prior to gating into the private preview. ### Destination charges exclusion rule If you’re on destination charges exclusion rule, you can either delete the exclusion rules or set an effective period end date to apply the feature. ![Revenue recognition exclusion rule for the destination payments](https://b.stripecdn.com/docs-statics-srv/assets/connect-destination-charges-exclusion-rule.d002006b2460151217a08cdcbbef344d.png) --- # Source: https://docs.stripe.com/get-started/development-environment.md # Set up your development environment Get familiar with the Stripe CLI and our server-side SDKs. Check out our [no-code docs](https://docs.stripe.com/no-code.md), use a [prebuilt solution](https://stripe.com/partners/directory) from our partner directory, or hire a [Stripe-certified expert](https://stripe.com/partners/directory?t=Consulting). Stripe’s server-side SDKs and command-line interface (CLI) allow you to interact with Stripe’s REST APIs. Start with the Stripe CLI to streamline your development environment and make API calls. Use the SDKs to avoid writing boilerplate code. To start sending requests from your environment, choose a language to follow a quickstart guide. > #### Chrome extensions > > We recommend you build your payment integration with Stripe (such as [Elements](https://docs.stripe.com/payments/elements.md) or [Checkout](https://docs.stripe.com/payments/checkout.md)) on your own website. Then, set up your Chrome extension to send users to this payment page when they’re ready to complete a purchase. > > This method is more secure and easier to maintain than trying to handle payments directly within the extension. # Ruby > This is a Ruby for when lang is ruby. View the full page at https://docs.stripe.com/get-started/development-environment?lang=ruby. In this quickstart, you install the [Stripe CLI](https://docs.stripe.com/stripe-cli.md)—an essential tool that gets you command line access to your Stripe integration. You also install the [Stripe Ruby server-side SDK](https://github.com/stripe/stripe-ruby) to get access to Stripe APIs from applications written in Ruby. ## What you learn In this quickstart, you’ll learn: - How to call Stripe APIs without writing a line of code - How to manage third-party dependencies using a bundler with RubyGems - How to install the Stripe Ruby SDK v18.3.0 - How to send your first SDK request ## Set up the Stripe CLI First, [create a Stripe account](https://dashboard.stripe.com/register) or [sign in](https://dashboard.stripe.com/login). ### Install From the command-line, use an install script or download and extract a versioned archive file for your operating system to install the CLI. #### homebrew To install the Stripe CLI with [homebrew](https://brew.sh/), run: ```bash brew install stripe/stripe-cli/stripe ``` This command fails if you run it on the Linux version of homebrew, but you can use this alternative or follow the instructions on the Linux tab. ```bash brew install stripe-cli ``` #### apt > The Debian build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. > On April 5th, 2024, we changed Stripe CLI’s GPG key to install the Stripe CLI through apt. If you configured the public key before April 5th, you’ll encounter this error: > > ``` W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://packages.stripe.dev/stripe-cli-debian-local stable InRelease: The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Failed to fetch https://packages.stripe.dev/stripe-cli-debian-local/dists/stable/InRelease The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Some index files failed to download. They have been ignored, or old ones used instead ``` > > To resolve this error, refresh Stripe’s GPG key by following [step 1](https://docs.stripe.com/get-started/development-environment.md#step_one). To install the Stripe CLI on Debian and Ubuntu-based distributions: 1. Add Stripe CLI’s GPG key to the apt sources keyring: ```bash curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor | sudo tee /usr/share/keyrings/stripe.gpg ``` 1. Add CLI’s apt repository to the apt sources list: ```bash echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" | sudo tee -a /etc/apt/sources.list.d/stripe.list ``` 1. Update the package list: ```bash sudo apt update ``` 1. Install the CLI: ```bash sudo apt install stripe ``` #### yum > The RPM build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. To install the Stripe CLI on RPM-based distributions: 1. Add CLI’s yum repository to the yum sources list: ```bash echo -e "[Stripe]\nname=stripe\nbaseurl=https://packages.stripe.dev/stripe-cli-rpm-local/\nenabled=1\ngpgcheck=0" >> /etc/yum.repos.d/stripe.repo ``` 1. Install the CLI: ```bash sudo yum install stripe ``` #### Scoop To install the Stripe CLI with [Scoop](https://scoop.sh/), run: ```bash scoop bucket add stripe https://github.com/stripe/scoop-stripe-cli.git ``` ```bash scoop install stripe ``` #### macOS To install the Stripe CLI on macOS without homebrew: 1. Download the latest `mac-os` tar.gz file of your cpu architecture type from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_[X.X.X]_mac-os_[ARCH_TYPE].tar.gz`. Optionally, install the binary in a location where you can execute it globally (for example, `/usr/local/bin`). #### Linux To install the Stripe CLI on Linux without a package manager: 1. Download the latest `linux` tar.gz file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_X.X.X_linux_x86_64.tar.gz`. 1. Move `./stripe` to your execution path. #### Windows To install the Stripe CLI on Windows without Scoop: 1. Download the latest `windows` zip file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the `stripe_X.X.X_windows_x86_64.zip` file. 1. Add the path to the unzipped `stripe.exe` file to your `Path` environment variable. To learn how to update environment variables, see the [Microsoft PowerShell documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.3#saving-changes-to-environment-variables). > Windows anti-virus scanners occasionally flag the Stripe CLI as unsafe. This is likely a false positive. For more information, see [issue #692](https://github.com/stripe/stripe-cli/issues/692) in the GitHub repository. 1. Run the unzipped `.exe` file. #### Docker The Stripe CLI is also available as a [Docker image](https://hub.docker.com/r/stripe/stripe-cli). To install the latest version, run: ```bash docker run --rm -it stripe/stripe-cli:latest ``` ### Authenticate Log in and authenticate your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) to generate a set of restricted keys. To learn more, see [Stripe CLI keys and permissions](https://docs.stripe.com/stripe-cli/keys.md). ```bash stripe login ``` Press **Enter** on your keyboard to complete the authentication process in your browser. ```bash Your pairing code is: enjoy-enough-outwit-win This pairing code verifies your authentication with Stripe. Press Enter to open the browser or visit https://dashboard.stripe.com/stripecli/confirm_auth?t=THQdJfL3x12udFkNorJL8OF1iFlN8Az1 (^C to quit) ``` ### Confirm setup Now that you’ve installed the CLI, you can make a single API request to [Create a product](https://docs.stripe.com/api/products/create.md). #### bash ```bash stripe products create \ --name="My First Product" \ --description="Created with the Stripe CLI" ``` Look for the product identifier (in `id`) in the response object. Save it for the next step. If everything worked, the command-line displays the following response. #### bash ```json { "id": "prod_LTenIrmp8Q67sa", // The identifier looks like this. "object": "product", "active": true, "attributes": [], "created": 1668198126, "default_price": null, "description": "Created with the Stripe CLI", "identifiers": {}, "images": [], "livemode": false, "metadata": {}, "name": "My First Product", "package_dimensions": null, "price": null, "product_class": null, "shippable": null, "sku": "my-first-product-10", "statement_descriptor": null, "tax_code": null, "type": "service", "unit_label": null, "updated": 1668198126, "url": null } ``` Next, call [Create a price](https://docs.stripe.com/api/prices/create.md) to attach a price of 30 USD. Swap the placeholder in `product` with your product identifier (for example, `prod_LTenIrmp8Q67sa`). #### bash ```bash stripe prices create \ --unit-amount=3000 \ --currency=usd \ --product="{{PRODUCT_ID}}" ``` If everything worked, the command-line displays the following response. #### bash ```json { "id": "price_1KzlAMJJDeE9fu01WMJJr79o", // The identifier looks like this. "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1652636348, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "product": "prod_Lh9iTGZhb2mcBy", "recurring": null, "tax_behavior": "unspecified", "tiers_mode": null, "transform_quantity": null, "type": "one_time", "unit_amount": 3000, "unit_amount_decimal": "3000" } ``` ## Manage third-party dependencies We recommend managing third-party dependencies using the [RubyGems](http://rubygems.org/) command-line tool, which allows you to add new libraries and include them in your Ruby projects. Check whether RubyGems is installed: ### Install RubyGems #### Install RubyGems ```bash gem --version ``` If you get `gem: command not found`, [download RubyGems](http://rubygems.org/pages/download) from their downloads page. ## Install the Ruby server-side SDK The latest version of the Stripe Ruby server-side SDK is v18.3.0. It supports Ruby versions 2.3+. Check your Ruby version: ```bash ruby -v ``` ### Install the library [Create a gem file](https://guides.rubygems.org/make-your-own-gem/) and install the generated gem using a bundler with [RubyGems](https://rubygems.org/). Add the latest version of the [Stripe gem](https://rubygems.org/gems/stripe) to a project: ```bash bundle add stripe ``` Install the required gems from your specified sources: ```bash bundle install ``` ### Installation alternatives **Add as dependency**—Add the latest version of the library as a gem dependency: ```ruby source 'https://rubygems.org' gem 'rails' gem 'stripe' ``` **Global installation**—Install the library globally with [RubyGems](https://rubygems.org/): ```bash gem install stripe ``` **Manual installation**—[Build the gem from source](https://github.com/stripe/stripe-ruby), and then install the library by running: ```bash gem build stripe.gemspec ``` ## Run your first SDK request Now that you have the Ruby SDK installed, you can create a subscription [Product](https://docs.stripe.com/api/products/create.md) and attach a [Price](https://docs.stripe.com/api/prices/create.md) with a couple API requests. We’re using the product identifier returned in the response to create the price in this example. > This sample uses the default keys of your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) for your *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment. Only you can see these values. #### Create a product and price ```ruby require 'rubygems' require 'stripe' Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2" starter_subscription = Stripe::Product.create( name: 'Starter Subscription', description: '$12/Month subscription', ) starter_subscription_price = Stripe::Price.create( currency: 'usd', unit_amount: 1200, recurring: {interval: 'month'}, product: starter_subscription['id'], ) puts "Success! Here is your starter subscription product id: #{starter_subscription.id}" puts "Success! Here is your starter subscription price id: #{starter_subscription_price.id}" ``` Save the file as `create_price.rb`. From the command line, `cd` to the directory containing the file you just saved and run: #### create_price.rb ```bash ruby create_price.rb ``` If everything worked, the command line shows the following response. Save these identifiers so you can use them while building your integration. #### bash ```bash Success! Here is your starter subscription product id: prod_0KxBDl589O8KAxCG1alJgiA6 Success! Here is your starter subscription price id: price_0KxBDm589O8KAxCGMgG7scjb ``` ## See also This wraps up the quickstart. See the links below for a few different ways to process a payment for the product you just created. - [Create a payment link](https://docs.stripe.com/payment-links.md) - [Stripe-hosted page](https://docs.stripe.com/checkout/quickstart.md) - [Advanced integration](https://docs.stripe.com/payments/quickstart.md) # Python > This is a Python for when lang is python. View the full page at https://docs.stripe.com/get-started/development-environment?lang=python. In this quickstart, you install the [Stripe CLI](https://docs.stripe.com/stripe-cli.md)—an essential tool that gets you command line access to your Stripe integration. You also install the [Stripe Python server-side SDK](https://github.com/stripe/stripe-python) to get access to Stripe APIs from applications written in Python. ## What you learn In this quickstart, you’ll learn: - How to call Stripe APIs without writing a line of code - How to manage third-party dependencies using a virtual environment and the pip package manager - How to install the latest Stripe Python SDK v14.3.0 - How to send your first SDK request ## Initial setup First, [create a Stripe account](https://dashboard.stripe.com/register) or [sign in](https://dashboard.stripe.com/login). ## Set up the Stripe CLI ### Install From the command-line, use an install script or download and extract a versioned archive file for your operating system to install the CLI. #### homebrew To install the Stripe CLI with [homebrew](https://brew.sh/), run: ```bash brew install stripe/stripe-cli/stripe ``` This command fails if you run it on the Linux version of homebrew, but you can use this alternative or follow the instructions on the Linux tab. ```bash brew install stripe-cli ``` #### apt > The Debian build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. > On April 5th, 2024, we changed Stripe CLI’s GPG key to install the Stripe CLI through apt. If you configured the public key before April 5th, you’ll encounter this error: > > ``` W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://packages.stripe.dev/stripe-cli-debian-local stable InRelease: The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Failed to fetch https://packages.stripe.dev/stripe-cli-debian-local/dists/stable/InRelease The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Some index files failed to download. They have been ignored, or old ones used instead ``` > > To resolve this error, refresh Stripe’s GPG key by following [step 1](https://docs.stripe.com/get-started/development-environment.md#step_one). To install the Stripe CLI on Debian and Ubuntu-based distributions: 1. Add Stripe CLI’s GPG key to the apt sources keyring: ```bash curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor | sudo tee /usr/share/keyrings/stripe.gpg ``` 1. Add CLI’s apt repository to the apt sources list: ```bash echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" | sudo tee -a /etc/apt/sources.list.d/stripe.list ``` 1. Update the package list: ```bash sudo apt update ``` 1. Install the CLI: ```bash sudo apt install stripe ``` #### yum > The RPM build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. To install the Stripe CLI on RPM-based distributions: 1. Add CLI’s yum repository to the yum sources list: ```bash echo -e "[Stripe]\nname=stripe\nbaseurl=https://packages.stripe.dev/stripe-cli-rpm-local/\nenabled=1\ngpgcheck=0" >> /etc/yum.repos.d/stripe.repo ``` 1. Install the CLI: ```bash sudo yum install stripe ``` #### Scoop To install the Stripe CLI with [Scoop](https://scoop.sh/), run: ```bash scoop bucket add stripe https://github.com/stripe/scoop-stripe-cli.git ``` ```bash scoop install stripe ``` #### macOS To install the Stripe CLI on macOS without homebrew: 1. Download the latest `mac-os` tar.gz file of your cpu architecture type from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_[X.X.X]_mac-os_[ARCH_TYPE].tar.gz`. Optionally, install the binary in a location where you can execute it globally (for example, `/usr/local/bin`). #### Linux To install the Stripe CLI on Linux without a package manager: 1. Download the latest `linux` tar.gz file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_X.X.X_linux_x86_64.tar.gz`. 1. Move `./stripe` to your execution path. #### Windows To install the Stripe CLI on Windows without Scoop: 1. Download the latest `windows` zip file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the `stripe_X.X.X_windows_x86_64.zip` file. 1. Add the path to the unzipped `stripe.exe` file to your `Path` environment variable. To learn how to update environment variables, see the [Microsoft PowerShell documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.3#saving-changes-to-environment-variables). > Windows anti-virus scanners occasionally flag the Stripe CLI as unsafe. This is likely a false positive. For more information, see [issue #692](https://github.com/stripe/stripe-cli/issues/692) in the GitHub repository. 1. Run the unzipped `.exe` file. #### Docker The Stripe CLI is also available as a [Docker image](https://hub.docker.com/r/stripe/stripe-cli). To install the latest version, run: ```bash docker run --rm -it stripe/stripe-cli:latest ``` ### Authenticate Log in and authenticate your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) to generate a set of restricted keys. To learn more, see [Stripe CLI keys and permissions](https://docs.stripe.com/stripe-cli/keys.md). ```bash stripe login ``` Press **Enter** on your keyboard to complete the authentication process in your browser. ```bash Your pairing code is: enjoy-enough-outwit-win This pairing code verifies your authentication with Stripe. Press Enter to open the browser or visit https://dashboard.stripe.com/stripecli/confirm_auth?t=THQdJfL3x12udFkNorJL8OF1iFlN8Az1 (^C to quit) ``` ### Confirm setup Now that you’ve installed the CLI, you can make a single API request to [Create a product](https://docs.stripe.com/api/products/create.md). #### bash ```bash stripe products create \ --name="My First Product" \ --description="Created with the Stripe CLI" ``` Look for the product identifier (in `id`) in the response object. Save it for the next step. If everything worked, the command-line displays the following response. #### bash ```json { "id": "prod_LTenIrmp8Q67sa", // The identifier looks like this. "object": "product", "active": true, "attributes": [], "created": 1668198126, "default_price": null, "description": "Created with the Stripe CLI", "identifiers": {}, "images": [], "livemode": false, "metadata": {}, "name": "My First Product", "package_dimensions": null, "price": null, "product_class": null, "shippable": null, "sku": "my-first-product-10", "statement_descriptor": null, "tax_code": null, "type": "service", "unit_label": null, "updated": 1668198126, "url": null } ``` Next, call [Create a price](https://docs.stripe.com/api/prices/create.md) to attach a price of 30 USD. Swap the placeholder in `product` with your product identifier (for example, `prod_LTenIrmp8Q67sa`). #### bash ```bash stripe prices create \ --unit-amount=3000 \ --currency=usd \ --product="{{PRODUCT_ID}}" ``` If everything worked, the command-line displays the following response. #### bash ```json { "id": "price_1KzlAMJJDeE9fu01WMJJr79o", // The identifier looks like this. "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1652636348, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "product": "prod_Lh9iTGZhb2mcBy", "recurring": null, "tax_behavior": "unspecified", "tiers_mode": null, "transform_quantity": null, "type": "one_time", "unit_amount": 3000, "unit_amount_decimal": "3000" } ``` ## Manage third-party dependencies We recommend managing third-party dependencies using the [venv](https://docs.python.org/3/tutorial/venv.html) module, which allows you to add new libraries and include them in your Python 3 projects. ### On Windows (cmd.exe): #### On Windows (cmd.exe) ```bash python3 -m venv env .\env\Scripts\activate.bat ``` ### On GNU/Linux or MacOS (bash): #### On GNU/Linux or MacOS (bash) ```bash python3 -m venv env source env/bin/activate ``` ## Install the Python server-side SDK The latest version of the Stripe Python server-side SDK is v14.3.0. It supports Python versions 3.6+. Check your Python version: ```bash python3 --version ``` ### Install the library Install the library from [PyPi](http://pypi.python.org/pypi/stripe/), a package manager for Python: ```bash pip3 install --upgrade stripe ``` Next, specify the following version in your requirements.txt file: ```txt stripe>=14.3.0 ``` ### Installation alternatives **Manual installation**—[Download the source code](https://github.com/stripe/stripe-python) for the SDK, and install the library by running: ```bash python3 setup.py install ``` ## Run your first SDK request Now that you have the Python SDK installed, you can create a subscription [Product](https://docs.stripe.com/api/products/create.md) and attach a [Price](https://docs.stripe.com/api/prices/create.md) with a couple API requests. We’re using the product identifier returned in the response to create the price in this example. > This sample uses the default keys of your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) for your *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment. Only you can see these values. #### Create a product and price ```python import stripe stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2" starter_subscription = stripe.Product.create( name="Starter Subscription", description="$12/Month subscription", ) starter_subscription_price = stripe.Price.create( unit_amount=1200, currency="usd", recurring={"interval": "month"}, product=starter_subscription['id'], ) # Save these identifiers print(f"Success! Here is your starter subscription product id: {starter_subscription.id}") print(f"Success! Here is your starter subscription price id: {starter_subscription_price.id}") ``` Save the file as `create_price.py`. From the command line, `cd` to the directory containing the file you just saved and run: #### create_price.py ```bash python3 create_price.py ``` If everything worked, the command line shows the following response. Save these identifiers so you can use them while building your integration. #### bash ```bash Success! Here is your starter subscription product id: prod_0KxBDl589O8KAxCG1alJgiA6 Success! Here is your starter subscription price id: price_0KxBDm589O8KAxCGMgG7scjb ``` ## See also This wraps up the quickstart. See the links below for a few different ways to process a payment for the product you just created. - [Create a payment link](https://docs.stripe.com/payment-links.md) - [Prebuilt checkout page](https://docs.stripe.com/checkout/quickstart.md) - [Custom payment flow](https://docs.stripe.com/payments/quickstart.md) # Go > This is a Go for when lang is go. View the full page at https://docs.stripe.com/get-started/development-environment?lang=go. In this quickstart, you install the [Stripe CLI](https://docs.stripe.com/stripe-cli.md)—an essential tool that gets you command line access to your Stripe integration. You also install the [Stripe Go server-side SDK](https://github.com/stripe/stripe-go) to get access to Stripe APIs from applications written in Go. ## What you learn In this quickstart, you’ll learn: - How to call Stripe APIs without writing a line of code - How to manage third-party dependencies using Go modules - How to install the latest Stripe Go SDK v84.3.0 - How to send your first SDK request ## Initial setup First, [create a Stripe account](https://dashboard.stripe.com/register) or [sign in](https://dashboard.stripe.com/login). ## Set up the Stripe CLI ### Install From the command-line, use an install script or download and extract a versioned archive file for your operating system to install the CLI. #### homebrew To install the Stripe CLI with [homebrew](https://brew.sh/), run: ```bash brew install stripe/stripe-cli/stripe ``` This command fails if you run it on the Linux version of homebrew, but you can use this alternative or follow the instructions on the Linux tab. ```bash brew install stripe-cli ``` #### apt > The Debian build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. > On April 5th, 2024, we changed Stripe CLI’s GPG key to install the Stripe CLI through apt. If you configured the public key before April 5th, you’ll encounter this error: > > ``` W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://packages.stripe.dev/stripe-cli-debian-local stable InRelease: The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Failed to fetch https://packages.stripe.dev/stripe-cli-debian-local/dists/stable/InRelease The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Some index files failed to download. They have been ignored, or old ones used instead ``` > > To resolve this error, refresh Stripe’s GPG key by following [step 1](https://docs.stripe.com/get-started/development-environment.md#step_one). To install the Stripe CLI on Debian and Ubuntu-based distributions: 1. Add Stripe CLI’s GPG key to the apt sources keyring: ```bash curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor | sudo tee /usr/share/keyrings/stripe.gpg ``` 1. Add CLI’s apt repository to the apt sources list: ```bash echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" | sudo tee -a /etc/apt/sources.list.d/stripe.list ``` 1. Update the package list: ```bash sudo apt update ``` 1. Install the CLI: ```bash sudo apt install stripe ``` #### yum > The RPM build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. To install the Stripe CLI on RPM-based distributions: 1. Add CLI’s yum repository to the yum sources list: ```bash echo -e "[Stripe]\nname=stripe\nbaseurl=https://packages.stripe.dev/stripe-cli-rpm-local/\nenabled=1\ngpgcheck=0" >> /etc/yum.repos.d/stripe.repo ``` 1. Install the CLI: ```bash sudo yum install stripe ``` #### Scoop To install the Stripe CLI with [Scoop](https://scoop.sh/), run: ```bash scoop bucket add stripe https://github.com/stripe/scoop-stripe-cli.git ``` ```bash scoop install stripe ``` #### macOS To install the Stripe CLI on macOS without homebrew: 1. Download the latest `mac-os` tar.gz file of your cpu architecture type from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_[X.X.X]_mac-os_[ARCH_TYPE].tar.gz`. Optionally, install the binary in a location where you can execute it globally (for example, `/usr/local/bin`). #### Linux To install the Stripe CLI on Linux without a package manager: 1. Download the latest `linux` tar.gz file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_X.X.X_linux_x86_64.tar.gz`. 1. Move `./stripe` to your execution path. #### Windows To install the Stripe CLI on Windows without Scoop: 1. Download the latest `windows` zip file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the `stripe_X.X.X_windows_x86_64.zip` file. 1. Add the path to the unzipped `stripe.exe` file to your `Path` environment variable. To learn how to update environment variables, see the [Microsoft PowerShell documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.3#saving-changes-to-environment-variables). > Windows anti-virus scanners occasionally flag the Stripe CLI as unsafe. This is likely a false positive. For more information, see [issue #692](https://github.com/stripe/stripe-cli/issues/692) in the GitHub repository. 1. Run the unzipped `.exe` file. #### Docker The Stripe CLI is also available as a [Docker image](https://hub.docker.com/r/stripe/stripe-cli). To install the latest version, run: ```bash docker run --rm -it stripe/stripe-cli:latest ``` ### Authenticate Log in and authenticate your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) to generate a set of restricted keys. To learn more, see [Stripe CLI keys and permissions](https://docs.stripe.com/stripe-cli/keys.md). ```bash stripe login ``` Press **Enter** on your keyboard to complete the authentication process in your browser. ```bash Your pairing code is: enjoy-enough-outwit-win This pairing code verifies your authentication with Stripe. Press Enter to open the browser or visit https://dashboard.stripe.com/stripecli/confirm_auth?t=THQdJfL3x12udFkNorJL8OF1iFlN8Az1 (^C to quit) ``` ### Confirm setup Now that you’ve installed the CLI, you can make a single API request to [Create a product](https://docs.stripe.com/api/products/create.md). #### bash ```bash stripe products create \ --name="My First Product" \ --description="Created with the Stripe CLI" ``` Look for the product identifier (in `id`) in the response object. Save it for the next step. If everything worked, the command-line displays the following response. #### bash ```json { "id": "prod_LTenIrmp8Q67sa", // The identifier looks like this. "object": "product", "active": true, "attributes": [], "created": 1668198126, "default_price": null, "description": "Created with the Stripe CLI", "identifiers": {}, "images": [], "livemode": false, "metadata": {}, "name": "My First Product", "package_dimensions": null, "price": null, "product_class": null, "shippable": null, "sku": "my-first-product-10", "statement_descriptor": null, "tax_code": null, "type": "service", "unit_label": null, "updated": 1668198126, "url": null } ``` Next, call [Create a price](https://docs.stripe.com/api/prices/create.md) to attach a price of 30 USD. Swap the placeholder in `product` with your product identifier (for example, `prod_LTenIrmp8Q67sa`). #### bash ```bash stripe prices create \ --unit-amount=3000 \ --currency=usd \ --product="{{PRODUCT_ID}}" ``` If everything worked, the command-line displays the following response. #### bash ```json { "id": "price_1KzlAMJJDeE9fu01WMJJr79o", // The identifier looks like this. "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1652636348, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "product": "prod_Lh9iTGZhb2mcBy", "recurring": null, "tax_behavior": "unspecified", "tiers_mode": null, "transform_quantity": null, "type": "one_time", "unit_amount": 3000, "unit_amount_decimal": "3000" } ``` ## Manage third-party dependencies We recommend managing third-party dependencies using [Go modules](https://go.dev/blog/using-go-modules), which allows you to add new libraries and include them in your Go projects. ### Initialize Go If you’re starting from scratch in a new directory, you first need to create a `go.mod` file for tracking dependencies. For example: #### Initialize Go ```bash go mod init stripe-example ``` ## Install the Go server-side SDK The latest version of the Stripe Go server-side SDK is v84.3.0. It supports Go versions 1.15+. ### Install the library Install the library with [Go modules](https://go.dev/blog/using-go-modules), a package manager for Go: ```bash go get github.com/stripe/stripe-go/v84 ``` After you install the library with Go modules to a *new* project, the library is automatically added as a dependency in your project’s go.mod file. For example: ```go.mod module stripe-example go 1.18 require github.com/stripe/stripe-go/v84 84.3.0 // indirect ``` ### Synchronize dependencies To keep your managed dependency set tidy for an *existing* project, run the following command to [sync your code’s dependencies](https://go.dev/doc/modules/managing-dependencies). ```bash go mod tidy ``` ## Run your first SDK request Now that you have the Go SDK installed, you can create a subscription [Product](https://docs.stripe.com/api/products/create.md) and attach a [Price](https://docs.stripe.com/api/prices/create.md) with a couple API requests. We’re using the product identifier returned in the response to create the price in this example. > This sample uses the default keys of your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) for your *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment. Only you can see these values. #### Create a product and price ```go package main import ( "fmt" "github.com/stripe/stripe-go/v84" "github.com/stripe/stripe-go/v84/product" "github.com/stripe/stripe-go/v84/price" ) func main() { stripe.Key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2" product_params := &stripe.ProductParams{ Name: stripe.String("Starter Subscription"), Description: stripe.String("$12/Month subscription"), } starter_product, _ := product.New(product_params) price_params := &stripe.PriceParams{ Currency: stripe.String(string(stripe.CurrencyUSD)), Product: stripe.String(starter_product.ID), Recurring: &stripe.PriceRecurringParams{ Interval: stripe.String(string(stripe.PriceRecurringIntervalMonth)), }, UnitAmount: stripe.Int64(1200), } starter_price, _ := price.New(price_params) fmt.Println("Success! Here is your starter subscription product id: " + starter_product.ID) fmt.Println("Success! Here is your starter subscription price id: " + starter_price.ID) } ``` Save the file as `create_price.go`. From the command line, `cd` to the directory containing the file you just saved and run: #### create_price.rb ```bash go run create_price.go ``` If everything worked, the command line shows the following response. Save these identifiers so you can use them while building your integration. #### bash ```bash Success! Here is your starter subscription product id: prod_0KxBDl589O8KAxCG1alJgiA6 Success! Here is your starter subscription price id: price_0KxBDm589O8KAxCGMgG7scjb ``` ## See also This wraps up the quickstart. See the links below for a few different ways to process a payment for the product you just created. - [Create a payment link](https://docs.stripe.com/payment-links.md) - [Prebuilt checkout page](https://docs.stripe.com/checkout/quickstart.md) - [Custom payment flow](https://docs.stripe.com/payments/quickstart.md) # Java > This is a Java for when lang is java. View the full page at https://docs.stripe.com/get-started/development-environment?lang=java. In this quickstart, you install the [Stripe CLI](https://docs.stripe.com/stripe-cli.md)—an essential tool that gets you command line access to your Stripe integration. You also install the [Stripe Java server-side SDK](https://github.com/stripe/stripe-java) to get access to Stripe APIs from applications written in Java. ## What you learn In this quickstart, you’ll learn: - How to call Stripe APIs without writing a line of code - How to manage third-party dependencies using Maven or Gradle - How to install the latest Stripe Java SDK v31.3.0 - How to send your first SDK request ## Initial setup First, [create a Stripe account](https://dashboard.stripe.com/register) or [sign in](https://dashboard.stripe.com/login). ## Set up the Stripe CLI ### Install From the command-line, use an install script or download and extract a versioned archive file for your operating system to install the CLI. #### homebrew To install the Stripe CLI with [homebrew](https://brew.sh/), run: ```bash brew install stripe/stripe-cli/stripe ``` This command fails if you run it on the Linux version of homebrew, but you can use this alternative or follow the instructions on the Linux tab. ```bash brew install stripe-cli ``` #### apt > The Debian build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. > On April 5th, 2024, we changed Stripe CLI’s GPG key to install the Stripe CLI through apt. If you configured the public key before April 5th, you’ll encounter this error: > > ``` W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://packages.stripe.dev/stripe-cli-debian-local stable InRelease: The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Failed to fetch https://packages.stripe.dev/stripe-cli-debian-local/dists/stable/InRelease The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Some index files failed to download. They have been ignored, or old ones used instead ``` > > To resolve this error, refresh Stripe’s GPG key by following [step 1](https://docs.stripe.com/get-started/development-environment.md#step_one). To install the Stripe CLI on Debian and Ubuntu-based distributions: 1. Add Stripe CLI’s GPG key to the apt sources keyring: ```bash curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor | sudo tee /usr/share/keyrings/stripe.gpg ``` 1. Add CLI’s apt repository to the apt sources list: ```bash echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" | sudo tee -a /etc/apt/sources.list.d/stripe.list ``` 1. Update the package list: ```bash sudo apt update ``` 1. Install the CLI: ```bash sudo apt install stripe ``` #### yum > The RPM build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. To install the Stripe CLI on RPM-based distributions: 1. Add CLI’s yum repository to the yum sources list: ```bash echo -e "[Stripe]\nname=stripe\nbaseurl=https://packages.stripe.dev/stripe-cli-rpm-local/\nenabled=1\ngpgcheck=0" >> /etc/yum.repos.d/stripe.repo ``` 1. Install the CLI: ```bash sudo yum install stripe ``` #### Scoop To install the Stripe CLI with [Scoop](https://scoop.sh/), run: ```bash scoop bucket add stripe https://github.com/stripe/scoop-stripe-cli.git ``` ```bash scoop install stripe ``` #### macOS To install the Stripe CLI on macOS without homebrew: 1. Download the latest `mac-os` tar.gz file of your cpu architecture type from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_[X.X.X]_mac-os_[ARCH_TYPE].tar.gz`. Optionally, install the binary in a location where you can execute it globally (for example, `/usr/local/bin`). #### Linux To install the Stripe CLI on Linux without a package manager: 1. Download the latest `linux` tar.gz file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_X.X.X_linux_x86_64.tar.gz`. 1. Move `./stripe` to your execution path. #### Windows To install the Stripe CLI on Windows without Scoop: 1. Download the latest `windows` zip file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the `stripe_X.X.X_windows_x86_64.zip` file. 1. Add the path to the unzipped `stripe.exe` file to your `Path` environment variable. To learn how to update environment variables, see the [Microsoft PowerShell documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.3#saving-changes-to-environment-variables). > Windows anti-virus scanners occasionally flag the Stripe CLI as unsafe. This is likely a false positive. For more information, see [issue #692](https://github.com/stripe/stripe-cli/issues/692) in the GitHub repository. 1. Run the unzipped `.exe` file. #### Docker The Stripe CLI is also available as a [Docker image](https://hub.docker.com/r/stripe/stripe-cli). To install the latest version, run: ```bash docker run --rm -it stripe/stripe-cli:latest ``` ### Authenticate Log in and authenticate your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) to generate a set of restricted keys. To learn more, see [Stripe CLI keys and permissions](https://docs.stripe.com/stripe-cli/keys.md). ```bash stripe login ``` Press **Enter** on your keyboard to complete the authentication process in your browser. ```bash Your pairing code is: enjoy-enough-outwit-win This pairing code verifies your authentication with Stripe. Press Enter to open the browser or visit https://dashboard.stripe.com/stripecli/confirm_auth?t=THQdJfL3x12udFkNorJL8OF1iFlN8Az1 (^C to quit) ``` ### Confirm setup Now that you’ve installed the CLI, you can make a single API request to [Create a product](https://docs.stripe.com/api/products/create.md). #### bash ```bash stripe products create \ --name="My First Product" \ --description="Created with the Stripe CLI" ``` Look for the product identifier (in `id`) in the response object. Save it for the next step. If everything worked, the command-line displays the following response. #### bash ```json { "id": "prod_LTenIrmp8Q67sa", // The identifier looks like this. "object": "product", "active": true, "attributes": [], "created": 1668198126, "default_price": null, "description": "Created with the Stripe CLI", "identifiers": {}, "images": [], "livemode": false, "metadata": {}, "name": "My First Product", "package_dimensions": null, "price": null, "product_class": null, "shippable": null, "sku": "my-first-product-10", "statement_descriptor": null, "tax_code": null, "type": "service", "unit_label": null, "updated": 1668198126, "url": null } ``` Next, call [Create a price](https://docs.stripe.com/api/prices/create.md) to attach a price of 30 USD. Swap the placeholder in `product` with your product identifier (for example, `prod_LTenIrmp8Q67sa`). #### bash ```bash stripe prices create \ --unit-amount=3000 \ --currency=usd \ --product="{{PRODUCT_ID}}" ``` If everything worked, the command-line displays the following response. #### bash ```json { "id": "price_1KzlAMJJDeE9fu01WMJJr79o", // The identifier looks like this. "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1652636348, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "product": "prod_Lh9iTGZhb2mcBy", "recurring": null, "tax_behavior": "unspecified", "tiers_mode": null, "transform_quantity": null, "type": "one_time", "unit_amount": 3000, "unit_amount_decimal": "3000" } ``` ## Manage third-party dependencies We recommend managing third-party dependencies using [Maven](https://maven.apache.org/guides/getting-started/index.html) or [Gradle](https://docs.gradle.org), which help you add new libraries and include them in your Java projects. ### Initialize a project - To create a project with **Maven**, see [How do I make my first Maven project?](https://maven.apache.org/guides/getting-started/index.html#How_do_I_make_my_first_Maven_project). - To create a project with **Gradle**, see [Building Java Applications Sample](https://docs.gradle.org/current/samples/sample_building_java_applications.html). ## Install the Java server-side SDK The latest version of the Stripe Java server-side SDK is v31.3.0. It supports Java versions 1.8+. Check your Java version: ```bash java -version ``` ### Install the library - With **Maven**, place the following in your project’s pom.xml file: ```xml com.stripe stripe-java 31.3.0 ``` - With **Gradle**, paste the next line inside the dependencies block of your build.gradle file: ```groovy implementation 'com.stripe:stripe-java:31.3.0' ``` ### Installation alternatives **Manual installation**—You can manually install stripe-java with the following JARs: [Download the Stripe JAR (.jar)](https://search.maven.org/remote_content?g=com.stripe&a=stripe-java&v=LATEST). [Download the Gson JAR (.jar)](https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.9/gson-2.8.9.jar) for [Google Gson](https://github.com/google/gson). **Proguard**—If you’re using ProGuard, be sure to exclude the library by adding the following to your `proguard.cfg` file: ```proguard -keep class com.stripe.** { *; } ``` ## Run your first SDK request Now that you have the Java SDK installed, you can create a subscription [Product](https://docs.stripe.com/api/products/create.md) and attach a [Price](https://docs.stripe.com/api/prices/create.md) with a couple API requests. We’re using the product identifier returned in the response to create the price in this example. > This sample uses the default keys of your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) for your *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment. Only you can see these values. #### Create a product and price ```java package com.stripe.sample; import com.stripe.Stripe; import com.stripe.exception.StripeException; import com.stripe.model.Product; import com.stripe.param.ProductCreateParams; import com.stripe.param.PriceCreateParams; import com.stripe.model.Price; public class Server { public static void main(String[] args) throws StripeException { Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"; ProductCreateParams productParams = ProductCreateParams.builder() .setName("Starter Subscription") .setDescription("$12/Month subscription") .build(); Product product = Product.create(productParams); System.out.println("Success! Here is your starter subscription product id: " + product.getId()); PriceCreateParams params = PriceCreateParams .builder() .setProduct(product.getId()) .setCurrency("usd") .setUnitAmount(1200L) .setRecurring( PriceCreateParams.Recurring .builder() .setInterval(PriceCreateParams.Recurring.Interval.MONTH) .build()) .build(); Price price = Price.create(params); System.out.println("Success! Here is your starter subscription price id: " + price.getId()); } } ``` Save the file as `CreatePrice.java`. From the project in your IDE for Maven or Gradle, run the sample. For example: `Run 'CreatePrice.main()'`. If everything worked, the command line shows the following response. Save these identifiers so you can use them while building your integration. #### bash ```bash Success! Here is your starter subscription product id: prod_0KxBDl589O8KAxCG1alJgiA6 Success! Here is your starter subscription price id: price_0KxBDm589O8KAxCGMgG7scjb ``` ## See also This wraps up the quickstart. See the links below for a few different ways to process a payment for the product you just created. - [Create a payment link](https://docs.stripe.com/payment-links.md) - [Prebuilt checkout page](https://docs.stripe.com/checkout/quickstart.md) - [Custom payment flow](https://docs.stripe.com/payments/quickstart.md) # Node.js > This is a Node.js for when lang is node. View the full page at https://docs.stripe.com/get-started/development-environment?lang=node. In this quickstart, you install the [Stripe CLI](https://docs.stripe.com/stripe-cli.md)—an essential tool that gets you command line access to your Stripe integration. You also install the [Stripe Node.js server-side SDK](https://github.com/stripe/stripe-node) to get access to Stripe APIs from applications written in Node.js. ## What you learn In this quickstart, you’ll learn: - How to call Stripe APIs without writing a line of code - How to manage third-party dependencies using the npm or yarn package manager - How to install the latest Stripe Node SDK v20.3.0 - How to send your first SDK request ## Initial setup First, [create a Stripe account](https://dashboard.stripe.com/register) or [sign in](https://dashboard.stripe.com/login). ## Set up the Stripe CLI ### Install From the command-line, use an install script or download and extract a versioned archive file for your operating system to install the CLI. #### homebrew To install the Stripe CLI with [homebrew](https://brew.sh/), run: ```bash brew install stripe/stripe-cli/stripe ``` This command fails if you run it on the Linux version of homebrew, but you can use this alternative or follow the instructions on the Linux tab. ```bash brew install stripe-cli ``` #### apt > The Debian build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. > On April 5th, 2024, we changed Stripe CLI’s GPG key to install the Stripe CLI through apt. If you configured the public key before April 5th, you’ll encounter this error: > > ``` W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://packages.stripe.dev/stripe-cli-debian-local stable InRelease: The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Failed to fetch https://packages.stripe.dev/stripe-cli-debian-local/dists/stable/InRelease The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Some index files failed to download. They have been ignored, or old ones used instead ``` > > To resolve this error, refresh Stripe’s GPG key by following [step 1](https://docs.stripe.com/get-started/development-environment.md#step_one). To install the Stripe CLI on Debian and Ubuntu-based distributions: 1. Add Stripe CLI’s GPG key to the apt sources keyring: ```bash curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor | sudo tee /usr/share/keyrings/stripe.gpg ``` 1. Add CLI’s apt repository to the apt sources list: ```bash echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" | sudo tee -a /etc/apt/sources.list.d/stripe.list ``` 1. Update the package list: ```bash sudo apt update ``` 1. Install the CLI: ```bash sudo apt install stripe ``` #### yum > The RPM build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. To install the Stripe CLI on RPM-based distributions: 1. Add CLI’s yum repository to the yum sources list: ```bash echo -e "[Stripe]\nname=stripe\nbaseurl=https://packages.stripe.dev/stripe-cli-rpm-local/\nenabled=1\ngpgcheck=0" >> /etc/yum.repos.d/stripe.repo ``` 1. Install the CLI: ```bash sudo yum install stripe ``` #### Scoop To install the Stripe CLI with [Scoop](https://scoop.sh/), run: ```bash scoop bucket add stripe https://github.com/stripe/scoop-stripe-cli.git ``` ```bash scoop install stripe ``` #### macOS To install the Stripe CLI on macOS without homebrew: 1. Download the latest `mac-os` tar.gz file of your cpu architecture type from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_[X.X.X]_mac-os_[ARCH_TYPE].tar.gz`. Optionally, install the binary in a location where you can execute it globally (for example, `/usr/local/bin`). #### Linux To install the Stripe CLI on Linux without a package manager: 1. Download the latest `linux` tar.gz file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_X.X.X_linux_x86_64.tar.gz`. 1. Move `./stripe` to your execution path. #### Windows To install the Stripe CLI on Windows without Scoop: 1. Download the latest `windows` zip file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the `stripe_X.X.X_windows_x86_64.zip` file. 1. Add the path to the unzipped `stripe.exe` file to your `Path` environment variable. To learn how to update environment variables, see the [Microsoft PowerShell documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.3#saving-changes-to-environment-variables). > Windows anti-virus scanners occasionally flag the Stripe CLI as unsafe. This is likely a false positive. For more information, see [issue #692](https://github.com/stripe/stripe-cli/issues/692) in the GitHub repository. 1. Run the unzipped `.exe` file. #### Docker The Stripe CLI is also available as a [Docker image](https://hub.docker.com/r/stripe/stripe-cli). To install the latest version, run: ```bash docker run --rm -it stripe/stripe-cli:latest ``` ### Authenticate Log in and authenticate your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) to generate a set of restricted keys. To learn more, see [Stripe CLI keys and permissions](https://docs.stripe.com/stripe-cli/keys.md). ```bash stripe login ``` Press **Enter** on your keyboard to complete the authentication process in your browser. ```bash Your pairing code is: enjoy-enough-outwit-win This pairing code verifies your authentication with Stripe. Press Enter to open the browser or visit https://dashboard.stripe.com/stripecli/confirm_auth?t=THQdJfL3x12udFkNorJL8OF1iFlN8Az1 (^C to quit) ``` ### Confirm setup Now that you’ve installed the CLI, you can make a single API request to [Create a product](https://docs.stripe.com/api/products/create.md). #### bash ```bash stripe products create \ --name="My First Product" \ --description="Created with the Stripe CLI" ``` Look for the product identifier (in `id`) in the response object. Save it for the next step. If everything worked, the command-line displays the following response. #### bash ```json { "id": "prod_LTenIrmp8Q67sa", // The identifier looks like this. "object": "product", "active": true, "attributes": [], "created": 1668198126, "default_price": null, "description": "Created with the Stripe CLI", "identifiers": {}, "images": [], "livemode": false, "metadata": {}, "name": "My First Product", "package_dimensions": null, "price": null, "product_class": null, "shippable": null, "sku": "my-first-product-10", "statement_descriptor": null, "tax_code": null, "type": "service", "unit_label": null, "updated": 1668198126, "url": null } ``` Next, call [Create a price](https://docs.stripe.com/api/prices/create.md) to attach a price of 30 USD. Swap the placeholder in `product` with your product identifier (for example, `prod_LTenIrmp8Q67sa`). #### bash ```bash stripe prices create \ --unit-amount=3000 \ --currency=usd \ --product="{{PRODUCT_ID}}" ``` If everything worked, the command-line displays the following response. #### bash ```json { "id": "price_1KzlAMJJDeE9fu01WMJJr79o", // The identifier looks like this. "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1652636348, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "product": "prod_Lh9iTGZhb2mcBy", "recurring": null, "tax_behavior": "unspecified", "tiers_mode": null, "transform_quantity": null, "type": "one_time", "unit_amount": 3000, "unit_amount_decimal": "3000" } ``` ## Install the Node.js server-side SDK The latest version of the Stripe Node.js server-side SDK is v20.3.0. It supports Node.js versions 12+. Check your Node version: ```bash node --version ``` ### Initialize Node #### Initialize Node ```bash npm init ``` ### Install the library Install the library with [npm](https://www.npmjs.com/package/node), a package manager for Node: ```bash npm install stripe --save ``` After you install the library with npm, the library is automatically added as a dependency in your project’s package.json file. For example: ```json { "name": "stripe-node-example", "version": "1.0.0", "description": "A Stripe demo", "main": "index.js", "scripts": { "node ": "node create_price.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "stripe": "^20.3.0" } } ``` ### Installation alternatives **Yarn**—You can install the library with [yarn](https://yarnpkg.com/), another package manager for Node: ```bash yarn add stripe ``` ## Run your first SDK request Now that you have the Node.js SDK installed, you can create a subscription [Product](https://docs.stripe.com/api/products/create.md) and attach a [Price](https://docs.stripe.com/api/prices/create.md) with a couple API requests. The Node.js SDK returns [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which can be used as chainable callbacks. To demonstrate, we’re passing the product identifier returned in the Product response to create a Price in this example. > This sample uses the default keys of your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) for your *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment. Only you can see these values. #### Create a product and price ```node const stripe = require('stripe')('sk_test_BQokikJOvBiI2HlWgH4olfQ2'); stripe.products.create({ name: 'Starter Subscription', description: '$12/Month subscription', }).then(product => { stripe.prices.create({ unit_amount: 1200, currency: 'usd', recurring: { interval: 'month', }, product: product.id, }).then(price => { console.log('Success! Here is your starter subscription product id: ' + product.id); console.log('Success! Here is your starter subscription price id: ' + price.id); }); }); ``` Save the file as `create_price.js`. From the command line, `cd` to the directory containing the file you just saved and run: #### create_price.js ```bash node create_price.js ``` If everything worked, the command line shows the following response. Save these identifiers so you can use them while building your integration. #### bash ```bash Success! Here is your starter subscription product id: prod_0KxBDl589O8KAxCG1alJgiA6 Success! Here is your starter subscription price id: price_0KxBDm589O8KAxCGMgG7scjb ``` ## See also This wraps up the quickstart. See the links below for a few different ways to process a payment for the product you just created. - [Create a payment link](https://docs.stripe.com/payment-links.md) - [Prebuilt checkout page](https://docs.stripe.com/checkout/quickstart.md) - [Custom payment flow](https://docs.stripe.com/payments/quickstart.md) # PHP > This is a PHP for when lang is php. View the full page at https://docs.stripe.com/get-started/development-environment?lang=php. In this quickstart, you install the [Stripe CLI](https://docs.stripe.com/stripe-cli.md)—an essential tool that gets you command line access to your Stripe integration. You also install the [Stripe PHP server-side SDK](https://github.com/stripe/stripe-php) to get access to Stripe APIs from applications written in PHP. ## What you learn In this quickstart, you’ll learn: - How to call Stripe APIs without writing a line of code - How to manage third-party dependencies using Composer - How to install the latest Stripe PHP SDK v19.3.0 - How to send your first SDK request ## Initial setup First, [create a Stripe account](https://dashboard.stripe.com/register) or [sign in](https://dashboard.stripe.com/login). ## Set up the Stripe CLI ### Install From the command-line, use an install script or download and extract a versioned archive file for your operating system to install the CLI. #### homebrew To install the Stripe CLI with [homebrew](https://brew.sh/), run: ```bash brew install stripe/stripe-cli/stripe ``` This command fails if you run it on the Linux version of homebrew, but you can use this alternative or follow the instructions on the Linux tab. ```bash brew install stripe-cli ``` #### apt > The Debian build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. > On April 5th, 2024, we changed Stripe CLI’s GPG key to install the Stripe CLI through apt. If you configured the public key before April 5th, you’ll encounter this error: > > ``` W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://packages.stripe.dev/stripe-cli-debian-local stable InRelease: The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Failed to fetch https://packages.stripe.dev/stripe-cli-debian-local/dists/stable/InRelease The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Some index files failed to download. They have been ignored, or old ones used instead ``` > > To resolve this error, refresh Stripe’s GPG key by following [step 1](https://docs.stripe.com/get-started/development-environment.md#step_one). To install the Stripe CLI on Debian and Ubuntu-based distributions: 1. Add Stripe CLI’s GPG key to the apt sources keyring: ```bash curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor | sudo tee /usr/share/keyrings/stripe.gpg ``` 1. Add CLI’s apt repository to the apt sources list: ```bash echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" | sudo tee -a /etc/apt/sources.list.d/stripe.list ``` 1. Update the package list: ```bash sudo apt update ``` 1. Install the CLI: ```bash sudo apt install stripe ``` #### yum > The RPM build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. To install the Stripe CLI on RPM-based distributions: 1. Add CLI’s yum repository to the yum sources list: ```bash echo -e "[Stripe]\nname=stripe\nbaseurl=https://packages.stripe.dev/stripe-cli-rpm-local/\nenabled=1\ngpgcheck=0" >> /etc/yum.repos.d/stripe.repo ``` 1. Install the CLI: ```bash sudo yum install stripe ``` #### Scoop To install the Stripe CLI with [Scoop](https://scoop.sh/), run: ```bash scoop bucket add stripe https://github.com/stripe/scoop-stripe-cli.git ``` ```bash scoop install stripe ``` #### macOS To install the Stripe CLI on macOS without homebrew: 1. Download the latest `mac-os` tar.gz file of your cpu architecture type from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_[X.X.X]_mac-os_[ARCH_TYPE].tar.gz`. Optionally, install the binary in a location where you can execute it globally (for example, `/usr/local/bin`). #### Linux To install the Stripe CLI on Linux without a package manager: 1. Download the latest `linux` tar.gz file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_X.X.X_linux_x86_64.tar.gz`. 1. Move `./stripe` to your execution path. #### Windows To install the Stripe CLI on Windows without Scoop: 1. Download the latest `windows` zip file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the `stripe_X.X.X_windows_x86_64.zip` file. 1. Add the path to the unzipped `stripe.exe` file to your `Path` environment variable. To learn how to update environment variables, see the [Microsoft PowerShell documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.3#saving-changes-to-environment-variables). > Windows anti-virus scanners occasionally flag the Stripe CLI as unsafe. This is likely a false positive. For more information, see [issue #692](https://github.com/stripe/stripe-cli/issues/692) in the GitHub repository. 1. Run the unzipped `.exe` file. #### Docker The Stripe CLI is also available as a [Docker image](https://hub.docker.com/r/stripe/stripe-cli). To install the latest version, run: ```bash docker run --rm -it stripe/stripe-cli:latest ``` ### Authenticate Log in and authenticate your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) to generate a set of restricted keys. To learn more, see [Stripe CLI keys and permissions](https://docs.stripe.com/stripe-cli/keys.md). ```bash stripe login ``` Press **Enter** on your keyboard to complete the authentication process in your browser. ```bash Your pairing code is: enjoy-enough-outwit-win This pairing code verifies your authentication with Stripe. Press Enter to open the browser or visit https://dashboard.stripe.com/stripecli/confirm_auth?t=THQdJfL3x12udFkNorJL8OF1iFlN8Az1 (^C to quit) ``` ### Confirm setup Now that you’ve installed the CLI, you can make a single API request to [Create a product](https://docs.stripe.com/api/products/create.md). #### bash ```bash stripe products create \ --name="My First Product" \ --description="Created with the Stripe CLI" ``` Look for the product identifier (in `id`) in the response object. Save it for the next step. If everything worked, the command-line displays the following response. #### bash ```json { "id": "prod_LTenIrmp8Q67sa", // The identifier looks like this. "object": "product", "active": true, "attributes": [], "created": 1668198126, "default_price": null, "description": "Created with the Stripe CLI", "identifiers": {}, "images": [], "livemode": false, "metadata": {}, "name": "My First Product", "package_dimensions": null, "price": null, "product_class": null, "shippable": null, "sku": "my-first-product-10", "statement_descriptor": null, "tax_code": null, "type": "service", "unit_label": null, "updated": 1668198126, "url": null } ``` Next, call [Create a price](https://docs.stripe.com/api/prices/create.md) to attach a price of 30 USD. Swap the placeholder in `product` with your product identifier (for example, `prod_LTenIrmp8Q67sa`). #### bash ```bash stripe prices create \ --unit-amount=3000 \ --currency=usd \ --product="{{PRODUCT_ID}}" ``` If everything worked, the command-line displays the following response. #### bash ```json { "id": "price_1KzlAMJJDeE9fu01WMJJr79o", // The identifier looks like this. "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1652636348, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "product": "prod_Lh9iTGZhb2mcBy", "recurring": null, "tax_behavior": "unspecified", "tiers_mode": null, "transform_quantity": null, "type": "one_time", "unit_amount": 3000, "unit_amount_decimal": "3000" } ``` ## Manage third-party dependencies We recommend managing third-party dependencies from [Packagist](https://packagist.org/) using [Composer](https://getcomposer.org/download/), which allows you to add new libraries and include them in your PHP projects. ### Install Composer From the command line, [download Composer](https://getcomposer.org/download/) using the instructions. ## Install the PHP server-side SDK The latest version of the Stripe PHP server-side SDK is v19.3.0. It supports PHP versions 5.6.0+. Check your PHP version: ```bash php --version ``` ### Install the library Install the library with [Composer](http://getcomposer.org/), a package manager for PHP: ```bash composer require stripe/stripe-php ``` After you install the library with Composer, it’s automatically added as a dependency in your project’s composer.json file. For example: ```json { "require": { "stripe/stripe-php": "^19.3.0" } } ``` To use the bindings, use Composer’s [autoload](https://getcomposer.org/doc/01-basic-usage.md#autoloading). For example: ```php require_once('vendor/autoload.php'); ``` ### Installation alternatives **Manual installation** You can [download the latest release](https://github.com/stripe/stripe-php/releases) to use the bindings, then include the init.php file: ```php require_once('/path/to/stripe-php/init.php'); ``` Then, add the following extensions: [cURL](https://secure.php.net/manual/en/book.curl.php) (or optionally, use your own non-curl client) [json](https://secure.php.net/manual/en/book.json.php) [mbstring](https://secure.php.net/manual/en/book.mbstring.php) ## Run your first SDK request Now that you have the PHP SDK installed, you can create a subscription [Product](https://docs.stripe.com/api/products/create.md) and attach a [Price](https://docs.stripe.com/api/prices/create.md) with a couple API requests. We’re using the product identifier returned in the response to create the price in this example. > This sample uses the default keys of your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) for your *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment. Only you can see these values. #### Create a product and price ```php products->create([ 'name' => 'Starter Subscription', 'description' => '$12/Month subscription', ]); echo "Success! Here is your starter subscription product id: " . $product->id . "\n"; $price = $stripe->prices->create([ 'unit_amount' => 1200, 'currency' => 'usd', 'recurring' => ['interval' => 'month'], 'product' => $product['id'], ]); echo "Success! Here is your starter subscription price id: " . $price->id . "\n"; ?> ``` Save the file as `create_price.php`. From the command line, `cd` to the directory containing the file you just saved and run: #### create_price.php ```bash php create_price.php ``` If everything worked, the command line shows the following response. Save these identifiers so you can use them while building your integration. #### bash ```bash Success! Here is your starter subscription product id: price_0KxBDl589O8KAxCG1alJgiA6 Success! Here is your starter subscription price id: price_0KxBDm589O8KAxCGMgG7scjb ``` ## See also This wraps up the quickstart. See the links below for a few different ways to process a payment for the product you just created. - [Create a payment link](https://docs.stripe.com/payment-links.md) - [Prebuilt checkout page](https://docs.stripe.com/checkout/quickstart.md) - [Custom payment flow](https://docs.stripe.com/payments/quickstart.md) # .NET > This is a .NET for when lang is dotnet. View the full page at https://docs.stripe.com/get-started/development-environment?lang=dotnet. In this quickstart, you install the [Stripe CLI](https://docs.stripe.com/stripe-cli.md)—an essential tool that gets you command line access to your Stripe integration. You also install the [Stripe .NET server-side SDK](https://github.com/stripe/stripe-dotnet) to get access to Stripe APIs from applications written in C#. ## What you learn In this quickstart, you’ll learn: - How to call Stripe APIs without writing a line of code - How to manage third-party dependencies using the .NET Core CLI, NuGet CLI or the Package Manager Console - How to install the latest Stripe .NET SDK v50.3.0 - How to send your first SDK request ## Initial setup First, [create a Stripe account](https://dashboard.stripe.com/register) or [sign in](https://dashboard.stripe.com/login). ## Set up the Stripe CLI ### Install From the command-line, use an install script or download and extract a versioned archive file for your operating system to install the CLI. #### homebrew To install the Stripe CLI with [homebrew](https://brew.sh/), run: ```bash brew install stripe/stripe-cli/stripe ``` This command fails if you run it on the Linux version of homebrew, but you can use this alternative or follow the instructions on the Linux tab. ```bash brew install stripe-cli ``` #### apt > The Debian build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. > On April 5th, 2024, we changed Stripe CLI’s GPG key to install the Stripe CLI through apt. If you configured the public key before April 5th, you’ll encounter this error: > > ``` W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://packages.stripe.dev/stripe-cli-debian-local stable InRelease: The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Failed to fetch https://packages.stripe.dev/stripe-cli-debian-local/dists/stable/InRelease The following signatures were invalid: EXPKEYSIG DEEBD57F917C83E3 Stripe W: Some index files failed to download. They have been ignored, or old ones used instead ``` > > To resolve this error, refresh Stripe’s GPG key by following [step 1](https://docs.stripe.com/get-started/development-environment.md#step_one). To install the Stripe CLI on Debian and Ubuntu-based distributions: 1. Add Stripe CLI’s GPG key to the apt sources keyring: ```bash curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor | sudo tee /usr/share/keyrings/stripe.gpg ``` 1. Add CLI’s apt repository to the apt sources list: ```bash echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" | sudo tee -a /etc/apt/sources.list.d/stripe.list ``` 1. Update the package list: ```bash sudo apt update ``` 1. Install the CLI: ```bash sudo apt install stripe ``` #### yum > The RPM build for the CLI is available on JFrog at https://packages.stripe.dev, which is not a domain owned by Stripe. When you visit this URL, it redirects you to the Jfrog artifactory list. To install the Stripe CLI on RPM-based distributions: 1. Add CLI’s yum repository to the yum sources list: ```bash echo -e "[Stripe]\nname=stripe\nbaseurl=https://packages.stripe.dev/stripe-cli-rpm-local/\nenabled=1\ngpgcheck=0" >> /etc/yum.repos.d/stripe.repo ``` 1. Install the CLI: ```bash sudo yum install stripe ``` #### Scoop To install the Stripe CLI with [Scoop](https://scoop.sh/), run: ```bash scoop bucket add stripe https://github.com/stripe/scoop-stripe-cli.git ``` ```bash scoop install stripe ``` #### macOS To install the Stripe CLI on macOS without homebrew: 1. Download the latest `mac-os` tar.gz file of your cpu architecture type from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_[X.X.X]_mac-os_[ARCH_TYPE].tar.gz`. Optionally, install the binary in a location where you can execute it globally (for example, `/usr/local/bin`). #### Linux To install the Stripe CLI on Linux without a package manager: 1. Download the latest `linux` tar.gz file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the file: `tar -xvf stripe_X.X.X_linux_x86_64.tar.gz`. 1. Move `./stripe` to your execution path. #### Windows To install the Stripe CLI on Windows without Scoop: 1. Download the latest `windows` zip file from [GitHub](https://github.com/stripe/stripe-cli/releases/latest). 1. Unzip the `stripe_X.X.X_windows_x86_64.zip` file. 1. Add the path to the unzipped `stripe.exe` file to your `Path` environment variable. To learn how to update environment variables, see the [Microsoft PowerShell documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-7.3#saving-changes-to-environment-variables). > Windows anti-virus scanners occasionally flag the Stripe CLI as unsafe. This is likely a false positive. For more information, see [issue #692](https://github.com/stripe/stripe-cli/issues/692) in the GitHub repository. 1. Run the unzipped `.exe` file. #### Docker The Stripe CLI is also available as a [Docker image](https://hub.docker.com/r/stripe/stripe-cli). To install the latest version, run: ```bash docker run --rm -it stripe/stripe-cli:latest ``` ### Authenticate Log in and authenticate your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) to generate a set of restricted keys. To learn more, see [Stripe CLI keys and permissions](https://docs.stripe.com/stripe-cli/keys.md). ```bash stripe login ``` Press **Enter** on your keyboard to complete the authentication process in your browser. ```bash Your pairing code is: enjoy-enough-outwit-win This pairing code verifies your authentication with Stripe. Press Enter to open the browser or visit https://dashboard.stripe.com/stripecli/confirm_auth?t=THQdJfL3x12udFkNorJL8OF1iFlN8Az1 (^C to quit) ``` ### Confirm setup Now that you’ve installed the CLI, you can make a single API request to [Create a product](https://docs.stripe.com/api/products/create.md). #### bash ```bash stripe products create \ --name="My First Product" \ --description="Created with the Stripe CLI" ``` Look for the product identifier (in `id`) in the response object. Save it for the next step. If everything worked, the command-line displays the following response. #### bash ```json { "id": "prod_LTenIrmp8Q67sa", // The identifier looks like this. "object": "product", "active": true, "attributes": [], "created": 1668198126, "default_price": null, "description": "Created with the Stripe CLI", "identifiers": {}, "images": [], "livemode": false, "metadata": {}, "name": "My First Product", "package_dimensions": null, "price": null, "product_class": null, "shippable": null, "sku": "my-first-product-10", "statement_descriptor": null, "tax_code": null, "type": "service", "unit_label": null, "updated": 1668198126, "url": null } ``` Next, call [Create a price](https://docs.stripe.com/api/prices/create.md) to attach a price of 30 USD. Swap the placeholder in `product` with your product identifier (for example, `prod_LTenIrmp8Q67sa`). #### bash ```bash stripe prices create \ --unit-amount=3000 \ --currency=usd \ --product="{{PRODUCT_ID}}" ``` If everything worked, the command-line displays the following response. #### bash ```json { "id": "price_1KzlAMJJDeE9fu01WMJJr79o", // The identifier looks like this. "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1652636348, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "product": "prod_Lh9iTGZhb2mcBy", "recurring": null, "tax_behavior": "unspecified", "tiers_mode": null, "transform_quantity": null, "type": "one_time", "unit_amount": 3000, "unit_amount_decimal": "3000" } ``` ## Install the .NET server-side SDK The latest version of the Stripe .NET server-side SDK is v50.3.0. It supports .NET Standard 2.0+, .NET Core 2.0+, and .NET Framework 4.6.1+. Check your [.NET SDK](https://docs.microsoft.com/en-us/dotnet/core/install/how-to-detect-installed-versions) version: ```bash dotnet --list-sdks ``` ### Install the library Use the [.NET Core Command Line Interface (CLI)](https://docs.microsoft.com/en-us/dotnet/core/tools/) to create a new project from the command line: ```bash dotnet new console ``` To install the library, run this command to add the package reference to your project file (`.csproj`): ```bash dotnet add package Stripe.net ``` After you install the library with the CLI, the library is automatically added as a dependency in your project file (`.csproj`). For example: ```xml Exe net6.0 enable enable ``` ### Installation alternatives **NuGet Command Line Interface (CLI)**—You can use the [NuGet CLI](https://docs.microsoft.com/en-us/nuget/tools/nuget-exe-cli-reference) to install the library: ```bash nuget install Stripe.net ``` **Package Manager Console (PowerShell)**—If you’re using the [Package Manager Console (PowerShell)](https://docs.microsoft.com/en-us/nuget/tools/package-manager-console), run the following command to install the library: ```PowerShell Install-Package Stripe.net ``` **VisualStudio**—To add the Stripe.net package to Visual Studio: Open the Solution Explorer. Right-click your project. Click **Manage NuGet Packages**. Click the **Browse** tab and search for **Stripe.net**. Click the **Stripe.net** package, select the appropriate version in the tab and click **Install**. ## Run your first SDK request Now that you have the .NET SDK installed, you can create a subscription [Product](https://docs.stripe.com/api/products/create.md) and attach a [Price](https://docs.stripe.com/api/prices/create.md) with a couple API requests. We’re using the product identifier returned in the response to create the price in this example. > This sample uses the default keys of your Stripe user [account](https://docs.stripe.com/get-started/account/activate.md) for your *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment. Only you can see these values. #### Create a product and price ```dotnet using System; using Stripe; class Program { static void Main(string[] args) { StripeConfiguration.ApiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"; var optionsProduct = new ProductCreateOptions { Name = "Starter Subscription", Description = "$12/Month subscription", }; var serviceProduct = new ProductService(); Product product = serviceProduct.Create(optionsProduct); Console.Write("Success! Here is your starter subscription product id: {0}\n", product.Id); var optionsPrice = new PriceCreateOptions { UnitAmount = 1200, Currency = "usd", Recurring = new PriceRecurringOptions { Interval = "month", }, Product = product.Id }; var servicePrice = new PriceService(); Price price = servicePrice.Create(optionsPrice); Console.Write("Success! Here is your starter subscription price id: {0}\n", price.Id); } } ``` Save the code to the `Program.cs` file in your project. From the command line, `cd` to the directory containing the file you just saved and run: #### Program.cs ```bash dotnet run ``` If everything worked, the command line shows the following response. Save these identifiers so you can use them while building your integration. #### bash ```bash Success! Here is your starter subscription product id: prod_0KxBDl589O8KAxCG1alJgiA6 Success! Here is your starter subscription price id: price_0KxBDm589O8KAxCGMgG7scjb ``` ## See also This wraps up the quickstart. See the links below for a few different ways to process a payment for the product you just created. - [Create a payment link](https://docs.stripe.com/payment-links.md) - [Prebuilt checkout page](https://docs.stripe.com/checkout/quickstart.md) - [Custom payment flow](https://docs.stripe.com/payments/quickstart.md) --- # Source: https://docs.stripe.com/issuing/cards/digital-wallets.md # Use digital wallets with Issuing Learn how to use Issuing to add cards to digital wallets. > Digital wallets tokens are only available in live mode. To fully test these features, you need to be approved for live use cases and use real cards. Issuing allows users to add cards to digital wallets like Apple Pay and Google Pay. Stripe supports the addition of cards through two methods: 1. **Manual Provisioning:** cardholders enter their card details into a phone’s wallet application to add it to their digital wallets. 1. **Push Provisioning:** mobile applications allow users to add cards to their digital wallets straight from the app. When a card is added to a digital wallet, a tokenized representation of that card is created. Network tokens are managed separately from cards. For more information about network tokens and how they work, see [Token Management](https://docs.stripe.com/issuing/controls/token-management.md). ## Manual Provisioning Cardholders can add Stripe Issuing [virtual cards](https://docs.stripe.com/issuing/cards/virtual.md) and [physical cards](https://docs.stripe.com/issuing/cards/physical.md) to their Apple Pay, Google Pay, and Samsung Pay wallets through manual provisioning. To do so, cardholders open the wallet app on their phone and enter their card details. Stripe then sends a 6-digit verification code to the `phone_number` or `email` of the cardholder associated with the card. A `card not supported` error displays if neither field is set on the cardholder when the card was provisioned. No code is required to implement manual provisioning, but the process to set it up can vary depending on the digital wallet provider and the country you’re based in: ### US Apple Pay wallets require approval from Apple. Check your [digital wallets settings](https://dashboard.stripe.com/settings/issuing/digital-wallets) to view the status of Apple Pay in your account. You might need to submit an application before using Apple Pay. After the application is submitted, approval can take 1-2 weeks. Google Pay and Samsung Pay have no additional required steps. ### EU and UK Digital wallet integrations require additional approval from the Stripe partnership team. Get in touch with your account representative or [contact Stripe](https://stripe.com/contact/sales) for more information. Apple Pay wallets require additional approval. Check your [digital wallets settings](https://dashboard.stripe.com/settings/issuing/digital-wallets) to view the status of Apple Pay in your account. You might need to submit an application before using Apple Pay. ## Push provisioning Push provisioning allows cardholders to add a Stripe Issuing cards to their digital wallets directly from your app by pressing an “add to wallet” button like the ones shown below. Users must first complete manual provisioning steps to enable push provisioning in the US. In addition to manual provisioning approval, push provisioning requires you to integrate with the Stripe SDK. This requires both approval processes through Stripe and code integration with the Stripe SDK for each platform you wish to support push provisioning on. Platform approvals cascade down to all of their connected accounts. Samsung Pay push provisioning isn’t supported with our SDKs. # iOS > This is a iOS for when platform is ios. View the full page at https://docs.stripe.com/issuing/cards/digital-wallets?platform=ios. ![A black UI button that says Add to Apple Wallet. There is an Apple Wallet logo image to the left of the text. It is a grey wallet with blue, yellow, green, and red cards stacked slightly offset.](https://b.stripecdn.com/docs-statics-srv/assets/add_to_apple_wallet.fe8cd234760a7478e34f5e91d22677bb.png) ## Request access > You must get accesss to [manual provisioning](https://docs.stripe.com/issuing/cards/digital-wallets.md?platform=android#manual-provisioning) before you can request push provisioning. Push provisioning requires a special entitlement from Apple called `com.apple.developer.payment-pass-provisioning`. You can request it by emailing [support-issuing@stripe.com](mailto:support-issuing@stripe.com). In your email, include your: - **Card network**: Visa or MasterCard. - **Card name**: The name of the card displayed in the wallet. - **App name**: Your app’s name. - **Developer team ID**: Found in your Apple Developer account settings under [membership](https://developer.apple.com/account/#/membership) (for example, `2A23JCNA5E`). - **ADAM ID**: Your app’s unique numeric ID. Found in [App Store Connect](https://appstoreconnect.apple.com), or in the App Store link to your app (for example, `https://apps.apple.com/app/id123456789`). - **Bundle ID**: Your app’s bundle identifier, also found in App Store Connect (for example, `com.example.yourapp`). If you have multiple apps (such as for testing), that have any different fields for the above attributes, you’ll need to request access for each of these. After we approve and apply your request, your app appears on the details page of a provisioned card in the Wallet app, and the `PKSecureElementPass` object is available in your app by calling `PKPassLibrary().passes()`. You might need to remove and re-provision the card for the change to take effect. ## Check eligibility [Client-side] Make sure you’ve integrated the latest version of the [Stripe iOS SDK](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=mobile&platform=ios) with your app. Determine if the device is eligible to use push provisioning. 1. Check that the value of `wallets[apple_pay][eligible]` in the issued card is `true`. 1. Call `PKPassLibrary().canAddSecureElementPass(primaryAccountIdentifier:)` with the `wallets[primary_account_identifier]` from your card, and check that the result is `true`. If the `primary_account_identifier` is empty, pass an empty string to `canAddSecureElementPass()`. Retrieve these values on your back end, then pass them to your app for the eligibility check. > You must check the server-side `wallets[apple_pay][eligible]` flag and the result of `canAddSecureElementPass()` before showing the `PKAddPassButton`. If you show an **Add to Apple Wallet** button without checking these values, App Review might reject your app. #### Swift ```swift import Stripe class MyViewController: UIViewController { @IBOutlet weak var addPassButton: PKAddPassButton! // ... func handleEligibilityResponse(eligible: Bool, primaryAccountIdentifier: String?) { if eligible && PKPassLibrary().canAddSecureElementPass(primaryAccountIdentifier: primaryAccountIdentifier ?? "") { addPassButton.isHidden = false } else { addPassButton.isHidden = true } } } ``` #### Objective C ```objc @import Stripe; @interface ViewController () @property (nonatomic, weak) IBOutlet PKAddPassButton *addPassButton; @end @implementation ViewController - (void)handleEligibilityResponse:(BOOL)eligible primaryAccountIdentifier:(NSString *)primaryAccountIdentifier { if (eligible && [[[PKPassLibrary alloc] init] canAddSecureElementPassWithPrimaryAccountIdentifier:primaryAccountIdentifier]) { [self.addPassButton setHidden:false]; } else { [self.addPassButton setHidden:true]; } } @end ``` For more context, see the code snippets and references to the sample app at each step. For this step, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/ios/Code/ViewController.swift#L201-L218) checks eligibility. ## Provision a card [Client-side] When the user taps the `PKAddPassButton`, create and present a `PKAddPaymentPassViewController`, which contains Apple’s UI for the push provisioning flow. `PKAddPaymentPassViewController` can use the `primaryAccountIdentifier` from the previous step to determine if a card has already been provisioned on a specific device. For example, if the card has already been added to an iPhone, Apple’s UI offers to add it to a paired Apple Watch. #### Swift ```swift import Stripe class MyViewController: UIViewController { // ... func beginPushProvisioning() { let config = STPPushProvisioningContext.requestConfiguration( withName: "Jenny Rosen", // the cardholder's name description: "RocketRides Card", // optional; a description of your card last4: "4242", // optional; the last 4 digits of the card brand: .visa, // optional; the brand of the card primaryAccountIdentifier: self.primaryAccountIdentifier // the primary_account_identifier value from the previous step ) let controller = PKAddPaymentPassViewController(requestConfiguration: config, delegate: self) self.present(controller!, animated: true, completion: nil) } } ``` #### Objective C ```objc @import Stripe; @implementation ViewController - (void)beginPushProvisioning { PKAddPaymentPassRequestConfiguration *config = [STPPushProvisioningContext requestConfigurationWithName:@"Jenny Rosen" description:@"RocketRides Card" last4:@"4242" brand:STPCardBrandVisa primaryAccountIdentifier:self.primaryAccountIdentifier]; PKAddPaymentPassViewController *controller = [[PKAddPaymentPassViewController alloc] initWithRequestConfiguration:config delegate:self]; [self presentViewController:controller animated:YES completion:nil]; } @end ``` For more context, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/ios/Code/ViewController.swift#L280-L288) uses a `PKAddPaymentPassViewController`. The `PKAddPaymentPassViewController`’s initializer takes a delegate that you need to implement – typically this can just be the view controller from which you’re presenting it. We provide a class called `STPPushProvisioningContext` to help you implement these methods. #### Swift ```swift class MyViewController: UIViewController { var pushProvisioningContext: STPPushProvisioningContext? = nil // ... } extension MyViewController: PKAddPaymentPassViewControllerDelegate { func addPaymentPassViewController(_ controller: PKAddPaymentPassViewController, generateRequestWithCertificateChain certificates: [Data], nonce: Data, nonceSignature: Data, completionHandler handler: @escaping (PKAddPaymentPassRequest) -> Void) { self.pushProvisioningContext = STPPushProvisioningContext(keyProvider: self) // STPPushProvisioningContext implements this delegate method for you, by retrieving encrypted card details from the Stripe API. self.pushProvisioningContext?.addPaymentPassViewController(controller, generateRequestWithCertificateChain: certificates, nonce: nonce, nonceSignature: nonceSignature, completionHandler: handler); } func addPaymentPassViewController(_ controller: PKAddPaymentPassViewController, didFinishAdding pass: PKPaymentPass?, error: Error?) { // Depending on if `error` is present, show a success or failure screen. self.dismiss(animated: true, completion: nil) } } ``` #### Objective C ```objc @interface ViewController () @property STPPushProvisioningContext *pushProvisioningContext; @end @implementation ViewController - (void)addPaymentPassViewController:(PKAddPaymentPassViewController *)controller generateRequestWithCertificateChain:(NSArray *)certificates nonce:(NSData *)nonce nonceSignature:(NSData *)nonceSignature completionHandler:(void (^)(PKAddPaymentPassRequest * _Nonnull))handler { self.pushProvisioningContext = [[STPPushProvisioningContext alloc] initWithKeyProvider:self]; // STPPushProvisioningContext implements this delegate method for you, by retrieving encrypted card details from the Stripe API. [self.pushProvisioningContext addPaymentPassViewController:controller generateRequestWithCertificateChain:certificates nonce:nonce nonceSignature:nonceSignature completionHandler:handler]; } - (void)addPaymentPassViewController:(PKAddPaymentPassViewController *)controller didFinishAddingPaymentPass:(PKPaymentPass *)pass error:(NSError *)error { // Depending on if `error` is present, show a success or failure screen. [self dismissViewControllerAnimated:YES completion:nil]; } @end ``` For more context, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/ios/Code/ViewController.swift#L293-L349) implements `PKAddPaymentPassViewControllerDelegate`. You can see that the `STPPushProvisioningContext`’s initializer expects a `keyProvider`. This is an instance of a class that implements the `STPIssuingCardEphemeralKeyProvider` protocol. This protocol defines a single required method, `createIssuingCardKeyWithAPIVersion:completion`. To implement this method, make an API call to your backend. Your backend creates an Ephemeral Key object using the Stripe API, and returns it to your app. Your app then calls the provided completion handler with your backend’s API response. #### Swift ```swift extension MyViewController: STPIssuingCardEphemeralKeyProvider { func createIssuingCardKey(withAPIVersion apiVersion: String, completion: @escaping STPJSONResponseCompletionBlock) { // This example uses Alamofire for brevity, but you can make the request however you want AF.request("https://myapi.com/ephemeral_keys", method: .post, parameters: ["api_version": apiVersion]) .responseJSON { response in switch response.result { case .success: if let data = response.data { do { let obj = try JSONSerialization.jsonObject(with: data, options: []) as! [AnyHashable: Any] completion(obj, nil) } catch { completion(nil, error) } } case .failure(let error): completion(nil, error) } } } } ``` #### Objective C ```objc @interface ViewController () @end @implementation ViewController - (void)createIssuingCardKeyWithAPIVersion:(NSString *)apiVersion completion:(STPJSONResponseCompletionBlock)completion { NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; NSURL *url = [NSURL URLWithString:@"https://myapi.com/ephemeral_keys"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.HTTPMethod = @"POST"; NSString *postBody = [@"api_version=" stringByAppendingString:apiVersion]; request.HTTPBody = [postBody dataUsingEncoding:NSUTF8StringEncoding]; [[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSDictionary *parsed = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; completion(parsed, error); }] resume]; } @end ``` For more context, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/ios/Code/ViewController.swift#L379-L394) implements `STPIssuingCardEphemeralKeyProvider`. ## Update your backend [Server-side] The push provisioning implementation exposes methods that expect you to communicate with your own backend to create a Stripe Ephemeral Key and return a JSON of it to your app. This key is a short-lived API credential that you can use to retrieve the encrypted card details for a single instance of a card object. To make sure that the object returned by the Stripe API is compatible with the version of the iOS or Android SDK you’re using, the Stripe SDK lets you know what API version it prefers. You must explicitly pass this API version to our API when creating the key. #### curl ```bash curl https://api.stripe.com/v1/ephemeral_keys \ -u <>: \ -d "issuing_card"="{{ISSUING_CARD_ID}}" \ -H "Stripe-Version: {{API_VERSION}}" ``` #### Ruby ```ruby # ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for # push provisioning. key = Stripe::EphemeralKey.create( {issuing_card: '{{ISSUING_CARD_ID}}'}, {stripe_version: '{{API_VERSION}}'} ) return key.to_json ``` #### Python ```python # ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for # push provisioning. key = stripe.EphemeralKey.create( issuing_card='{{ISSUING_CARD_ID}}', stripe_version='{{API_VERSION}}', ) return jsonify(key) ``` #### PHP ```php // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. $key = \Stripe\EphemeralKey::create( ['issuing_card' => '{{ISSUING_CARD_ID}}'], ['stripe_version' => '{{API_VERSION}}'] ); return json_encode($key); ``` #### Node.js ```javascript // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. let key = await stripe.ephemeralKeys.create( {issuing_card: '{{ISSUING_CARD_ID}}'}, {apiVersion: '{{API_VERSION}}'} ); res.json(key); ``` #### Java ```java // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. RequestOptions requestOptions = (new RequestOptions.RequestOptionsBuilder()) .setStripeVersion("{{API_VERSION}}") .build(); Map options = new HashMap(); options.put("issuing_card", "{{ISSUING_CARD_ID}}"); EphemeralKey key = EphemeralKey.create(options, requestOptions); return key.getRawJson(); ``` #### Go ```go // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. params := &stripe.EphemeralKeyParams{ IssuingCard: stripe.String("{{ISSUING_CARD_ID}}"), StripeVersion: stripe.String("{{API_VERSION}}"), } key, err := ephemeralkey.New(params) return key.RawJSON ``` #### .NET ```dotnet // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. var options = new EphemeralKeyCreateOptions { IssuingCard = "{{ISSUING_CARD_ID}}", StripeVersion = "{{API_VERSION}}" }; var service = new EphemeralKeyService(); service.Create(options); return key.RawJson; ``` ```json { "id": "ephkey_1G4V6eEEs6YsaMZ2P1diLWdj", "object": "ephemeral_key", "associated_objects": [ { "id": "ic_1GWQp6EESaYspYZ9uSEZOcq9", "type": "issuing.card" } ], "created": 1586556828, "expires": 1586560428, "livemode": false, "secret": "ek_test_YWNjdF8xRmdlTjZFRHelWWxwWVo5LEtLWFk0amJ2N0JOa0htU1JzEZkd2RpYkpJdnM_00z2ftxCGG" } ``` For more context, see how the [sample backend](https://github.com/stripe-samples/push-provisioning-samples/blob/main/server/ruby/README.md) creates a [Stripe Ephemeral Key](https://github.com/stripe-samples/push-provisioning-samples/blob/main/server/ruby/server.rb#L68-L88). ## Testing The `com.apple.developer.payment-pass-provisioning` entitlement only works with distribution provisioning profiles, meaning even after you obtain it, the only way to test the end-to-end push provisioning flow is by distributing your app with TestFlight or the App Store. To help with testing, we provide a mock version of `PKAddPaymentPassViewController` called `STPFakeAddPaymentPassViewController` that you can use interchangeably during testing. This only works in [test mode](https://docs.stripe.com/testing-use-cases.md#test-versus-live-mode) using test mode cards. #### Swift ```swift import Stripe class MyViewController: UIViewController { // ... func beginPushProvisioning() { let config = STPPushProvisioningContext.requestConfiguration( withName: "Jenny Rosen", // the cardholder's name description: "RocketRides Card", // optional; a description of your card last4: "4242", // optional; the last 4 digits of the card brand: .visa // optional; the brand of the card )let controller = STPFakeAddPaymentPassViewController(requestConfiguration: config, delegate: self) self.present(controller!, animated: true, completion: nil) } } ``` #### Objective C ```objc @import Stripe; @implementation ViewController - (void)beginPushProvisioning { PKAddPaymentPassRequestConfiguration *config = [STPPushProvisioningContext requestConfigurationWithName:@"Jenny Rosen" description:@"RocketRides Card" last4:@"4242" brand:STPCardBrandVisa]; PKAddPaymentPassViewController *controller = [[STPFakeAddPaymentPassViewController alloc] initWithRequestConfiguration:config delegate:self];[self presentViewController:controller animated:YES completion:nil]; } @end ``` To build the sample app, follow the steps in the [readme](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/ios/README.md). You don’t need to build the app to follow the instructions above. # Android > This is a Android for when platform is android. View the full page at https://docs.stripe.com/issuing/cards/digital-wallets?platform=android. ![A black UI button that says Add to Google Wallet. There is a Google Wallet logo image to the left of the text.](https://b.stripecdn.com/docs-statics-srv/assets/add_to_google_pay_black.2df6c169bbc605123ec73d37dc73a86e.png) ## Request access > You must get accesss to [manual provisioning](https://docs.stripe.com/issuing/cards/digital-wallets.md?platform=android#manual-provisioning) before you can request push provisioning. Stripe provides an SDK wrapper around a private Google library for push provisioning. To distribute your app on the Google Pay Store with push provisioning you need to: 1. [Request access to Google Pay](https://developers.google.com/pay/issuers/requesting-access?api=true). After you complete the form, expect approval within a few hours to a day. 1. After receiving approval, download Google’s [TapAndPay private SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/releases). The most recently tested version of the TapAndPay SDK is version 18. 1. [Request access to the push provisioning API](https://support.google.com/faqs/contact/pp_api_allowlist) for your app. You must provide your [application ID](https://developer.android.com/studio/build/application-id) to be added to Google’s allowlist. Details on this process are available in Google’s [documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/allowlist). After the process is complete, Google grants push provisioning entitlements. 1. After Google has granted push provisioning entitlements, [contact Stripe](mailto:support-issuing@stripe.com) with your application name, application ID, card network, and card name to complete this step. ## Update your app [Client-side] To update your app: 1. Import Google’s [private SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/setup). 1. Import Stripe’s SDK. ```java dependencies { [... your dependencies] implementation 'com.stripe:stripe-android-issuing-push-provisioning:1.2.2' } ``` For more context, see the code snippets and references to the sample app at each step. For this step, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/app/build.gradle.kts#L111-L118) imports these SDKs. - Prepare your backend to create ephemeral keys for your cards. [See section below](https://docs.stripe.com/issuing/cards/digital-wallets.md#backend-changes). - Create an `EphemeralKeyProvider` that extends `PushProvisioningEphemeralKeyProvider`. As the ephemeral key provider will be passed to another activity, it also needs to implement `Parcelable` (see [Parcelable](https://developer.android.com/reference/android/os/Parcelable)). For more context, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/app/src/main/java/com/stripe/android/pushprovisioning/network/BackendPushProvisioningEphemeralKeyProvider.kt#L20-L43) defines its `EphemeralKeyProvider`. - Implement the **Add to Google Pay** button [according to Google’s specifications](https://developers.google.com/pay/issuers/apis/push-provisioning/android/branding-guidelines). The [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/app/src/main/res/layout/card_picker_item.xml#L19-L25) provides an example of the button adhering to branding guidelines. > As [recommended](https://developers.google.com/pay/issuers/apis/push-provisioning/android/faq#implementation_questions) by Google, don’t require your users to install the Google Pay app, or check its existence programmatically. The app is only a frontend and you don’t need it for Google Pay to work. Users can manage their cards from within their Google settings in the “Settings” app. Google requires that the **Add to Google Pay** button only displays when a card doesn’t already exist on the user’s device, and that users with cards pending verification complete the final guided activation process. Use Google’s [list of checkpoints](https://developers.google.com/pay/issuers/apis/push-provisioning/android/test-cases) to help you verify that your implementation is correct. To check the status of your users’ cards, use [listTokens()](https://developers.google.com/pay/issuers/apis/push-provisioning/android/reading-wallet#listtokens) to retrieve a list of all of your cards already present on the device. Compare the value of `getFpanLastFour()` on each returned object to Stripe’s [last4](https://docs.stripe.com/api/issuing/cards/object.md#issuing_card_object-last4)) property of the [Issued Card object](https://docs.stripe.com/api/issuing/cards/object.md) for the card you want to add. Discard all non-matching objects from the response list. - If the resulting list is empty, it means that the card you intend to add isn’t present on the device yet. You can proceed with displaying the button as described below. - If the resulting list contains a `TokenInfo` object, check its [TokenState](https://developers.google.com/pay/issuers/apis/push-provisioning/android/enumerated-values#token_status) by invoking `getTokenState()`. - If the status is `TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION`, your user has already attempted to manually add the given card to their device. Display the **Add to Google Pay** button, but help them to recover from this situation by wiring the `onActivityResult` listener to the `tokenize()` method as [outlined in Google’s documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/wallet-operations#resolving_yellow_path). - If the status is anything else, the card is already present on the device. **Do not display a Google Pay button.** Make sure to provide your application ID to Stripe before starting internal testing. Setup can take more than a week, and the consequences of an incomplete setup include receiving inconsistent responses to these two methods. The result of `listTokens()` **only contains cards added after** Stripe completes the setup. When a user taps the button, launch Stripe’s `PushProvisioningActivity` using the `PushProvisioningActivityStarter`. ```java new PushProvisioningActivityStarter( this, // The Activity or Fragment you are initiating the push provisioning from new PushProvisioningActivityStarter.Args( "Stripe Card", // The name that will appear on the push provisioning UI ephemeralKeyProvider, // Your instance of EphemeralKeyProvider false // If you want to enable logs or not )).startForResult(); ``` For more context, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/app/src/main/java/com/stripe/android/pushprovisioning/MainActivity.kt#L119-L124) launches `PushProvisioningActivity`. This prepares the push provisioning and launches the UI to add the card to the wallet. Implement the callback in your `onActivityResult`. ```java protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (requestCode == PushProvisioningActivityStarter.REQUEST_CODE) { if (resultCode == PushProvisioningActivity.RESULT_OK) { PushProvisioningActivityStarter.Result success = PushProvisioningActivityStarter.Result.fromIntent(data); } else if (resultCode == PushProvisioningActivity.RESULT_ERROR) { PushProvisioningActivityStarter.Error error = PushProvisioningActivityStarter.Error.fromIntent(data); } } } ``` For more context, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/app/src/main/java/com/stripe/android/pushprovisioning/MainActivity.kt#L132-L167) implements `onActivityResult`. If the provisioning was successful, you’ll receive a `PushProvisioningActivityStarter.Result` containing a `cardTokenId` which is Google’s ID for the card in the active wallet. You can use the rest of the wallet functions with this ID. If the provisioning encountered an error, a `PushProvisioningActivityStarter.Error` will be returned with a `code` and a `message`. The `message` is a developer-friendly text explaining the error. The `code` can have the following values: | Enum | Meaning | | ------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | **USER\_CANCELED** | The user canceled the provisioning. | | **CARD\_CANCELED** | The card has been canceled or is lost or stolen and can’t be provisioned. | | **EPHEMERAL\_KEY\_ERROR** | There was an error retrieving the ephemeral key. | | **TAP\_AND\_PAY\_UNAVAILABLE** | The TapAndPay library can’t be used, most likely because the app isn’t added to an allowlist. | | **NO\_STABLE\_HARDWARE\_ID** | This can happen in the development emulator. The app can’t retrieve the stable hardware ID. | | **NO\_ACTIVE\_WALLET\_FOUND** | No active wallet available. Note that emulators generally don’t have Google Pay. | | **PUSH\_PROVISIONING\_ENCRYPTED\_PAYLOAD\_ERROR** | There was an error contacting Stripe’s servers to get the encrypted payload for push provisioning. | | **UNKNOWN\_ERROR** | An unexpected error occurred. The `message` will have additional information. | ## Update your backend [Server-side] The push provisioning implementation exposes methods that expect you to communicate with your own backend to create a Stripe Ephemeral Key and return a JSON of it to your app. This key is a short-lived API credential that you can use to retrieve the encrypted card details for a single instance of a card object. To make sure that the object returned by the Stripe API is compatible with the version of the iOS or Android SDK you’re using, the Stripe SDK lets you know what API version it prefers. You must explicitly pass this API version to our API when creating the key. #### curl ```bash curl https://api.stripe.com/v1/ephemeral_keys \ -u <>: \ -d "issuing_card"="{{ISSUING_CARD_ID}}" \ -H "Stripe-Version: {{API_VERSION}}" ``` #### Ruby ```ruby # ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for # push provisioning. key = Stripe::EphemeralKey.create( {issuing_card: '{{ISSUING_CARD_ID}}'}, {stripe_version: '{{API_VERSION}}'} ) return key.to_json ``` #### Python ```python # ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for # push provisioning. key = stripe.EphemeralKey.create( issuing_card='{{ISSUING_CARD_ID}}', stripe_version='{{API_VERSION}}', ) return jsonify(key) ``` #### PHP ```php // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. $key = \Stripe\EphemeralKey::create( ['issuing_card' => '{{ISSUING_CARD_ID}}'], ['stripe_version' => '{{API_VERSION}}'] ); return json_encode($key); ``` #### Node.js ```javascript // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. let key = await stripe.ephemeralKeys.create( {issuing_card: '{{ISSUING_CARD_ID}}'}, {apiVersion: '{{API_VERSION}}'} ); res.json(key); ``` #### Java ```java // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. RequestOptions requestOptions = (new RequestOptions.RequestOptionsBuilder()) .setStripeVersion("{{API_VERSION}}") .build(); Map options = new HashMap(); options.put("issuing_card", "{{ISSUING_CARD_ID}}"); EphemeralKey key = EphemeralKey.create(options, requestOptions); return key.getRawJson(); ``` #### Go ```go // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. params := &stripe.EphemeralKeyParams{ IssuingCard: stripe.String("{{ISSUING_CARD_ID}}"), StripeVersion: stripe.String("{{API_VERSION}}"), } key, err := ephemeralkey.New(params) return key.RawJSON ``` #### .NET ```dotnet // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. var options = new EphemeralKeyCreateOptions { IssuingCard = "{{ISSUING_CARD_ID}}", StripeVersion = "{{API_VERSION}}" }; var service = new EphemeralKeyService(); service.Create(options); return key.RawJson; ``` ```json { "id": "ephkey_1G4V6eEEs6YsaMZ2P1diLWdj", "object": "ephemeral_key", "associated_objects": [ { "id": "ic_1GWQp6EESaYspYZ9uSEZOcq9", "type": "issuing.card" } ], "created": 1586556828, "expires": 1586560428, "livemode": false, "secret": "ek_test_YWNjdF8xRmdlTjZFRHelWWxwWVo5LEtLWFk0amJ2N0JOa0htU1JzEZkd2RpYkpJdnM_00z2ftxCGG" } ``` For more context, see how the [sample backend](https://github.com/stripe-samples/push-provisioning-samples/blob/main/server/ruby/README.md) creates a [Stripe Ephemeral Key](https://github.com/stripe-samples/push-provisioning-samples/blob/main/server/ruby/server.rb#L68-L88). ## Testing All testing must be done in live mode, with live Issuing cards, and on physical devices. To build the sample app, follow the steps in the [readme](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/README.md). You don’t need to build the app to follow the instructions above. # React Native > This is a React Native for when platform is react-native. View the full page at https://docs.stripe.com/issuing/cards/digital-wallets?platform=react-native. ![A black UI button that says Add to Apple Wallet. There is an Apple Wallet logo image to the left of the text. It is a grey wallet with blue, yellow, green, and red cards stacked slightly offset.](https://b.stripecdn.com/docs-statics-srv/assets/add_to_apple_wallet.fe8cd234760a7478e34f5e91d22677bb.png) ![A black UI button that says Add to Google Wallet. There is a Google Wallet logo image to the left of the text.](https://b.stripecdn.com/docs-statics-srv/assets/add_to_google_pay_black.2df6c169bbc605123ec73d37dc73a86e.png) ## Request access > You must get accesss to [manual provisioning](https://docs.stripe.com/issuing/cards/digital-wallets.md?platform=android#manual-provisioning) before you can request push provisioning. ### Requesting access for iOS Push provisioning requires a special entitlement from Apple called `com.apple.developer.payment-pass-provisioning`. You can request it by emailing [support-issuing@stripe.com](mailto:support-issuing@stripe.com). In your email, include your: - **Card network**: Visa or MasterCard. - **Card name**: The name of the card displayed in the wallet. - **App name**: Your app’s name. - **Developer team ID**: Found in your Apple Developer account settings under [membership](https://developer.apple.com/account/#/membership). - **ADAM ID**: Your app’s unique numeric ID. Found in [App Store Connect](https://appstoreconnect.apple.com), or in the App Store link to your app (for example, `https://apps.apple.com/app/id123456789`). - **Bundle ID**: Your app’s bundle identifier, also found in App Store Connect (for example, `com.example.yourapp`). ### Requesting access for Android Stripe provides an SDK wrapper around a private Google library for push provisioning. To distribute your app on the Google Pay Store with push provisioning you need to request access to this library: - [Request access to Google Pay](https://developers.google.com/pay/issuers/requesting-access?api=true) - Download Google’s [TapAndPay private SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/releases) (current compatible version is [17.1.2](https://developers.google.com/static/pay/issuers/apis/push-provisioning/android/downloads/tapandpay_sdk.m2repo_2021-07-19_v17.1.2.zip)) - [Request access to the push provisioning API](https://support.google.com/faqs/contact/pp_api_allowlist) for your app. You will need to provide your [application ID](https://developer.android.com/studio/build/application-id) to be added to Google’s allowlist. Details on this process are available in Google’s [documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/allowlist). - Provide the same application ID, your app name, card network, and card name to [support-issuing@stripe.com](mailto:support-issuing@stripe.com). ## Setup your app [Client-side] The [React Native SDK](https://github.com/stripe/stripe-react-native) is open source and fully documented. Internally, it uses the [native iOS](https://github.com/stripe/stripe-ios) and [Android](https://github.com/stripe/stripe-android) SDKs. To install Stripe’s React Native SDK, run one of the following commands in your project’s directory (depending on which package manager you use): #### yarn ```bash yarn add @stripe/stripe-react-native ``` #### npm ```bash npm install @stripe/stripe-react-native ``` Next, install some other necessary dependencies: - For iOS, go to the **ios** directory and run `pod install` to ensure that you also install the required native dependencies. - For Android, there are no more dependencies to install. > We recommend following the [official TypeScript guide](https://reactnative.dev/docs/typescript#adding-typescript-to-an-existing-project) to add TypeScript support. ### Stripe initialization To initialize Stripe in your React Native app, either wrap your payment screen with the `StripeProvider` component, or use the `initStripe` initialization method. Only the API [publishable key](https://docs.stripe.com/keys.md#obtain-api-keys) in `publishableKey` is required. The following example shows how to initialize Stripe using the `StripeProvider` component. ```jsx import { useState, useEffect } from 'react'; import { StripeProvider } from '@stripe/stripe-react-native'; function App() { const [publishableKey, setPublishableKey] = useState(''); const fetchPublishableKey = async () => { const key = await fetchKey(); // fetch key from your server here setPublishableKey(key); }; useEffect(() => { fetchPublishableKey(); }, []); return ( {/* Your app code here */} ); } ``` > Use your API [test keys](https://docs.stripe.com/keys.md#obtain-api-keys) while you test and develop, and your [live mode](https://docs.stripe.com/keys.md#test-live-modes) keys when you publish your app. ### Android-specific setup To enable push provisioning on Android, after you receive access to the TapAndPay SDK (see above), you need to [include it in your native Android project](https://developers.google.com/pay/issuers/apis/push-provisioning/android/setup). Then, you need to import Stripe’s native Android push provisioning library by adding the following to your `android/app/build.gradle` file: #### Groovy ```groovy dependencies { // ...implementation 'com.stripe:stripe-android-issuing-push-provisioning:1.1.0' } ``` #### Kotlin ```kotlin dependencies { // ...implementation("com.stripe:stripe-android-issuing-push-provisioning:1.1.0") } ``` ### iOS-specific setup To enable push provisioning on iOS, after Stripe confirms the entitlement has been granted, you need to [add the capability to your provisioning profile on app store connect](https://developer.apple.com/account/resources/profiles/list). Then, you need to add the new entitlement to your `ios/app.config.js` file: ``` "entitlements": { "com.apple.developer.payment-pass-provisioning": true } ``` ## Update your backend [Server-side] The push provisioning implementation exposes methods that expect you to communicate with your own backend to create a Stripe Ephemeral Key and return a JSON of it to your app. This key is a short-lived API credential that you can use to retrieve the encrypted card details for a single instance of a card object. To make sure that the object returned by the Stripe API is compatible with the version of the SDK you’re using, you must explicitly pass the API version exported by the React Native SDK to our API when creating the key. #### curl ```bash curl https://api.stripe.com/v1/ephemeral_keys \ -u <>: \ -d "issuing_card"="{{ISSUING_CARD_ID}}" \ -H "Stripe-Version: {{API_VERSION}}" ``` #### Ruby ```ruby # ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for # push provisioning. key = Stripe::EphemeralKey.create( {issuing_card: '{{ISSUING_CARD_ID}}'}, {stripe_version: '{{API_VERSION}}'} ) return key.to_json ``` #### Python ```python # ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for # push provisioning. key = stripe.EphemeralKey.create( issuing_card='{{ISSUING_CARD_ID}}', stripe_version='{{API_VERSION}}', ) return jsonify(key) ``` #### PHP ```php // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. $key = \Stripe\EphemeralKey::create( ['issuing_card' => '{{ISSUING_CARD_ID}}'], ['stripe_version' => '{{API_VERSION}}'] ); return json_encode($key); ``` #### Node.js ```javascript // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. let key = await stripe.ephemeralKeys.create( {issuing_card: '{{ISSUING_CARD_ID}}'}, {apiVersion: '{{API_VERSION}}'} ); res.json(key); ``` #### Java ```java // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. RequestOptions requestOptions = (new RequestOptions.RequestOptionsBuilder()) .setStripeVersion("{{API_VERSION}}") .build(); Map options = new HashMap(); options.put("issuing_card", "{{ISSUING_CARD_ID}}"); EphemeralKey key = EphemeralKey.create(options, requestOptions); return key.getRawJson(); ``` #### Go ```go // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. params := &stripe.EphemeralKeyParams{ IssuingCard: stripe.String("{{ISSUING_CARD_ID}}"), StripeVersion: stripe.String("{{API_VERSION}}"), } key, err := ephemeralkey.New(params) return key.RawJSON ``` #### .NET ```dotnet // ISSUING_CARD_ID is the ID of the Issuing Card you'd like to use for // push provisioning. var options = new EphemeralKeyCreateOptions { IssuingCard = "{{ISSUING_CARD_ID}}", StripeVersion = "{{API_VERSION}}" }; var service = new EphemeralKeyService(); service.Create(options); return key.RawJson; ``` ```json { "id": "ephkey_1G4V6eEEs6YsaMZ2P1diLWdj", "object": "ephemeral_key", "associated_objects": [ { "id": "ic_1GWQp6EESaYspYZ9uSEZOcq9", "type": "issuing.card" } ], "created": 1586556828, "expires": 1586560428, "livemode": false, "secret": "ek_test_YWNjdF8xRmdlTjZFRHelWWxwWVo5LEtLWFk0amJ2N0JOa0htU1JzEZkd2RpYkpJdnM_00z2ftxCGG" } ``` You should also create an endpoint to retrieve issuing card details that you must pass to the `` component: ```curl curl https://api.stripe.com/v1/issuing/cards/ISSUING_CARD_ID \ -u "<>:" ``` ```cli stripe issuing cards retrieve ISSUING_CARD_ID ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") card = client.v1.issuing.cards.retrieve('ISSUING_CARD_ID') ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. card = client.v1.issuing.cards.retrieve("ISSUING_CARD_ID") ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $card = $stripe->issuing->cards->retrieve('ISSUING_CARD_ID', []); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CardRetrieveParams params = CardRetrieveParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Card card = client.v1().issuing().cards().retrieve("ISSUING_CARD_ID", params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const card = await stripe.issuing.cards.retrieve('ISSUING_CARD_ID'); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.IssuingCardRetrieveParams{} result, err := sc.V1IssuingCards.Retrieve(context.TODO(), "ISSUING_CARD_ID", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.Issuing.Cards; Stripe.Issuing.Card card = service.Get("ISSUING_CARD_ID"); ``` ## Update your app [Client-side] First, determine if the device is eligible to use push provisioning by checking that the value of `wallets.apple_pay.eligible` in the issued card (retrieved from the second endpoint you created above in step 3) is `true`. If it is, save the card details to use later in our component, and proceed. If `wallets.apple_pay.eligible` is `false`, don’t show the `` on iOS, or App Review might reject your app. The same applies to `wallets.google_pay.eligible` for Android. ```javascript import React, {useEffect, useState} from 'react'; import {Constants} from '@stripe/stripe-react-native'; import {View} from 'react-native'; export default function MyScreen() { const [key, setKey] = useState(null);const [card, setCard] = useState(null); useEffect(() => { fetchEphemeralKey();fetchIssuingCard(); }, []); const fetchIssuingCard = async () => { const response = await fetch(`${API_URL}/issuing-card`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ ISSUING_CARD_ID: '{{ISSUING_CARD_ID}}', }), }); const card = await response.json(); if (!card.wallets.apple_pay.eligible) { // Do not show component on iOS. See card.wallets.apple_pay.ineligible_reason for details } else if (!card.wallets.google_pay.eligible) { // Do not show component on Android. See card.wallets.google_pay.ineligible_reason for details } else { setCard(card); } }; const fetchEphemeralKey = async () => { // See above }; return ; } ``` Next, fetch your ephemeral key from the first endpoint you created in Step 3 above, and save it. ```javascript import React, {useEffect, useState} from 'react'; import {Constants} from '@stripe/stripe-react-native'; import {View} from 'react-native'; export default function MyScreen() { const [key, setKey] = useState(null); useEffect(() => { fetchEphemeralKey(); }, []); const fetchEphemeralKey = async () => { const response = await fetch(`${API_URL}/ephemeral-key`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ ISSUING_CARD_ID: '{{ISSUING_CARD_ID}}', API_VERSION: Constants.API_VERSIONS.ISSUING, }), }); const myKey = await response.json(); setKey(myKey); }; return ; } ``` You don’t need any more server communication. Next, you must determine if the card *can* be added to the wallet. You can check for this with the `canAddCardToWallet` method, which returns an object containing a boolean field `canAddCard`. If `canAddCard` is `false`, don’t render the `AddToWalletButton`, otherwise your app might be rejected by Apple. On Android, the card might be in the wallet already, but stuck in a bad state. You can add logic to handle this case by checking for a `token` in the `details` object returned from `canAddCardToWallet`. If that response is non-null, and the `token.status` is `"TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION"`, pass that `token` into ``'s props. ```javascript import React, {useEffect, useState} from 'react'; import {Constants, canAddCardToWallet, GooglePayCardToken} from '@stripe/stripe-react-native'; import {View} from 'react-native'; export default function MyScreen() { const [key, setKey] = useState(null); const [card, setCard] = useState(null);const [showAddToWalletButton, setShowAddToWalletButton] = useState(false); const [androidCardToken, setAndroidCardToken] = useState(null); useEffect(() => { fetchEphemeralKey(); fetchIssuingCard(); }, []); const checkIfCanAddCard = async () => { const { canAddCard, details, error } = await canAddCardToWallet({ primaryAccountIdentifier: card?.wallets?.primary_account_identifier, cardLastFour: card.last4, hasPairedAppleWatch: // Pass a boolean indicating whether or not the device has a paired Apple Watch. iOS only. }); if (error) { Alert.alert(error.code, error.message); } else { setShowAddToWalletButton(canAddCard); if (details?.token?.status === 'TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION') { setAndroidCardToken(details.token); } } }; const fetchIssuingCard = async () => { // See aboveawait checkIfCanAddCard(); }; const fetchEphemeralKey = async () => { // See above }; return ; } ``` Now we have all the information we need to show the button: ```javascript import React, {useEffect, useState} from 'react'; import { Constants, canAddCardToWallet, AddToWalletButton, GooglePayCardToken, } from '@stripe/stripe-react-native'; import {View, Image, Alert, StyleSheet} from 'react-native'; import AddToGooglePayPNG from '../assets/Add-to-Google-Pay-Button-dark-no-shadow.png'; export default function MyScreen() { const [key, setKey] = useState(null); const [card, setCard] = useState(null); const [showAddToWalletButton, setShowAddToWalletButton] = useState(false); const [androidCardToken, setAndroidCardToken] = useState(null); useEffect(() => { fetchEphemeralKey(); fetchIssuingCard(); }, []); const canAddCard = async () => { // See above }; const fetchIssuingCard = async () => { // See above }; const fetchEphemeralKey = async () => { // See above }; return ( {showAddToWalletButton && ( { Alert.alert( error ? error.code : 'Success', error ? error.message : 'Card was successfully added to the wallet.', ); }} /> )} ); } const styles = StyleSheet.create({ payButton: { // You may add custom styles to your button, but make sure it complies // with the relevant platform guidelines: // iOS : https://developer.apple.com/wallet/add-to-apple-wallet-guidelines/ // Android : https://developers.google.com/pay/issuers/apis/push-provisioning/android/branding-guidelines }, }); ``` When a user taps the button, it launches the UI to add the card to the wallet. Implement the callback in your `onComplete` prop. If the `error` field is non-null, an error occurred and the card wasn’t added to the wallet. If the `error` is null, then the card was successfully provisioned. ### Button style On iOS, the button style is determined by the `iOSButtonStyle` prop. Set this prop to: - `onLightBackground` when you show the button on top of a light or white background. - `onDarkBackground` when you show the button on top of a dark or black background. On Android, you must pass in the actual image asset to the `androidAssetSource` prop. You can download all the possible asset options [directly from Google](https://developers.google.com/static/pay/issuers/apis/push-provisioning/android/downloads/add-to-wallet-png.zip). Follow [Google’s branding guidelines](https://developers.google.com/pay/issuers/apis/push-provisioning/android/branding-guidelines#style) when implementing your button. To pass your chosen PNG to the `AddToWalletButton` component, add it to your project, import it like you would any other asset, and then resolve the source with `Image.resolveAssetSource`: ```javascript import {Image} from 'react-native'; import AddToGooglePayPNG from '../assets/Add-to-Google-Pay-Button-dark-no-shadow.png'; ... ``` ## Testing ### iOS On iOS, you can test push provisioning in development, on simulators, and with test cards as long as you pass `testEnv={true}` to the `AddToWalletButton` component. Be aware that if the `testEnv` prop is set to `true`, cards won’t actually be added to the device’s wallet. In testing environments, you don’t need the `com.apple.developer.payment-pass-provisioning` entitlement. ### Android On Android, the `testEnv` prop has no effect. All testing must be done in live mode, with live issuing cards, and on physical devices. Make sure to provide your application ID to Stripe before starting internal testing. --- # Source: https://docs.stripe.com/revenue-recognition/connect/direct-charges.md # Revenue Recognition for direct charges Learn how revenue recognition works with direct charges. ## Revenue collected with application fees With Connect, your platform can make charges directly on the connected account and take application fees in the process. To add an application fee on a [direct charge](https://docs.stripe.com/connect/direct-charges.md), pass an optional `application_fee_amount` value. Stripe recognizes the revenue immediately. In this example, the `application_fee_amount="200"` is set on the direct charge. - On January 15, you make a direct charge of 10 USD with a 2 USD application fee. - The 2 USD application fee transfers to your platform. - 8 USD is netted in the connected account. | Account | Jan | | ------- | ----- | | Revenue | +2.00 | | Cash | +2.00 | ## Contra revenue with issuing refunds To refund an application fee, pass a `refund_application_fee` value of `true` in the refund request or provide a `refund_application_fee` value of `false` to refund the application fee separately through the API. In both cases, Stripe books the refunded application fee as contra revenue. In this example, the `application_fee_amount="200"` is set on the charge. - On January 15, you make a direct charge of 10 USD with a 2 USD application fee. - The 2 USD application fee transfers to your platform. - 8 USD is netted in the connected account. - On February 21, Stripe refunds the full charge amount of 10 USD and the full application fee amount of 2 USD. | Account | Jan | Feb | | ------- | ----- | ----- | | Revenue | +2.00 | | | Cash | +2.00 | -2.00 | | Refunds | | +2.00 | --- # Source: https://docs.stripe.com/financial-connections/disconnections.md # Disconnect a Financial Connections account Use the Disconnect API to unlink customer bank accounts. Disconnect a user’s [Financial Connections Account](https://docs.stripe.com/api/financial_connections/accounts/object.md) if you no longer need data access or if your user writes into you requesting disconnection. Alternatively, your users can [disconnect their accounts themselves](https://support.stripe.com/user/how-do-i-disconnect-my-linked-financial-account). If you disconnect an account, you can’t refresh their data and access previously refreshed data. However, any associated [PaymentMethods](https://docs.stripe.com/api/payment_methods.md) remain usable. To regain access to new account data, your user needs to re-authenticate their account through the [authentication flow](https://docs.stripe.com/financial-connections/fundamentals.md#authentication-flow). ## Disconnect a Financial Connections account To disconnect an account, use the [disconnect API](https://docs.stripe.com/api/financial_connections/accounts/disconnect.md): ```curl curl -X POST https://api.stripe.com/v1/financial_connections/accounts/{{FINANCIALCONNECTIONSACCOUNT_ID}}/disconnect \ -u "<>:" ``` ```cli stripe financial_connections accounts disconnect {{FINANCIALCONNECTIONSACCOUNT_ID}} ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") account = client.v1.financial_connections.accounts.disconnect('{{FINANCIALCONNECTIONSACCOUNT_ID}}') ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. account = client.v1.financial_connections.accounts.disconnect( "{{FINANCIALCONNECTIONSACCOUNT_ID}}", ) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $account = $stripe->financialConnections->accounts->disconnect( '{{FINANCIALCONNECTIONSACCOUNT_ID}}', [] ); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); AccountDisconnectParams params = AccountDisconnectParams.builder().build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Account account = client.v1().financialConnections().accounts().disconnect( "{{FINANCIALCONNECTIONSACCOUNT_ID}}", params ); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const account = await stripe.financialConnections.accounts.disconnect( '{{FINANCIALCONNECTIONSACCOUNT_ID}}' ); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.FinancialConnectionsAccountDisconnectParams{} result, err := sc.V1FinancialConnectionsAccounts.Disconnect( context.TODO(), "{{FINANCIALCONNECTIONSACCOUNT_ID}}", params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var client = new StripeClient("<>"); var service = client.V1.FinancialConnections.Accounts; Stripe.FinancialConnections.Account account = service.Disconnect( "{{FINANCIALCONNECTIONSACCOUNT_ID}}"); ``` This request returns the account with an updated `status` to reflect the successful disconnection. ```json { "id": "fca_zbyrdjTrwcYZJZc6WBs6GPid", "object": "financial_connections.account", "account_holder": { "customer": "cus_NfjonN9919dELB", "type": "customer" }, "institution_name": "PNC Bank","status": "disconnected", // ... } ``` After account disconnection, Stripe emits a `financial_connections.account.disconnected` *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests). --- # Source: https://docs.stripe.com/payments/checkout/discounts.md # Add discounts Reduce the amount charged to a customer by discounting their subtotal with coupons and promotion codes. # Stripe-hosted page > This is a Stripe-hosted page for when payment-ui is stripe-hosted. View the full page at https://docs.stripe.com/payments/checkout/discounts?payment-ui=stripe-hosted. You can use discounts to reduce the amount charged to a customer. Coupons and promotion codes allow you to: - Apply a discount to an entire purchase subtotal - Apply a discount to specific products - Reduce the total charged by a percentage or a flat amount - Create customer-facing promotion codes on top of coupons to share directly with customers > To use coupons for discounting *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) with Checkout and Billing, see [Discounts for subscriptions](https://docs.stripe.com/billing/subscriptions/coupons.md). ## Create a coupon Coupons specify a fixed value discount. You can create customer-facing promotion codes that map to a single underlying coupon. This means that the codes `FALLPROMO` and `SPRINGPROMO` can both point to one 25% off coupon. You can create coupons in the [Dashboard](https://dashboard.stripe.com/coupons) or with the [API](https://docs.stripe.com/api.md#coupons): ```curl curl https://api.stripe.com/v1/coupons \ -u "<>:" \ -d percent_off=20 \ -d duration=once ``` ```cli stripe coupons create \ --percent-off=20 \ --duration=once ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") coupon = client.v1.coupons.create({ percent_off: 20, duration: 'once', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. coupon = client.v1.coupons.create({"percent_off": 20, "duration": "once"}) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $coupon = $stripe->coupons->create([ 'percent_off' => 20, 'duration' => 'once', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CouponCreateParams params = CouponCreateParams.builder() .setPercentOff(new BigDecimal(20)) .setDuration(CouponCreateParams.Duration.ONCE) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Coupon coupon = client.v1().coupons().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const coupon = await stripe.coupons.create({ percent_off: 20, duration: 'once', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CouponCreateParams{ PercentOff: stripe.Float64(20), Duration: stripe.String(stripe.CouponDurationOnce), } result, err := sc.V1Coupons.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CouponCreateOptions { PercentOff = 20M, Duration = "once" }; var client = new StripeClient("<>"); var service = client.V1.Coupons; Coupon coupon = service.Create(options); ``` ## Use a coupon To create a session with an applied discount, pass the [coupon ID](https://docs.stripe.com/api/coupons/object.md#coupon_object-id) in the `coupon` parameter of the [discounts](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-discounts) array. Checkout currently supports up to one coupon or promotion code. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "discounts[0][coupon]"="{{COUPON_ID}}" \ -d mode=payment \ --data-urlencode success_url="https://example.com/success" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "discounts[0][coupon]"="{{COUPON_ID}}" \ --mode=payment \ --success-url="https://example.com/success" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], discounts: [{coupon: '{{COUPON_ID}}'}], mode: 'payment', success_url: 'https://example.com/success', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "discounts": [{"coupon": "{{COUPON_ID}}"}], "mode": "payment", "success_url": "https://example.com/success", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'discounts' => [['coupon' => '{{COUPON_ID}}']], 'mode' => 'payment', 'success_url' => 'https://example.com/success', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addDiscount( SessionCreateParams.Discount.builder().setCoupon("{{COUPON_ID}}").build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setSuccessUrl("https://example.com/success") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], discounts: [ { coupon: '{{COUPON_ID}}', }, ], mode: 'payment', success_url: 'https://example.com/success', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Discounts: []*stripe.CheckoutSessionCreateDiscountParams{ &stripe.CheckoutSessionCreateDiscountParams{ Coupon: stripe.String("{{COUPON_ID}}"), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), SuccessURL: stripe.String("https://example.com/success"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Discounts = new List { new Stripe.Checkout.SessionDiscountOptions { Coupon = "{{COUPON_ID}}" }, }, Mode = "payment", SuccessUrl = "https://example.com/success", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Configure a coupon Coupons have the following parameters that you can use: - `currency` - `percent_off` or `amount_off` - `max_redemptions` - `redeem_by`, the latest date customers can apply the coupon - `applies_to`, limits the products that the coupon applies to > The coupon object adds discounts to both one-time payments and subscriptions. Some coupon object parameters, like `duration`, only apply to [subscriptions](https://docs.stripe.com/billing/subscriptions/coupons.md). ### Limit redemption usage The `max_redemptions` and `redeem_by` values apply to the coupon across every application. For example, you can restrict a coupon to the first 50 usages of it, or you can make a coupon expire by a certain date. ### Limit eligible products You can limit the products that are eligible for discounts using a coupon by adding the product IDs to the `applies_to` hash in the Coupon object. Any promotion codes that map to this coupon only apply to the list of eligible products. ### Delete a coupon You can delete coupons in the Dashboard or the API. Deleting a coupon prevents it from being applied to future transactions or customers. ## Create a promotion code Promotion codes are customer-facing codes created on top of coupons. You can also specify additional restrictions that control when a customer can apply the promotion. You can share these codes with customers who can enter them during checkout to apply a discount. To create a [promotion code](https://docs.stripe.com/api/promotion_codes.md), specify an existing `coupon` and any restrictions (for example, limiting it to a specific `customer`). If you have a specific code to give to your customer (for example, `FALL25OFF`), set the `code`. If you leave this field blank, we’ll generate a random `code` for you. The `code` is case-insensitive and unique across active promotion codes for any customer. For example: - You can create multiple customer-restricted promotion codes with the same `code`, but you can’t reuse that `code` for a promotion code redeemable by any customer. - If you create a promotion code that is redeemable by any customer, you can’t create another active promotion code with the same `code`. - You can create a promotion code with `code: NEWUSER`, inactivate it by passing `active: false`, and then create a new promotion code with `code: NEWUSER`. Promotion codes can be created in the coupons section of the [Dashboard](https://dashboard.stripe.com/coupons/create) or with the [API](https://docs.stripe.com/api.md#promotion_codes): ```curl curl https://api.stripe.com/v1/promotion_codes \ -u "<>:" \ -d coupon={{COUPON_ID}} \ -d code=VIPCODE ``` ## Use a promotion code Enable customer-redeemable promotion codes using the [allow_promotion_codes](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-allow_promotion_codes) parameter in a Checkout Session. This enables a field in Checkout to allow customers to input promotion codes. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d allow_promotion_codes=true \ --data-urlencode success_url="https://example.com/success" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --allow-promotion-codes=true \ --success-url="https://example.com/success" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price_data: { unit_amount: 2000, product_data: {name: 'T-shirt'}, currency: 'usd', }, quantity: 1, }, ], mode: 'payment', allow_promotion_codes: true, success_url: 'https://example.com/success', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [ { "price_data": { "unit_amount": 2000, "product_data": {"name": "T-shirt"}, "currency": "usd", }, "quantity": 1, }, ], "mode": "payment", "allow_promotion_codes": True, "success_url": "https://example.com/success", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price_data' => [ 'unit_amount' => 2000, 'product_data' => ['name' => 'T-shirt'], 'currency' => 'usd', ], 'quantity' => 1, ], ], 'mode' => 'payment', 'allow_promotion_codes' => true, 'success_url' => 'https://example.com/success', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setUnitAmount(2000L) .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setCurrency("usd") .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setAllowPromotionCodes(true) .setSuccessUrl("https://example.com/success") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { unit_amount: 2000, product_data: { name: 'T-shirt', }, currency: 'usd', }, quantity: 1, }, ], mode: 'payment', allow_promotion_codes: true, success_url: 'https://example.com/success', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ UnitAmount: stripe.Int64(2000), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, Currency: stripe.String(stripe.CurrencyUSD), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), AllowPromotionCodes: stripe.Bool(true), SuccessURL: stripe.String("https://example.com/success"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { UnitAmount = 2000, ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, Currency = "usd", }, Quantity = 1, }, }, Mode = "payment", AllowPromotionCodes = true, SuccessUrl = "https://example.com/success", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Configure a promotion code For each promotion code, you can customize eligible customers, redemptions, and other limits. ### Limit by customer To limit a promotion to a particular customer, specify a [customer](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-customer) when creating the promotion code. If no customer is specified, any customer can redeem the code. ### Limit by first-time order You can also limit the promotion code to first-time customers with [restrictions.first_time_transaction](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-restrictions-first_time_transaction). If the `customer` isn’t defined, or if a defined `customer` has no prior payments or non-void *invoices* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice), it’s considered a first-time transaction. > Sessions that don’t create [Customers](https://docs.stripe.com/api/customers.md) instead create [Guest Customers](https://support.stripe.com/questions/guest-customer-faq) in the Dashboard. Promotion codes limited to first-time customers are still accepted for these Sessions. ### Set a minimum amount With promotion codes, you can set a minimum transaction amount for eligible discount by configuring [minimum_amount](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-restrictions-minimum_amount) and [minimum_amount_currency](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-restrictions-minimum_amount_currency). Since promotion code restrictions are checked at redemption time, the minimum transaction amount only applies to the initial payment for a subscription. ### Customize expirations You can set an expiration date on the promotion code using [expires_at](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-expires_at). If the underlying coupon already has `redeem_by` set, then the expiration date for the promotion code can’t be later than that of the coupon. If `promotion_code[expires_at]` isn’t specified, the coupon’s `redeem_by` automatically populates `expires_at`. For example, you might have plans to support a coupon for a year, but you only want it to be redeemable for one week after a customer receives it. You can set `coupon[redeem_by]` to one year from now, and set each `promotion_code[expires_at]` to one week after it’s created. ### Limit redemptions You can limit the number of redemptions by using [max_redemptions](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-max_redemptions), which works similarly to the coupon parameter. If the underlying coupon already has `max_redemptions` set, then the `max_redemptions` for the promotion code can’t be greater than that of the coupon. For example, you might want a seasonal sale coupon to be redeemable by the first 50 customers, but the winter promotion can only use 20 of those redemptions. In this scenario, you can set `coupon[max_redemptions]: 50` and `promotion_code[max_redemptions]: 20`. ### Inactive promotions You can set whether a promotion code is currently redeemable by using the [active](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-active) parameter. However, if the underlying coupon for a promotion code becomes invalid, all of its promotion codes become permanently inactive. Similarly, if a promotion code reaches its `max_redemptions` or `expires_at`, it becomes permanently inactive. You can’t reactivate these promotion codes. ### Delete promotions You can delete promotions in the Dashboard or the API. Deleting a promotion prevents it from being applied to future transactions or customers. # Embedded form > This is a Embedded form for when payment-ui is embedded-form. View the full page at https://docs.stripe.com/payments/checkout/discounts?payment-ui=embedded-form. You can use discounts to reduce the amount charged to a customer. Coupons and promotion codes allow you to: - Apply a discount to an entire purchase subtotal - Apply a discount to specific products - Reduce the total charged by a percentage or a flat amount - Create customer-facing promotion codes on top of coupons to share directly with customers > To use coupons for discounting *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) with Checkout and Billing, see [Discounts for subscriptions](https://docs.stripe.com/billing/subscriptions/coupons.md). ## Create a coupon Coupons specify a fixed value discount. You can create customer-facing promotion codes that map to a single underlying coupon. This means that the codes `FALLPROMO` and `SPRINGPROMO` can both point to one 25% off coupon. You can create coupons in the [Dashboard](https://dashboard.stripe.com/coupons) or with the [API](https://docs.stripe.com/api.md#coupons): ```curl curl https://api.stripe.com/v1/coupons \ -u "<>:" \ -d percent_off=20 \ -d duration=once ``` ```cli stripe coupons create \ --percent-off=20 \ --duration=once ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") coupon = client.v1.coupons.create({ percent_off: 20, duration: 'once', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. coupon = client.v1.coupons.create({"percent_off": 20, "duration": "once"}) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $coupon = $stripe->coupons->create([ 'percent_off' => 20, 'duration' => 'once', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); CouponCreateParams params = CouponCreateParams.builder() .setPercentOff(new BigDecimal(20)) .setDuration(CouponCreateParams.Duration.ONCE) .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Coupon coupon = client.v1().coupons().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const coupon = await stripe.coupons.create({ percent_off: 20, duration: 'once', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CouponCreateParams{ PercentOff: stripe.Float64(20), Duration: stripe.String(stripe.CouponDurationOnce), } result, err := sc.V1Coupons.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new CouponCreateOptions { PercentOff = 20M, Duration = "once" }; var client = new StripeClient("<>"); var service = client.V1.Coupons; Coupon coupon = service.Create(options); ``` ## Use a coupon To create a session with an applied discount, pass the [coupon ID](https://docs.stripe.com/api/coupons/object.md#coupon_object-id) in the `coupon` parameter of the [discounts](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-discounts) array. Checkout currently supports up to one coupon or promotion code. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "discounts[0][coupon]"="{{COUPON_ID}}" \ -d mode=payment \ -d ui_mode=embedded \ --data-urlencode return_url="https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d "discounts[0][coupon]"="{{COUPON_ID}}" \ --mode=payment \ --ui-mode=embedded \ --return-url="https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], discounts: [{coupon: '{{COUPON_ID}}'}], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [{"price": "{{PRICE_ID}}", "quantity": 1}], "discounts": [{"coupon": "{{COUPON_ID}}"}], "mode": "payment", "ui_mode": "embedded", "return_url": "https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price' => '{{PRICE_ID}}', 'quantity' => 1, ], ], 'discounts' => [['coupon' => '{{COUPON_ID}}']], 'mode' => 'payment', 'ui_mode' => 'embedded', 'return_url' => 'https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPrice("{{PRICE_ID}}") .setQuantity(1L) .build() ) .addDiscount( SessionCreateParams.Discount.builder().setCoupon("{{COUPON_ID}}").build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setReturnUrl("https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price: '{{PRICE_ID}}', quantity: 1, }, ], discounts: [ { coupon: '{{COUPON_ID}}', }, ], mode: 'payment', ui_mode: 'embedded', return_url: 'https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ Price: stripe.String("{{PRICE_ID}}"), Quantity: stripe.Int64(1), }, }, Discounts: []*stripe.CheckoutSessionCreateDiscountParams{ &stripe.CheckoutSessionCreateDiscountParams{ Coupon: stripe.String("{{COUPON_ID}}"), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), ReturnURL: stripe.String("https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { Price = "{{PRICE_ID}}", Quantity = 1, }, }, Discounts = new List { new Stripe.Checkout.SessionDiscountOptions { Coupon = "{{COUPON_ID}}" }, }, Mode = "payment", UiMode = "embedded", ReturnUrl = "https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Configure a coupon Coupons have the following parameters that you can use: - `currency` - `percent_off` or `amount_off` - `max_redemptions` - `redeem_by`, the latest date customers can apply the coupon - `applies_to`, limits the products that the coupon applies to > The coupon object adds discounts to both one-time payments and subscriptions. Some coupon object parameters, like `duration`, only apply to [subscriptions](https://docs.stripe.com/billing/subscriptions/coupons.md). ### Limit redemption usage The `max_redemptions` and `redeem_by` values apply to the coupon across every application. For example, you can restrict a coupon to the first 50 usages of it, or you can make a coupon expire by a certain date. ### Limit eligible products You can limit the products that are eligible for discounts using a coupon by adding the product IDs to the `applies_to` hash in the Coupon object. Any promotion codes that map to this coupon only apply to the list of eligible products. ### Delete a coupon You can delete coupons in the Dashboard or the API. Deleting a coupon prevents it from being applied to future transactions or customers. ## Create a promotion code Promotion codes are customer-facing codes created on top of coupons. You can also specify additional restrictions that control when a customer can apply the promotion. You can share these codes with customers who can enter them during checkout to apply a discount. To create a [promotion code](https://docs.stripe.com/api/promotion_codes.md), specify an existing `coupon` and any restrictions (for example, limiting it to a specific `customer`). If you have a specific code to give to your customer (for example, `FALL25OFF`), set the `code`. If you leave this field blank, we’ll generate a random `code` for you. The `code` is case-insensitive and unique across active promotion codes for any customer. For example: - You can create multiple customer-restricted promotion codes with the same `code`, but you can’t reuse that `code` for a promotion code redeemable by any customer. - If you create a promotion code that is redeemable by any customer, you can’t create another active promotion code with the same `code`. - You can create a promotion code with `code: NEWUSER`, inactivate it by passing `active: false`, and then create a new promotion code with `code: NEWUSER`. Promotion codes can be created in the coupons section of the [Dashboard](https://dashboard.stripe.com/coupons/create) or with the [API](https://docs.stripe.com/api.md#promotion_codes): ```curl curl https://api.stripe.com/v1/promotion_codes \ -u "<>:" \ -d coupon={{COUPON_ID}} \ -d code=VIPCODE ``` ## Use a promotion code Enable customer-redeemable promotion codes using the [allow_promotion_codes](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-allow_promotion_codes) parameter in a Checkout Session. This enables a field in Checkout to allow customers to input promotion codes. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d ui_mode=embedded \ -d allow_promotion_codes=true \ --data-urlencode return_url="https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" ``` ```cli stripe checkout sessions create \ -d "line_items[0][price_data][unit_amount]"=2000 \ -d "line_items[0][price_data][product_data][name]"=T-shirt \ -d "line_items[0][price_data][currency]"=usd \ -d "line_items[0][quantity]"=1 \ --mode=payment \ --ui-mode=embedded \ --allow-promotion-codes=true \ --return-url="https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" ``` ```ruby # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = Stripe::StripeClient.new("<>") session = client.v1.checkout.sessions.create({ line_items: [ { price_data: { unit_amount: 2000, product_data: {name: 'T-shirt'}, currency: 'usd', }, quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', allow_promotion_codes: true, return_url: 'https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}', }) ``` ```python # Set your secret key. Remember to switch to your live secret key in production. # See your keys here: https://dashboard.stripe.com/apikeys client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. session = client.v1.checkout.sessions.create({ "line_items": [ { "price_data": { "unit_amount": 2000, "product_data": {"name": "T-shirt"}, "currency": "usd", }, "quantity": 1, }, ], "mode": "payment", "ui_mode": "embedded", "allow_promotion_codes": True, "return_url": "https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}", }) ``` ```php // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys $stripe = new \Stripe\StripeClient('<>'); $session = $stripe->checkout->sessions->create([ 'line_items' => [ [ 'price_data' => [ 'unit_amount' => 2000, 'product_data' => ['name' => 'T-shirt'], 'currency' => 'usd', ], 'quantity' => 1, ], ], 'mode' => 'payment', 'ui_mode' => 'embedded', 'allow_promotion_codes' => true, 'return_url' => 'https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}', ]); ``` ```java // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys StripeClient client = new StripeClient("<>"); SessionCreateParams params = SessionCreateParams.builder() .addLineItem( SessionCreateParams.LineItem.builder() .setPriceData( SessionCreateParams.LineItem.PriceData.builder() .setUnitAmount(2000L) .setProductData( SessionCreateParams.LineItem.PriceData.ProductData.builder() .setName("T-shirt") .build() ) .setCurrency("usd") .build() ) .setQuantity(1L) .build() ) .setMode(SessionCreateParams.Mode.PAYMENT) .setUiMode(SessionCreateParams.UiMode.EMBEDDED) .setAllowPromotionCodes(true) .setReturnUrl("https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}") .build(); // For SDK versions 29.4.0 or lower, remove '.v1()' from the following line. Session session = client.v1().checkout().sessions().create(params); ``` ```node // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys const stripe = require('stripe')('<>'); const session = await stripe.checkout.sessions.create({ line_items: [ { price_data: { unit_amount: 2000, product_data: { name: 'T-shirt', }, currency: 'usd', }, quantity: 1, }, ], mode: 'payment', ui_mode: 'embedded', allow_promotion_codes: true, return_url: 'https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}', }); ``` ```go // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys sc := stripe.NewClient("<>") params := &stripe.CheckoutSessionCreateParams{ LineItems: []*stripe.CheckoutSessionCreateLineItemParams{ &stripe.CheckoutSessionCreateLineItemParams{ PriceData: &stripe.CheckoutSessionCreateLineItemPriceDataParams{ UnitAmount: stripe.Int64(2000), ProductData: &stripe.CheckoutSessionCreateLineItemPriceDataProductDataParams{ Name: stripe.String("T-shirt"), }, Currency: stripe.String(stripe.CurrencyUSD), }, Quantity: stripe.Int64(1), }, }, Mode: stripe.String(stripe.CheckoutSessionModePayment), UIMode: stripe.String(stripe.CheckoutSessionUIModeEmbedded), AllowPromotionCodes: stripe.Bool(true), ReturnURL: stripe.String("https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}"), } result, err := sc.V1CheckoutSessions.Create(context.TODO(), params) ``` ```dotnet // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys var options = new Stripe.Checkout.SessionCreateOptions { LineItems = new List { new Stripe.Checkout.SessionLineItemOptions { PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions { UnitAmount = 2000, ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions { Name = "T-shirt", }, Currency = "usd", }, Quantity = 1, }, }, Mode = "payment", UiMode = "embedded", AllowPromotionCodes = true, ReturnUrl = "https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}", }; var client = new StripeClient("<>"); var service = client.V1.Checkout.Sessions; Stripe.Checkout.Session session = service.Create(options); ``` ## Configure a promotion code For each promotion code, you can customize eligible customers, redemptions, and other limits. ### Limit by customer To limit a promotion to a particular customer, specify a [customer](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-customer) when creating the promotion code. If no customer is specified, any customer can redeem the code. ### Limit by first-time order You can also limit the promotion code to first-time customers with [restrictions.first_time_transaction](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-restrictions-first_time_transaction). If the `customer` isn’t defined, or if a defined `customer` has no prior payments or non-void *invoices* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice), it’s considered a first-time transaction. > Sessions that don’t create [Customers](https://docs.stripe.com/api/customers.md) instead create [Guest Customers](https://support.stripe.com/questions/guest-customer-faq) in the Dashboard. Promotion codes limited to first-time customers are still accepted for these Sessions. ### Set a minimum amount With promotion codes, you can set a minimum transaction amount for eligible discount by configuring [minimum_amount](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-restrictions-minimum_amount) and [minimum_amount_currency](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-restrictions-minimum_amount_currency). Since promotion code restrictions are checked at redemption time, the minimum transaction amount only applies to the initial payment for a subscription. ### Customize expirations You can set an expiration date on the promotion code using [expires_at](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-expires_at). If the underlying coupon already has `redeem_by` set, then the expiration date for the promotion code can’t be later than that of the coupon. If `promotion_code[expires_at]` isn’t specified, the coupon’s `redeem_by` automatically populates `expires_at`. For example, you might have plans to support a coupon for a year, but you only want it to be redeemable for one week after a customer receives it. You can set `coupon[redeem_by]` to one year from now, and set each `promotion_code[expires_at]` to one week after it’s created. ### Limit redemptions You can limit the number of redemptions by using [max_redemptions](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-max_redemptions), which works similarly to the coupon parameter. If the underlying coupon already has `max_redemptions` set, then the `max_redemptions` for the promotion code can’t be greater than that of the coupon. For example, you might want a seasonal sale coupon to be redeemable by the first 50 customers, but the winter promotion can only use 20 of those redemptions. In this scenario, you can set `coupon[max_redemptions]: 50` and `promotion_code[max_redemptions]: 20`. ### Inactive promotions You can set whether a promotion code is currently redeemable by using the [active](https://docs.stripe.com/api/promotion_codes/create.md#create_promotion_code-active) parameter. However, if the underlying coupon for a promotion code becomes invalid, all of its promotion codes become permanently inactive. Similarly, if a promotion code reaches its `max_redemptions` or `expires_at`, it becomes permanently inactive. You can’t reactivate these promotion codes. ### Delete promotions You can delete promotions in the Dashboard or the API. Deleting a promotion prevents it from being applied to future transactions or customers. --- # Source: https://docs.stripe.com/connect/disputes.md # Disputes on Connect platforms Learn about the dispute responsibilities on Connect platforms. You can view all disputes filed against your platform and connected accounts in your Dashboard. When one of your connected accounts receives a dispute against a payment, the [charge type](https://docs.stripe.com/connect/charges.md#types) and negative balance responsibility determine: - Whether you or your connected account responds to that dispute to accept or challenge it. - Which account Stripe debits for the chargeback and fees. This guide describes how Stripe processes disputes for each charge type and how you can handle them. ## Direct charges For connected accounts that use [direct charges](https://docs.stripe.com/connect/direct-charges.md) and where your platform isn’t liable for negative balances (including Standard accounts), those accounts handle their own disputes. The disputed funds and dispute fees are taken from their balance, not the platform’s. For connected accounts where your platform is *liable for negative balances* (The responsibility for managing risk and recovering negative balances on connected accounts. Stripe or the Connect platform can be liable for negative balances on connected accounts) (including Custom and Express accounts), you’re ultimately responsible for any disputes involving those accounts. For direct payments on connected accounts where your platform is liable for negative balances, Stripe debits disputed amounts and fees from the connected account’s balance. However, your platform is ultimately liable. If Stripe can’t debit the disputed amount and fee from the connected account, Stripe debits it from your platform account. ## Destination and separate charges and transfers For [destination charges](https://docs.stripe.com/connect/destination-charges.md) and [separate charges and transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md), with or without `on_behalf_of`, Stripe debits dispute amounts and fees from your platform account. We recommend setting up [a webhook](https://docs.stripe.com/webhooks.md) to listen to [dispute created events](https://docs.stripe.com/api/events/types.md#event_types-charge.dispute.created). When that happens, you can attempt to recover funds from the connected account by reversing the transfer through the [Dashboard](https://dashboard.stripe.com/test/transfers) or by [creating a transfer reversal](https://docs.stripe.com/api/transfer_reversals/create.md). If the connected account has a negative balance, Stripe attempts to [debit its external account](https://docs.stripe.com/connect/account-balances.md#automatically-debit-connected-accounts) if `debit_negative_balances` is set to `true`. If you challenge the dispute and win, you can transfer the funds that you previously reversed back to the connected account. If your platform has an insufficient balance, the transfer fails. Prevent insufficient balance errors by [adding funds to your Stripe balance](https://docs.stripe.com/get-started/account/add-funds.md). > Retransferring a previous reversal is subject to [cross-border transfer restrictions](https://docs.stripe.com/connect/account-capabilities.md#transfers-cross-border), meaning you might have no means to repay your connected account. Instead, wait to recover disputed cross-border payment transfers for destination charges with `on_behalf_of` until after a dispute is lost. To automate dispute management and handle chargebacks, browse [Fraud Stripe Apps](https://marketplace.stripe.com/categories/fraud) on the App Marketplace. ## Provide Connect embedded components to allow your connected accounts to respond to disputes Your connected accounts can use [Connect embedded components](https://docs.stripe.com/connect/get-started-connect-embedded-components.md) to manage disputes from within your site. The following components support dispute management: - [Payments component](https://docs.stripe.com/connect/supported-embedded-components/payments.md): Displays all of an account’s payments and disputes. - [Disputes list component](https://docs.stripe.com/connect/supported-embedded-components/disputes-list.md): Displays all of an account’s disputes. - [Disputes for a payment component](https://docs.stripe.com/connect/supported-embedded-components/disputes-for-a-payment.md): Displays the disputes for a single specified payment. You can use it to include dispute management functionality on a page with your payments UI. Note: The following is a preview/demo component that behaves differently than live mode usage with real connected accounts. The actual component has more functionality than what might appear in this demo component. For example, for connected accounts without Stripe dashboard access (custom accounts), no user authentication is required in production. ## See also - [Respond to disputes](https://docs.stripe.com/disputes/responding.md) - [Dispute categories](https://docs.stripe.com/disputes/categories.md) - [Prevent disputes and fraud](https://docs.stripe.com/disputes/prevention.md) - [Use Radar with Connect](https://docs.stripe.com/connect/radar.md) --- # Source: https://docs.stripe.com/payments/eftpos-australia.md # eftpos Australia Learn about eftpos Australia, a common payment method in Australia. [Eftpos](https://www.eftposaustralia.com.au/) is Australia’s local debit card network. More than 90% of eftpos cards are co-branded with either Visa or Mastercard, meaning you can process these cards over either network supported by the card. Stripe processes co-branded eftpos cards over eftpos, plus either Visa or Mastercard, in accordance with [least cost routing requirements](https://support.stripe.com/questions/supporting-dual-network-debit-cards-in-australia) and depending on the [type of transaction](https://docs.stripe.com/payments/eftpos-australia.md#identify-which-network-a-payment-was-processed-on). > Eftpos-only cards (also known as “proprietary eftpos cards”) only support in-person payments and can’t be used for online transactions. #### Payment method properties - **Customer locations** Australia - **Presentment currency** AUD - **Payment confirmation** Customer-initiated - **Payment method family** Cards - **Payment method type** Debit and prepaid cards - **Recurring payments** Yes - **Payout timing** Standard payout timing applies - **Connect support** Yes - **Dispute support** Yes - **Manual capture support** No - **Refunds / Partial refunds** Yes / Yes #### Business locations Stripe accounts in the following countries can accept eftpos payments with local currency settlement. - AU #### Product support - Connect - Checkout - Payment Links - Subscriptions - Invoicing - Elements1 - Terminal2 1Express Checkout Element doesn’t support eftpos. 2Terminal integrations have [specific regional requirements](https://docs.stripe.com/terminal/payments/regional.md?integration-country=AU) to process eftpos in Australia. ## Availability Eftpos is available to any business that uses Stripe in Australia, with the following exceptions: - Massage parlors ([MCC](https://docs.stripe.com/connect/setting-mcc.md) 7297) - Financial institutions—manual cash disbursements ([MCC](https://docs.stripe.com/connect/setting-mcc.md) 6010) - Financial institutions—merchandise and services ([MCC](https://docs.stripe.com/connect/setting-mcc.md) 6012) - Non-financial institutions—foreign currency, money orders and travelers’ checks. ([MCC](https://docs.stripe.com/connect/setting-mcc.md) 6051) - Remote stored value load—merchant ([MCC](https://docs.stripe.com/connect/setting-mcc.md) 6530) - Stored value card purchase/load ([MCC](https://docs.stripe.com/connect/setting-mcc.md) 6540) - Wires, money orders ([MCC](https://docs.stripe.com/connect/setting-mcc.md) 4829) ## Integration If your integration can already [accept card payments](https://docs.stripe.com/payments/accept-a-payment.md), you can also accept eftpos without additional updates. Eftpos is the default network for payment. Unless you change the default network, you must inform your customers that whenever they use a dual-network debit card, their payments might be processed through the debit network, regardless of the logo that appears when they enter their payment information. We recommend you notify your customers based on the type of payment transaction: - For single payment transactions, display a notification to the customer before the completion of the checkout process. - For new recurring payment transactions, display a notification to the customer at the time of setup. - For existing recurring payment transactions, notify your customers in advance of future transactions. You must notify your customers about how network routing functions, and how payments processing works. You can use the suggested notification message below: Notwithstanding the payment brand logo displayed when you enter your payment information, whenever you use a dual-network debit card displaying eftpos and another payment brand, your payment (including any future recurring debit payments authorized by you) might be processed through either network. For more information, see the . We recommend that you provide further information in your Terms and Conditions or FAQs on how network routing functions and how payments processing works. For guidelines on best practices, see the Australian Payments Network [MCR Online Notification Guidelines](https://www.auspaynet.com.au/resources/cards-and-devices). ## Understand which network processes payments Stripe dynamically routes between the international scheme (Visa or Mastercard) and eftpos, depending on the type of payment, technical availability and authorization rate considerations: - If a payment requires [placing a hold on the card](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md) (in other words, if there’s a delay between authorization and capture), Stripe always routes to the international scheme. - For other types of payments, Stripe generally defaults to the eftpos network. If you require that eftpos is never the default network for any payments, please contact [support](https://support.stripe.com/contact). To identify which network a payment was processed on, inspect the [network](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card-network) field on the [Charge](https://docs.stripe.com/api/charges/object.md) object associated with a successful [Payment Intent](https://docs.stripe.com/api/payment_intents/object.md): ```javascript { "id": "ch_1Ff52K2eZvKYlo2CWe10i0s7", "object": "charge", ... "payment_method_details": { "card": { "brand": "visa", ... "network": "eftpos_au" }, "type": "card" } } ``` ## See also - [Migrating from Charges API to the Payment Intents API](https://docs.stripe.com/payments/payment-intents/migration.md) - [Available eftpos test cards](https://docs.stripe.com/testing.md#cards) --- # Source: https://docs.stripe.com/issuing/elements.md # Using Issuing Elements Learn how to display card details in your web application in a PCI-compliant way. [Stripe.js](https://docs.stripe.com/js.md) includes a browser-side JavaScript library you can use to display the sensitive data of your Issuing cards on the web in compliance with PCI requirements. The sensitive data renders inside Stripe-hosted iframes and never touches your servers. > Stripe.js collects extra data to protect our users. Learn more about how Stripe collects data for [advanced fraud detection](https://docs.stripe.com/disputes/prevention/advanced-fraud-detection.md). ## Ephemeral key authentication Stripe.js uses ephemeral keys to securely retrieve Card information from the Stripe API without publicly exposing your secret keys. You need to do some of the ephemeral key exchange on the server-side to set this up. The ephemeral key creation process begins in the browser, by creating a **nonce** using Stripe.js. A nonce is a single-use token that creates an **ephemeral key**. This nonce is sent to your server, where you exchange it for an ephemeral key by calling the Stripe API (using your secret key). Create a server-side ephemeral key, then pass it back to the browser for Stripe.js to use. ## Create a secure endpoint [Server-side] The first step to integrating with Issuing Elements is to create a secure, server-side endpoint to generate ephemeral keys for the card you want to show. Your Issuing Elements web integration calls this endpoint. Here’s how you might implement an ephemeral key creation endpoint in web applications framework across various languages: #### Node.js ```javascript // This example sets up an endpoint using the Express framework. const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.urlencoded({ extended: true })); const stripe = require('stripe')('<>'); app.post('/ephemeral-keys', async (request, response) => { const { card_id, nonce } = request.body; /* Important: Authenticate your user here! */ const ephemeralKey = await stripe.ephemeralKeys.create({ nonce: nonce, issuing_card: card_id, }, { apiVersion: '2026-01-28.clover', }); response.json({ ephemeralKeySecret: ephemeralKey.secret, }); }); ``` #### Ruby ```ruby # This example sets up an endpoint using the Sinatra framework. # Watch this video to get started: https://youtu.be/8aA9Enb8NVc require 'sinatra' require 'sinatra/json' Stripe.api_key = '<>' post '/ephemeral-keys' do # Important: Authenticate your user here! @ephemeral_key = Stripe::EphemeralKey.create({ nonce: params[:nonce], issuing_card: params[:card_id], }, { stripe_version: '2026-01-28.clover', }) json(ephemeralKeySecret: @ephemeral_key.secret) end ``` #### PHP ```php >'); $payload = @file_get_contents('php://input'); $params = json_decode($payload, true); try { // Important: Authenticate your user here! $ephemeralKey = $stripe->ephemeralKeys->create([ 'nonce' => $params['nonce'], 'issuing_card' => $params['card_id'], ], [ 'stripe_version' => '2022-08-01' ]); } catch(\UnexpectedValueException $e) { http_response_code(400); exit(); } catch(\Stripe\Exception\SignatureVerificationException $e) { // Invalid signature http_response_code(400); exit(); } http_response_code(200); echo json_encode(['ephemeralKeySecret' => $ephemeralKey->secret]); ``` #### Python ```python # This example sets up an endpoint using the Flask framework. # Watch this video to get started: https://youtu.be/7Ul1vfmsDck import stripe from flask import Flask, request, jsonify app = Flask(__name__) stripe.api_key = '<>' @app.route('/ephemeral-keys', methods=['POST']) def ephemeral_keys(): # Important: Authenticate your user here! ephemeralKey = stripe.EphemeralKey.create( nonce=request.args.get('nonce'), issuing_card=request.args.get('card_id'), stripe_version='2026-01-28.clover', ) return jsonify( ephemeralKeySecret=ephemeralKey.secret, ) ``` > #### Important > > Your endpoint is responsible for authenticating that the requesting user has permission to see the requested card’s details. Make sure your endpoint only issues ephemeral keys to users of the requested card. > You must specify the API version when creating ephemeral keys. Currently, the minimum required version is `2020-03-02`. You must also pass in an ephemeral key nonce, which you create in your web integration. ## Web API integration [Client-side] First, include Stripe.js on your page. For more information on how to set up Stripe.js, refer to [including Stripe.js.](https://docs.stripe.com/js/including) Create a `Stripe` instance and an ephemeral key nonce for the card you want to retrieve using [stripe.createEphemeralKeyNonce](https://docs.stripe.com/js/issuing/create_ephemeral_key_nonce). Use the nonce to retrieve the ephemeral key by calling the [server-side endpoint](https://docs.stripe.com/issuing/elements.md#create-secure-endpoint) that you created: ```javascript const stripe = Stripe('<>'); // Initialize Elements which you'll need later const elements = stripe.elements(); // Use Stripe.js to create a nonce const cardId = 'ic_1ITi6XKYfU8ZP6raDAXem8ql'; const nonceResult = await stripe.createEphemeralKeyNonce({ issuingCard: cardId, }); const nonce = nonceResult.nonce; // Call your ephemeral key creation endpoint to fetch the ephemeral key. // Note that the ephemeral key expires after 15 minutes. const ephemeralKeyResult = await fetch('/ephemeral-keys', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': /* Important: this endpoint must be authenticated. */ }, body: JSON.stringify({ card_id: cardId, nonce: nonce, }) }); const ephemeralKeyResponse = await ephemeralKeyResult.json(); const ephemeralKeySecret = ephemeralKeyResponse.ephemeralKeySecret; ``` ### Refresh ephemeral key every 15 minutes Ephemeral keys for Issuing Elements expire after 15 minutes. Call your backend endpoint every 15 minutes during a user session to refresh the ephemeral key and prevent stale authentication. After regenerating, use the Element’s `update({...})` method to send in a new ephemeral key and nonce. ## Display an Element [Client-side] Now that you have an ephemeral key, you can display an Issuing Element. All Elements are created with the following pattern: ```javascript const element = elements.create(elementName, options); element.mount("#my-parent-container"); ``` ### Available Issuing Elements | Element | Name | Availability | | ------------ | -------------------------- | ------------------ | | Number (PAN) | `issuingCardNumberDisplay` | Virtual cards only | | CVC | `issuingCardCvcDisplay` | Virtual cards only | | Expiry date | `issuingCardExpiryDisplay` | Any card | | PIN | `issuingCardPinDisplay` | Any card | | Copy button | `issuingCardCopyButton` | Any card | ### Usage Each element type has different options and functions. Select which element type you want to learn more about: #### Card Display Element This section applies to creating elements that display a card’s details: `issuingCardNumberDisplay`, `issuingCardCvcDisplay`, `issuingCardExpiryDisplay`, or `issuingCardPinDisplay`. ### Options | Name | Type | Usage | Required | | -------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | | `issuingCard` | `string` | The ID of your issued card (for example, `ic_abc123`) | Yes | | `nonce` | `string` | Your ephemeral key nonce | Yes | | `ephemeralKeySecret` | `string` | The `secret` component of your ephemeral key | Yes | | `style` | [Style object](https://docs.stripe.com/js/appendix/style) | Keep in mind that some variants, pseudo-classes, and properties are for input Elements and won’t apply to these Elements. An example of an input-only pseudo-class is `::placeholder`. | No | ### Example ```javascript const number = elements.create('issuingCardNumberDisplay', { issuingCard: cardId, nonce: nonce, ephemeralKeySecret: ephemeralKeySecret, style: { base: { color: '#fff', fontSize: '16px' }, }, }); number.mount('#card-number'); ``` #### Card Copy Button Element This section applies to displaying the `issuingCardCopyButton`. This element takes a `toCopy` option and renders a transparent “copy to clipboard” button that takes up the space of its parent `
`. This allows it to intercept all click events with a click handler. The click handler takes the corresponding card data specified at initialization and copies it to the clipboard. With this, you can display “copy to clipboard” buttons next to the card number, expiry, and cvc, which prevents your cardholders from manually copying card data. We restrict the copy functionality to Stripe’s PCI-compliant `