# Collect card payments Prepare your application and back end to collect card payments using Stripe Terminal. # iOS New to the Payment Intents API? Here are some helpful resources: - [The Payment Intents API](https://docs.stripe.com/payments/payment-intents.md) - [The PaymentIntent object](https://docs.stripe.com/api/payment_intents.md) - [More payment scenarios](https://docs.stripe.com/payments/more-payment-scenarios.md) Collecting payments with Stripe Terminal requires writing a payment flow in your application. Use the Stripe Terminal SDK to create and update a [PaymentIntent](https://docs.stripe.com/api.md#payment_intents), an object representing a single payment session. Designed to be robust to failures, the Terminal integration splits the payment process into several steps, each of which can be retried safely: 1. [Create a PaymentIntent](https://docs.stripe.com/terminal/payments/collect-card-payment.md#create-payment). 1. [Process the payment](https://docs.stripe.com/terminal/payments/collect-card-payment.md#process-payment). Authorization on the customer’s card takes place when the SDK processes the payment. 1. (Optional) [Capture the payment](https://docs.stripe.com/terminal/payments/collect-card-payment.md#capture-payment) ## Create a PaymentIntent [Client-side] [Server-side] The first step when collecting payments is to start the payment flow. When a customer begins checking out, your application must create a `PaymentIntent` object. This represents a new payment session on Stripe. - [createPaymentIntent (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)createPaymentIntent:completion:) You can create a `PaymentIntent` on the client or server. Use [test amounts](https://docs.stripe.com/terminal/references/testing.md#physical-test-cards) to try producing different results. An amount ending in `00` results in an approved payment. > #### Don't recreate PaymentIntents for declined cards > > Don’t recreate a PaymentIntent if a card is declined. Instead, re-use the same PaymentIntent to help [avoid double charges](https://docs.stripe.com/terminal/payments/collect-card-payment.md#avoiding-double-charges). ### Client-side Create a `PaymentIntent` from your client: #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // ... // Action for a "Checkout" button func checkoutAction() throws { let params = try PaymentIntentParametersBuilder(amount: 1000, currency: "usd").build() Terminal.shared.createPaymentIntent(params) { createResult, createError in if let error = createError { print("createPaymentIntent failed: \(error)") } else if let paymentIntent = createResult { print("createPaymentIntent succeeded") // ... } } } // ... } ``` ### Server-side You can create the `PaymentIntent` on your server if the information required to start a payment isn’t readily available in your app. The following example shows how to create a `PaymentIntent` on your server: #### curl ```bash curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -d "amount"=1000 \ -d "currency"="usd" \ -d "payment_method_types[]"="card_present" \ -d "capture_method"="manual" ``` For Terminal payments, the `payment_method_types` parameter must include `card_present`. You can control the payment flow as follows: - To fully control the payment flow for `card_present` payments, set the `capture_method` to `manual`. This allows you to add a reconciliation step before finalizing the payment. - To authorize and capture payments in one step, set the `capture_method` to `automatic`. To accept payments in Australia, you need to set `capture_method` to `automatic` or `manual_preferred`. For more details, visit our [Australia documentation](https://docs.stripe.com/terminal/payments/regional.md?integration-country=AU). To accept Interac payments in Canada, you must also include `interac_present` in `payment_method_types`. For more details, visit our [Canada documentation](https://docs.stripe.com/terminal/payments/regional.md?integration-country=CA). The `PaymentIntent` contains a [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret), a key that’s unique to the individual `PaymentIntent`. To use the client secret, you must obtain it from the `PaymentIntent` on your server and [pass it to the client side](https://docs.stripe.com/payments/payment-intents.md#passing-to-client). #### Ruby ```ruby post '/create_payment_intent' do intent = # ... Create or retrieve the PaymentIntent {client_secret: intent.client_secret}.to_json end ``` - [retrievePaymentIntent (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)retrievePaymentIntent:completion:) To retrieve a `PaymentIntent`, use the client secret to call `retrievePaymentIntent`. After you retrieve the `PaymentIntent`, use it to call `processPaymentIntent`. #### Swift ```swift func checkoutButtonAction() { // ... Fetch the client secret from your backend Terminal.shared.retrievePaymentIntent(clientSecret: clientSecret) { retrieveResult, retrieveError in if let error = retrieveError { print("retrievePaymentIntent failed: \(error)") } else if let paymentIntent = retrieveResult { print("retrievePaymentIntent succeeded: \(paymentIntent)") // ... } } } ``` ## Process the payment [Client-side] You can process a payment immediately with the card presented by a customer, or instead inspect card details before proceeding to process the payment. For most use cases, we recommend processing immediately, because it’s a simpler integration with fewer API calls. However, if you want to insert your own business logic before authorizing the card, use the two-step collect-and-confirm flow. #### Process immediately After you create a PaymentIntent, the next step is to process the payment. The reader prompts the customer to insert or tap their card and then attempts to authorize the payment. - [processPaymentIntent (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)processPaymentIntent:delegate:completion:) While processing a payment, cardholder might take a few seconds to get their card from their wallet or pose a question to the operator during payment. #### Swift ```swift // Action for a "Checkout" button func checkoutAction() throws { let params = try PaymentIntentParametersBuilder(amount: 1000, currency: "usd").build() Terminal.shared.createPaymentIntent(params) { createResult, createError in if let error = createError { print("createPaymentIntent failed: \(error)") } else if let paymentIntent = createResult { print("createPaymentIntent succeeded") self.processCancelable = Terminal.shared.processPaymentIntent(paymentIntent, collectConfig: nil, confirmConfig: nil) { processResult, processError in if let error = processError { print("processPaymentIntent failed: \(error)") } else if let processedPaymentIntent = processResult { print("processPaymentIntent succeeded") // Notify your backend to capture the PaymentIntent if let stripeId = processedPaymentIntent.stripeId { APIClient.shared.capturePaymentIntent(stripeId) { captureError in if let error = captureError { print("capturePaymentIntent failed: \(error)") } else { print("capturePaymentIntent succeeded") } } } else { print("Payment processed offline"); } } } } } } ``` ### Cancel collection #### Programmatic cancellation - [Cancelable (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCancelable.html) You can cancel processing a PaymentIntent using the `Cancelable` object returned by the iOS SDK. #### Customer-initiated cancellation - [setCustomerCancellation (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCollectPaymentIntentConfigurationBuilder.html#/c:objc\(cs\)SCPCollectPaymentIntentConfigurationBuilder\(im\)setCustomerCancellation) - [CustomerCancellation (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Enums/SCPCustomerCancellation.html) Smart readers show customers a cancel button by default. You can disable this by setting `customerCancellation` to `.disableIfAvailable`. Tapping the cancel button cancels the active transaction. #### Swift ```swift let collectConfig = try CollectPaymentIntentConfigurationBuilder() .setCustomerCancellation(.disableIfAvailable) // turn OFF the cancel button, ON by default .build() Terminal.shared.collectPaymentMethod(paymentIntent: paymentIntent, collectConfig: collectConfig) { intentWithPaymentMethod, attachError in } ``` ### Handle events - [ReaderDisplayDelegate (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Protocols/SCPReaderDisplayDelegate.html) When collecting a payment method using a reader such as the [Stripe M2](https://docs.stripe.com/terminal/readers/stripe-m2.md), without a built-in display, your app must be able to display events from the payment method collection process to users. These events help users successfully collect payments (for example, retrying a card, trying a different card, or using a different read method). When a transaction begins, the SDK passes a `ReaderInputOptions` value to your app’s reader display handler, denoting the acceptable types of input (for example, `Swipe`, `Insert`, or `Tap`). In your app’s checkout UI, prompt the user to present a card using one of these options. During the transaction, the SDK might request your app to display additional prompts (for example, `Retry Card`) to your user by passing a `ReaderDisplayMessage` value to your app’s reader display handler. Make sure your checkout UI displays these messages to the user. #### Swift ```swift // MARK: MobileReaderDelegate - only needed for Bluetooth readers, this is the delegate set during connectReader func reader(_ reader: Reader, didRequestReaderInput inputOptions: ReaderInputOptions) { readerMessageLabel.text = Terminal.stringFromReaderInputOptions(inputOptions) } func reader(_ reader: Reader, didRequestReaderDisplayMessage displayMessage: ReaderDisplayMessage) { readerMessageLabel.text = Terminal.stringFromReaderDisplayMessage(displayMessage) } ``` ### Collect payments with Tap to Pay on iPhone When your application is ready to collect a payment, the Stripe Terminal iOS SDK takes over the display to handle the collection process. After calling the [process payment](https://docs.stripe.com/terminal/payments/collect-card-payment.md#process-payment) method, your application remains running, but the iPhone displays a full-screen prompt to the cardholder, instructing them to present their card or NFC-based mobile wallet. If there’s an error reading the card, a prompt for retry displays. A successful presentation returns a success indication, and then control returns to your application. ![Tap to Pay on iPhone payment collection](https://b.stripecdn.com/docs-statics-srv/assets/ttpoi-payment-collection.50a552f2d75b8a3b92a439810cd9361d.png) Payment collection - For manual capture of payments, a successful `processPaymentIntent` call results in a `PaymentIntent` with a status of `requires_capture`. - For automatic capture of payments, the `PaymentIntent` transitions to a `succeeded` state. You must manually capture a PaymentIntent within 2 days or the authorization expires and funds are released to the customer. ### Handle failures - [ConfirmPaymentIntentError (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPConfirmPaymentIntentError.html#/c:objc\(cs\)SCPConfirmPaymentIntentError\(py\)paymentIntent) When processing a payment fails, the SDK returns an error that includes the updated `PaymentIntent` if it was declined by stripe. Your application needs to inspect the `PaymentIntent` to decide how to deal with the error. | PaymentIntent status | Meaning | Resolution | | ------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `requires_payment_method` | Payment method declined | Try collecting a different payment method by calling `processPaymentIntent` again with the same `PaymentIntent`. | | `requires_confirmation` | Temporary connectivity problem | Call `processPaymentIntent` again with the same `PaymentIntent` to retry the request. | | `PaymentIntent` is `nil` | Request to Stripe timed out, unknown `PaymentIntent` status | Retry processing the original `PaymentIntent`. Don’t create a new one, because that might result in multiple authorizations for the cardholder. | If you encounter multiple, consecutive timeouts, there might be a problem with your connectivity. Make sure that your app can communicate with the internet. ### Avoid double charges The `PaymentIntent` object enables money movement at Stripe—use a single `PaymentIntent` to represent a transaction. Re-use the same `PaymentIntent` after a card is declined (for example, if it has insufficient funds), so your customer can try again with a different card. If you edit the `PaymentIntent`, you must call `processPaymentIntent` to update the payment information on the reader. A `PaymentIntent` must be in the `requires_payment_method` state before Stripe can process it. An authorized, captured, or canceled `PaymentIntent` can’t be processed by a reader. #### Collect, inspect, and confirm After you create a PaymentIntent, the next step is to process the payment. The reader prompts the customer to insert or tap their card and then creates a PaymentMethod. ## Collect a PaymentMethod - [collectPaymentMethod (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)collectPaymentMethod:delegate:completion:) After you’ve created a `PaymentIntent`, the next step is to collect a payment method with the SDK. To collect a payment method, your app needs to be connected to a reader. The connected reader waits for a card to be presented after your app calls `collectPaymentMethod`. #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController, ReaderDisplayDelegate { // Label for displaying messages from the card reader let readerMessageLabel = UILabel(frame: .zero) var collectCancelable: Cancelable? = nil // ... // Action for a "Checkout" button func checkoutAction() throws { let params = try PaymentIntentParametersBuilder(amount: 1000, currency: "usd").build() Terminal.shared.createPaymentIntent(params) { createResult, createError in if let error = createError { print("createPaymentIntent failed: \(error)") } else if let paymentIntent = createResult { print("createPaymentIntent succeeded") self.collectCancelable = Terminal.shared.collectPaymentMethod(paymentIntent) { collectResult, collectError in if let error = collectError { print("collectPaymentMethod failed: \(error)") } else if let paymentIntent = collectResult { print("collectPaymentMethod succeeded") // ... Confirm the payment } } } } } } // MARK: MobileReaderDelegate - only needed for mobile readers, this is the delegate set during connectReader func reader(_ reader: Reader, didRequestReaderInput inputOptions: ReaderInputOptions = []) { readerMessageLabel.text = Terminal.stringFromReaderInputOptions(inputOptions) } func reader(_ reader: Reader, didRequestReaderDisplayMessage displayMessage: ReaderDisplayMessage) { readerMessageLabel.text = Terminal.stringFromReaderDisplayMessage(displayMessage) } // MARK: ReaderDisplayDelegate func terminal(_ terminal: Terminal, didRequestReaderInput inputOptions: ReaderInputOptions = []) { readerMessageLabel.text = Terminal.stringFromReaderInputOptions(inputOptions) } func terminal(_ terminal: Terminal, didRequestReaderDisplayMessage displayMessage: ReaderDisplayMessage) { readerMessageLabel.text = Terminal.stringFromReaderDisplayMessage(displayMessage) } ``` This method collects encrypted payment method data using the connected card reader, and associates the encrypted data with the local `PaymentIntent`. ### Optionally inspect payment method details - [CollectPaymentIntentConfiguration (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCollectPaymentIntentConfiguration.html) - [CardPresentDetails (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCardPresentDetails.html) For advanced use cases, you can examine the payment method details of the presented card and perform your own business logic prior to authorization. Use the `setUpdatePaymentIntent` setter in `CollectPaymentIntentConfigurationBuilder` to attach a `PaymentMethod` to the server-side `PaymentIntent`. This data is returned in the `collectPaymentMethod` response. #### Swift ```swift class PaymentViewController: UIViewController, ReaderDisplayDelegate { // ... // Action for a "Checkout" button func checkoutAction() throws { let params = try PaymentIntentParametersBuilder(amount: 1000, currency: "usd").build() Terminal.shared.createPaymentIntent(params) { createResult, createError in if let error = createError { print("createPaymentIntent failed: \(error)") } else if let paymentIntent = createResult { print("createPaymentIntent succeeded") let collectConfig = try CollectPaymentIntentConfigurationBuilder().setUpdatePaymentIntent(true).build() self.collectCancelable = Terminal.shared.collectPaymentMethod(paymentIntent: paymentIntent, collectConfig: collectConfig) { collectResult, collectError in if let error = collectError { print("collectPaymentMethod failed: \(error)") } else if let paymentIntent = collectResult { print("collectPaymentMethod succeeded") if let paymentMethod = paymentIntent.paymentMethod, let card = paymentMethod.cardPresent ?? paymentMethod.interacPresent { // ... Perform business logic on card } // ... Confirm the payment } } } } } } ``` This method attaches the collected encrypted payment method data with an update to the `PaymentIntent` object. It doesn’t require authorization until you confirm the payment. After payment method collection, you must authorize or cancel the payment within 30 seconds. If the SDK is [operating offline](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md), the `paymentMethod` field isn’t present in the `PaymentIntent` object. You can access attributes like card brand, funding, and other useful data at this point. Stripe attempts to detect whether a mobile wallet is used in a transaction as shown in the `wallet.type` attribute. However, the attribute isn’t populated if the card’s issuing bank doesn’t support reader-driven identification of a mobile wallet, so accurate detection isn’t guaranteed. After authorization and when you [process the payment](https://docs.stripe.com/terminal/payments/collect-card-payment.md#process-payment), Stripe receives up-to-date information from the networks and updates `wallet.type`. ### Cancel collection #### Programmatic cancellation - [Cancelable (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCancelable.html) You can cancel collecting a payment method using the `Cancelable` object returned by the iOS SDK. #### Customer-initiated cancellation - [setCustomerCancellation (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCollectPaymentIntentConfigurationBuilder.html#/c:objc\(cs\)SCPCollectPaymentIntentConfigurationBuilder\(im\)setCustomerCancellation) - [CustomerCancellation (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Enums/SCPCustomerCancellation.html) Smart readers show customers a cancel button by default. You can disable this by setting `customerCancellation` to `.disableIfAvailable`. Tapping the cancel button cancels the active transaction. #### Swift ```swift let collectConfig = try CollectPaymentIntentConfigurationBuilder() .setCustomerCancellation(.disableIfAvailable) // turn OFF the cancel button, ON by default .build() Terminal.shared.collectPaymentMethod(paymentIntent: paymentIntent, collectConfig: collectConfig) { intentWithPaymentMethod, attachError in } ``` ### Handle events - [ReaderDisplayDelegate (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Protocols/SCPReaderDisplayDelegate.html) When collecting a payment method using a reader such as the [Stripe M2](https://docs.stripe.com/terminal/readers/stripe-m2.md), without a built-in display, your app must be able to display events from the payment method collection process to users. These events help users successfully collect payments (for example, retrying a card, trying a different card, or using a different read method). When a transaction begins, the SDK passes a `ReaderInputOptions` value to your app’s reader display handler, denoting the acceptable types of input (for example, `Swipe`, `Insert`, or `Tap`). In your app’s checkout UI, prompt the user to present a card using one of these options. During the transaction, the SDK might request your app to display additional prompts (for example, `Retry Card`) to your user by passing a `ReaderDisplayMessage` value to your app’s reader display handler. Make sure your checkout UI displays these messages to the user. #### Swift ```swift // MARK: MobileReaderDelegate - only needed for Bluetooth readers, this is the delegate set during connectReader func reader(_ reader: Reader, didRequestReaderInput inputOptions: ReaderInputOptions) { readerMessageLabel.text = Terminal.stringFromReaderInputOptions(inputOptions) } func reader(_ reader: Reader, didRequestReaderDisplayMessage displayMessage: ReaderDisplayMessage) { readerMessageLabel.text = Terminal.stringFromReaderDisplayMessage(displayMessage) } ``` ### Collect payments with Tap to Pay on iPhone When your application is ready to collect a payment, the Stripe Terminal iOS SDK takes over the display to handle the collection process. After calling the [process payment](https://docs.stripe.com/terminal/payments/collect-card-payment.md#process-payment) method, your application remains running, but the iPhone displays a full-screen prompt to the cardholder, instructing them to present their card or NFC-based mobile wallet. If there’s an error reading the card, a prompt for retry displays. A successful presentation returns a success indication, and then control returns to your application. ![Tap to Pay on iPhone payment collection](https://b.stripecdn.com/docs-statics-srv/assets/ttpoi-payment-collection.50a552f2d75b8a3b92a439810cd9361d.png) Payment collection ## Confirm the PaymentIntent - [confirmPaymentIntent (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)confirmPaymentIntent:completion:) After successfully collecting a payment method from the customer, the next step is to confirm the payment with the SDK. When you’re ready to proceed with the payment, call `confirmPaymentIntent` with the updated `PaymentIntent` from the [previous step](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-inspect-payment-method). - For manual capture of payments, a successful `confirmPaymentIntent` call results in a `PaymentIntent` with a status of `requires_capture`. - For automatic capture of payments, the `PaymentIntent` transitions to a `succeeded` state. Always confirm PaymentIntents using the Terminal SDK on the client. Server-side confirmation bypasses critical interactions, such as PIN prompts, and might result in transaction failures. #### Swift ```swift // Action for a "Checkout" button func checkoutAction() throws { let params = try PaymentIntentParametersBuilder(amount: 1000, currency: "usd").build() Terminal.shared.createPaymentIntent(params) { createResult, createError in if let error = createError { print("createPaymentIntent failed: \(error)") } else if let paymentIntent = createResult { print("createPaymentIntent succeeded") self.collectCancelable = Terminal.shared.collectPaymentMethod(paymentIntent) { collectResult, collectError in if let error = collectError { print("collectPaymentMethod failed: \(error)") } else if let collectPaymentMethodPaymentIntent = collectResult { print("collectPaymentMethod succeeded") // ... Confirm the payment self.confirmCancelable = Terminal.shared.confirmPaymentIntent(collectPaymentMethodPaymentIntent) { confirmResult, confirmError in if let error = confirmError { print("confirmPaymentIntent failed: \(error)") } else if let confirmedPaymentIntent = confirmResult { print("confirmPaymentIntent succeeded") // Notify your backend to capture the PaymentIntent if let stripeId = confirmedPaymentIntent.stripeId { APIClient.shared.capturePaymentIntent(stripeId) { captureError in if let error = captureError { print("capture failed: \(error)") } else { print("capture succeeded") } } } else { print("Payment collected offline"); } } } } } } } ``` You must manually capture a PaymentIntent within 2 days or the authorization expires and funds are released to the customer. ### Handle failures - [ConfirmPaymentIntentError (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPConfirmPaymentIntentError.html#/c:objc\(cs\)SCPConfirmPaymentIntentError\(py\)paymentIntent) When confirming a payment fails, the SDK returns an error that includes the updated `PaymentIntent`. Your application needs to inspect the `PaymentIntent` to decide how to deal with the error. | PaymentIntent Status | Meaning | Resolution | | ------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `requires_payment_method` | Payment method declined | Try collecting a different payment method by calling `collectPaymentMethod` again with the same `PaymentIntent`. | | `requires_confirmation` | Temporary connectivity problem | Call `confirmPaymentIntent` again with the same `PaymentIntent` to retry the request. | | `PaymentIntent` is `nil` | Request to Stripe timed out, unknown `PaymentIntent` status | Retry confirming the original `PaymentIntent`. Don’t create a new one, because that might result in multiple authorizations for the cardholder. | If you encounter multiple, consecutive timeouts, there might be a problem with your connectivity. Make sure that your app can communicate with the internet. ### Avoid double charges The `PaymentIntent` object enables money movement at Stripe—use a single `PaymentIntent` to represent a transaction. Re-use the same `PaymentIntent` after a card is declined (for example, if it has insufficient funds), so your customer can try again with a different card. If you edit the `PaymentIntent`, you must call `collectPaymentMethod` to update the payment information on the reader. A `PaymentIntent` must be in the `requires_payment_method` state before Stripe can confirm it. An authorized, captured, or canceled `PaymentIntent` can’t be confirmed by a reader. ## Capture the payment [Server-side] If you defined `capture_method` as `manual` during `PaymentIntent` creation in [Step 1](https://docs.stripe.com/terminal/payments/collect-card-payment.md#create-payment), the SDK returns an authorized but not captured `PaymentIntent` to your application. Learn more about the difference between [authorization and capture](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md). When your app receives a confirmed `PaymentIntent` from the SDK, make sure it notifies your backend to capture the payment. Create an endpoint on your backend that accepts a `PaymentIntent` ID and sends a request to the Stripe API to capture it: ```curl curl -X POST https://api.stripe.com/v1/payment_intents/{{PAYMENT_INTENT_ID}}/capture \ -u "<>:" ``` A successful `capture` call results in a `PaymentIntent` with a status of `succeeded`. To make sure the application fee captured is correct for connected accounts, inspect each `PaymentIntent` and modify the application fee, if needed, before manually capturing the payment. ### Reconcile payments To monitor the payments activity of your business, you might want to reconcile PaymentIntents with your internal orders system on your server at the end of a day’s activity. A `PaymentIntent` that retains a `requires_capture` status might represent two things: **Unnecessary authorization on your customer’s card statement** - Cause: User abandons your app’s checkout flow in the middle of a transaction - Solution: If the uncaptured `PaymentIntent` isn’t associated with a completed order on your server, you can [cancel](https://docs.stripe.com/api/payment_intents/cancel.md) it. You can’t use a canceled `PaymentIntent` to perform charges. **Incomplete collection of funds from a customer** - Cause: Failure of the request from your app notifying your backend to capture the payment - Solution: If the uncaptured `PaymentIntent` is associated with a completed order on your server, and no other payment has been taken for the order (for example, a cash payment), you can [capture](https://docs.stripe.com/api/payment_intents/capture.md) it. ### Collect tips (US only) In the US, eligible users can [collect a tip on the receipt when capturing payments](https://docs.stripe.com/terminal/features/collecting-tips/on-receipt.md).