# Reviewing uncaptured payments Learn how to use reviews if your Stripe integration uses auth and capture. By default, you [create Stripe payments](https://docs.stripe.com/payments/accept-a-payment.md) in one step, which requires no further action on your part to send the funds to your bank account. However, Stripe also supports two-step payments, often called [auth and capture](https://support.stripe.com/questions/does-stripe-support-authorize-and-capture). If your integration uses this technique, keep in mind that **approving a review and capturing a payment are separate actions.** ## Reviewing uncaptured payments in the Dashboard When Stripe places an uncaptured payment in review, the Dashboard displays a **Capture** button in addition to the set of buttons for closing the review by approving or refunding it. Also, because refunding uncaptured payments is often called “releasing” or “[reversing](https://docs.stripe.com/refunds.md#refund-requests),” uncaptured payments have a **Cancel** button instead of a **Refund** button. Approving the review doesn’t automatically capture the charge. You still need to click **Capture**. ![](images/radar/uncaptured-payment.png) ## Using 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 To create an uncaptured payment, set the capture behavior accordingly in the API request. On success, check the payment intent’s [review](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-review) attribute. If the attribute is empty, capture the charge. ```ruby <> # 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 <> # 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 <> // 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 <> // 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(); } ``` ```javascript <> // 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 <> // 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) } ``` ```dotnet <> // 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); } ``` ### Capturing a payment after a review is approved By design, the previous step left the payments in `review` uncaptured. In this step, use *webhooks* to automate the process of capturing these payments upon approval. Start by [configuring your webhooks](https://docs.stripe.com/webhooks.md#register-webhook) to listen for the `review.closed` event. The event data includes the [review object](https://docs.stripe.com/api.md#review_object), and the object’s `reason` attribute indicates whether the review was approved, or if it was closed for some other 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 <> 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 ``` To capture approved payments, the review process must be completed within 7 days. Otherwise, as with any other uncaptured payment, the authorization automatically expires and you can no longer capture the payment.