One cart’s three changes dropped onto PaymentIntent statuses: an item added before confirmation is an update; a coupon after authorization uses amount_to_capture; shipping lifts the total to 6,500 over a 5,500 hold, so it needs increment_authorization or a new PaymentIntent.

How to update payment intent amounts in Stripe when the cart changes after the card is entered

The card is in, then the cart moves: an extra item, a coupon, a new shipping quote. Which call still works depends on one field, and it is not the amount.

Can you update payment intent amounts after the card is entered?#

You can update payment intent amounts with one call until confirmation; after authorization Stripe documents three routes: capture less, increment on eligible cards, or charge the difference on a new PaymentIntent. A narrow fourth route, overcapture, is shown below.

Stripe's PaymentIntents overview, accessed 4 October 2026, states the first case: "If the amount changes, you can update its amount." Then the hold guide covers the second: "A partial capture automatically releases the remaining amount." Finally, the increment reference covers the third, and it needs the status requires_capture.

So the first question for a cart change is not the new total. Instead, ask what status the intent is in right now.

javascript
// Read the status before you touch the amount.
const pi = await fetch(`https://api.stripe.com/v1/payment_intents/${id}`, {
  headers: { Authorization: "Basic " + btoa(process.env.STRIPE_SECRET_KEY + ":"), "Stripe-Version": "2026-08-26.dahlia" },
}).then((r) => r.json());
console.log(pi.status, pi.amount, pi.amount_capturable);

What does a mismatched hold cost the checkout?#

An unreconciled hold either releases money the order needed or expires: Stripe's capture reference (accessed 4 October 2026) cancels uncaptured PaymentIntents 7 days after creation by default. In its words, "Uncaptured PaymentIntents are cancelled a set number of days (7 by default) after their creation."

If a hold drifts from the final cart, it ends in one of three ways: a cancelled payment, a second charge the customer has to accept, or a refund. Each one is a support ticket, and the first is a lost order.

But the card brand sets the clock, and it is short. In practice, Stripe's hold guide, accessed 4 October 2026, gives about a week for online cards, and less for some Visa payments you start yourself.

Show data table
How long an online card hold stays capturable, by brand; the Visa merchant-initiated window is exactly 4 days and 18 hours. Source: Stripe, place a hold on a payment method, accessed 4 October 2026.
Item Value
Visa, customer-initiated 7
Visa, merchant-initiated 5
Mastercard 7
American Express 7
Discover 7

Most online card holds last about a week, and some Visa payments you start yourself get only five days.

Hold validity How long an online card hold stays capturable, by brand; the Visa merchant-initiated window is exactly 4 days and 18 hours. Source: Stripe, place a hold on a payment method, accessed 4 October 2026. Stripe, place a hold on a payment method, accessed 4 October 2026

Also, the hold guide says what happens at the end. When the hold runs out, "the funds are released and the payment status changes to canceled." To know the exact deadline, the same guide points at the charge's capture_before field.

javascript
// When does the hold run out? Stripe puts the deadline on the charge.
const pi = await fetch(`https://api.stripe.com/v1/payment_intents/${id}?expand[]=latest_charge`, {
  headers: { Authorization: "Basic " + btoa(process.env.STRIPE_SECRET_KEY + ":"), "Stripe-Version": "2026-08-26.dahlia" },
}).then((r) => r.json());
const deadline = pi.latest_charge.payment_method_details.card.capture_before;   // Unix seconds
console.log("capture before", new Date(deadline * 1000).toISOString());

What can you change at each PaymentIntent status?#

Stripe documents a plain amount update before payment; once the status is requires_capture, the documented routes are amount_to_capture to lower it and increment_authorization to raise it, and after succeeded, a refund or a new PaymentIntent. Stripe's update reference says the call "Updates properties on a PaymentIntent object without confirming". Also, its error codes page answers a call made in the wrong state with payment_intent_unexpected_state.

Then Stripe's own pages, all read on 4 October 2026, fill in the rest of the table. For example, the lifecycle page lets you cancel "before it reaches a processing or succeeded state". Then the capture reference captures only in requires_capture. Finally, the increment reference adds: "After it's captured, a PaymentIntent can no longer be incremented."

Stripe test mode agreed on 5 October 2026. An amount update on a held intent came back payment_intent_unexpected_state, and its message listed the statuses that take one: requires_payment_method, requires_confirmation and requires_action. An update during 3D Secure went through and sent the intent back to requires_confirmation, so confirm it again. A capture above the hold came back amount_too_large.

What each PaymentIntent status allows when the cart changes. Source: Stripe PaymentIntents lifecycle, update, capture and increment references, accessed 4 October 2026, and Stripe test mode, 5 October 2026.

StatusAmount upAmount downCancelRecapture
requires_payment_methodupdate, before paymentupdate, before paymentyesno hold yet
requires_confirmationupdate, before paymentupdate, before paymentyesno hold yet
requires_actionupdate, then confirm againupdate, then confirm againyesno hold yet
processingnonoonly some bank debitsno
requires_captureincrement_authorization if eligible, or overcaptureamount_to_capture at captureyes, releases the holdone capture, or multicapture
succeedednew PaymentIntentrefundnono
cancelednew PaymentIntentnone neededalready canceledno
PaymentIntent lifecycleAllowed amount changes at each status. Source: Stripe lifecycle page and API references, accessed 4 October 2026.
javascript
// Map the status to the documented way to change the amount.
function amountRoute(pi, newTotal) {
  switch (pi.status) {
    case "requires_payment_method":
    case "requires_confirmation":
    case "requires_action": return "update, then confirm again";
    case "requires_capture":
      return newTotal <= pi.amount_capturable ? "capture amount_to_capture" : "increment_authorization or new intent";
    case "succeeded": return newTotal === pi.amount_received ? "no change" : newTotal < pi.amount_received ? "refund" : "new intent for the difference";
    case "canceled": return "new intent";
    default: return "wait or cancel";   // processing
  }
}

How do you change the amount before confirmation?#

Before confirmation, send the new total to the PaymentIntents update endpoint; Stripe's update reference warns that changing the payment method means confirming the PaymentIntent again. Its words are "updating the payment_method always requires you to confirm the PaymentIntent again". So change the amount and leave the card alone, since a Stripe update payment intent call takes just the new total in the smallest currency unit, such as cents.

Keep one intent per cart, because Stripe's overview says to create it "as soon as you know the amount", then update it as the cart moves. As a result, the cart stores the intent id, and each edit before payment is an update.

bash
curl https://api.stripe.com/v1/payment_intents/pi_123 \
  -u "$STRIPE_SECRET_KEY:" -H "Stripe-Version: 2026-08-26.dahlia" \
  -d amount=5500

How do you lower the amount after authorization?#

After authorization you lower the total at capture: pass amount_to_capture below the held amount, and Stripe's hold documentation says the remainder is released automatically. Because Stripe documents no call that shrinks a hold in place, a coupon or a removed item waits for capture.

Stripe's capture reference, accessed 4 October 2026, sets the bound: the amount to capture "must be less than or equal to the original amount". If you leave it out, Stripe takes the full amount it holds. So the one thing to get right is the final number.

Held versus captured after a coupon1,000 cents released

5,500 cents

Held at confirmation

4,500 cents

Captured after a 1,000 coupon

A partial capture takes the final total, and Stripe releases the rest of the hold.

Held versus captured after a coupon (US cents, illustrative amounts from the worked example)
OptionUS cents, illustrative amounts from the worked example
Held at confirmation5,500 cents
Captured after a 1,000 coupon4,500 cents

Source: Stripe, place a hold on a payment method, accessed 4 October 2026

bash
curl https://api.stripe.com/v1/payment_intents/pi_123/capture \
  -u "$STRIPE_SECRET_KEY:" -H "Stripe-Version: 2026-08-26.dahlia" \
  -d amount_to_capture=4500

Plan for one capture. However, if an order ships in parts, Stripe's multicapture guide is built for that case.

How do you raise the amount with Stripe incremental authorization?#

Call increment_authorization with the new total while the PaymentIntent is in requires_capture; Stripe's documentation (accessed 4 October 2026) allows 10 attempts per PaymentIntent on eligible cards. In Stripe's words: "You have a maximum of 10 incremental authorization attempts per PaymentIntent."

But it is not on by default. Stripe's increment page says "It's only available with Visa, Mastercard, American Express, or Discover." Also, it offers the feature "to users on IC+ pricing", so other accounts must ask support, and Discover qualifies only in some merchant categories. Then you ask for it when you create the intent, with request_incremental_authorization set to if_available.

After payment, read the result. Then the charge marks the feature available or unavailable, and only available is worth a call.

Ask only once Stripe has turned it on. On a test account without the feature, the create took the flag, but the confirm was refused with payment_intent_invalid_parameter: "This account is not eligible for the requested card features." That was on 5 October 2026, even with if_available.

bash
# Without request_incremental_authorization at create, Stripe answers invalid_request_error.
curl https://api.stripe.com/v1/payment_intents/pi_123/increment_authorization \
  -u "$STRIPE_SECRET_KEY:" -H "Stripe-Version: 2026-08-26.dahlia" \
  -d amount=6500

Also, each step has a cap. The same Stripe page, accessed 4 October 2026, sets it at "either 500 USD (or local equivalent) over, or 500% over the previously authorized amount (whichever is higher)".

Show data table
Largest single increment, worked from Stripe's rule of the higher of 500 USD or 500% over the previous authorization. Source: Stripe, increment an authorization, accessed 4 October 2026.
Item Value
previous authorization 50 USD 500
previous authorization 100 USD 500
previous authorization 200 USD 1,000
previous authorization 1000 USD 5,000

Up to a 100 USD hold the 500 USD floor sets the cap; above it the 500% leg takes over.

Increment cap Largest single increment, worked from Stripe's rule of the higher of 500 USD or 500% over the previous authorization. Source: Stripe, increment an authorization, accessed 4 October 2026. Stripe, increment an authorization, accessed 4 October 2026

What if the card cannot be incremented?#

If the increment is unavailable or declined, the original hold stays capturable; capture it and charge the difference on a new PaymentIntent, or overcapture within the card brand's percentage limit. In that case, Stripe's increment page, accessed 4 October 2026, says a failure "returns a card_declined error instead". The intent "remains capturable for the previously authorized amount", so you can still take it.

So a failed step never loses the order, because you still hold the old amount.

Then there is overcapture, the smaller way out. Stripe's overcapture page, accessed 4 October 2026, lets you take a little more than the hold, up to a brand limit. It is also an IC+ feature. You ask for it at creation with request_overcapture set to if_available, then the page says to "provide an amount_to_capture up to the maximum_amount_capturable" at capture. On the same test account, asking for it was refused with the same error, and the charge reported overcapture unavailable. Because it depends on the account, the script below does not use it.

Show data table
How far above the hold a Visa payment can be captured, by merchant category. The Visa limits exclude businesses in the EEA, and the 15% general row covers cardholder-initiated payments only. Mastercard is listed only for US restaurants on US-issued cards. Source: Stripe, capture more than the authorized amount, accessed 4 October 2026.
Item Value
Visa, all other merchant categories 15
Visa, lodging and cruise lines 15
Visa, restaurants (global) 20
Visa, restaurants (US) 30

Overcapture leaves room for a small rise only, between 15% and 30% above the hold for Visa.

Overcapture limit How far above the hold a Visa payment can be captured, by merchant category. The Visa limits exclude businesses in the EEA, and the 15% general row covers cardholder-initiated payments only. Mastercard is listed only for US restaurants on US-issued cards. Source: Stripe, capture more than the authorized amount, accessed 4 October 2026. Stripe, capture more than the authorized amount, accessed 4 October 2026

When neither fits, capture the hold and charge the gap on a second intent with the saved card. That works only if the first intent saved it: create it with a customer and setup_future_usage set to off_session, which Stripe's overview says "saves payment methods to use again in the future".

bash
# The first intent was created with customer=cus_123 and setup_future_usage=off_session,
# so its card is saved to the customer and can be charged again.
curl https://api.stripe.com/v1/payment_intents \
  -u "$STRIPE_SECRET_KEY:" -H "Stripe-Version: 2026-08-26.dahlia" \
  -d amount=1000 -d currency=usd \
  -d customer=cus_123 -d payment_method=pm_saved \
  -d off_session=true -d confirm=true

What does one cart with three changes look like in code?#

This worked example creates one PaymentIntent, updates it for an added item, confirms it with manual capture, then reconciles a coupon and a shipping change at fulfilment. The amounts are illustrative cents: two items at 4,000, a third item to 5,500, a coupon of 1,000, then shipping.

The script calls the REST API with fetch, so it needs Node 18 or later and no other tools. For test cards, it uses pm_card_visa from Stripe's testing page. It also uses pm_card_debit_incrementalAuthAuthorized, which the increment page lists for a raise that goes through, and pm_card_credit_disableEnterpriseCardFeatures, which it lists as one that "Declines the increased authorization request". Each create, the customer included, carries an idempotency key built from the cart id, as Stripe's overview asks.

We ran it in Stripe test mode on 5 October 2026, on Node 26, against an account without incremental authorization. The first cart captured 5,000 of a 5,500 hold. The other two read the increment as unavailable, captured 5,500 and charged 1,000 on a second intent. Both test cards report unavailable on such an account, so the successful increment is Stripe's documented path, not one we saw. Set STRIPE_INCREMENTS=1 only once Stripe has enabled the feature.

javascript
// cart-three-changes.mjs  Run: STRIPE_SECRET_KEY=sk_test_... node cart-three-changes.mjs
// Add STRIPE_INCREMENTS=1 only if Stripe has enabled incremental authorization on the account.
import { randomUUID } from "node:crypto";
const KEY = process.env.STRIPE_SECRET_KEY;
const AUTH = "Basic " + btoa(KEY + ":");   // same as curl -u "$KEY:"
const VERSION = "2026-08-26.dahlia";        // pin it: an old account default renames statuses
const INCREMENTS = process.env.STRIPE_INCREMENTS === "1";
async function stripe(path, params = {}, idem) {
  const headers = { Authorization: AUTH, "Stripe-Version": VERSION, "Content-Type": "application/x-www-form-urlencoded" };
  if (idem) headers["Idempotency-Key"] = idem;          // a retry returns the same object
  const res = await fetch(`https://api.stripe.com/v1/${path}`, {
    method: "POST",
    headers,
    body: new URLSearchParams(params),
  });
  const json = await res.json();
  if (!res.ok) throw Object.assign(new Error(json.error?.message), { code: json.error?.code });
  return json;
}
const log = (step, pi) => console.log(step, pi.status, pi.amount, pi.amount_capturable, pi.amount_received);
async function runCart(testCard, shipping) {
  const cartId = randomUUID();                         // your cart's own id
  // 1. Two items: create with manual capture, and request increments if the account has them.
  //    The customer and setup_future_usage save the card for a later charge.
  const customer = (await stripe("customers", {}, `cart-${cartId}-customer`)).id;
  let pi = await stripe("payment_intents", {
    amount: "4000", currency: "usd", "payment_method_types[]": "card",
    customer, setup_future_usage: "off_session",
    capture_method: "manual",
    ...(INCREMENTS && { "payment_method_options[card][request_incremental_authorization]": "if_available" }),
  }, `cart-${cartId}`);
  log("create", pi);                                   // requires_payment_method
  // 2. Item added before confirmation: update.
  pi = await stripe(`payment_intents/${pi.id}`, { amount: "5500" });
  log("update", pi);                                   // requires_payment_method
  // 3. Confirm: the card is held, not charged.
  pi = await stripe(`payment_intents/${pi.id}/confirm`, { payment_method: testCard });
  log("confirm", pi);                                  // requires_capture
  // 4. Coupon after authorization, shipping at fulfilment: settle at capture.
  const held = pi.amount_capturable;
  const total = 5500 - 1000 + shipping;
  if (total <= held) {
    pi = await stripe(`payment_intents/${pi.id}/capture`, { amount_to_capture: String(total) });
    return log("capture less", pi);                    // succeeded
  }
  const charge = await fetch(`https://api.stripe.com/v1/payment_intents/${pi.id}?expand[]=latest_charge`,
    { headers: { Authorization: AUTH, "Stripe-Version": VERSION } }).then((r) => r.json());
  const inc = charge.latest_charge?.payment_method_details?.card?.incremental_authorization?.status;
  console.log("increment", inc);                       // "available" or "unavailable"
  if (inc === "available") {
    try {
      pi = await stripe(`payment_intents/${pi.id}/increment_authorization`, { amount: String(total) });
      log("increment", pi);                            // requires_capture
      return log("capture", await stripe(`payment_intents/${pi.id}/capture`));   // succeeded
    } catch (e) { console.log("increment failed:", e.code); }   // the hold stays as it was
  }
  // 5. Fallback: capture the hold, charge the difference to the saved card.
  log("capture hold", await stripe(`payment_intents/${pi.id}/capture`));         // succeeded
  log("difference", await stripe("payment_intents", {
    amount: String(total - held), currency: "usd", "payment_method_types[]": "card",
    customer, payment_method: pi.payment_method, off_session: "true", confirm: "true",
  }, `cart-${cartId}-difference`));                                                 // succeeded
}
await runCart("pm_card_visa", 500);                              // total 5,000: capture less
await runCart("pm_card_debit_incrementalAuthAuthorized", 2000);  // total 6,500: increment if enabled, else new intent
await runCart("pm_card_credit_disableEnterpriseCardFeatures", 2000);  // no increment: capture 5,500, new intent for 1,000

First, check the sums once by hand. In this illustrative cart, a 5,500 hold minus the 1,000 coupon leaves 4,500. With 500 of shipping, the illustrative total is 5,000, under the hold, so capture takes 5,000 and releases 500. With 2,000 of shipping, the illustrative total is 6,500, which is 1,000 over the hold. Then the script either increments or charges that 1,000 on a new intent.

Try it
Start from
Incremental authorization on the charge
5,500 held, minus 1,000 coupon, plus 2,000 shipping = 6,500

Increment, then capture

increment

The total is 1,000 over the hold and the card reports increments as available, within one step's cap of 50,000. Rules from Stripe: place a hold, capture a PaymentIntent and incremental authorization, accessed 4 October 2026. Modelled, not measured.

The calls to make, in order. Amounts are illustrative, in cents, the smallest currency unit Stripe takes.
Stripe callAmount
increment_authorization, amount6,500
capture6,500
Worked example: the starting inputs above, the same rules the controls run
Total5,500 held, minus 1,000 coupon, plus 2,000 shipping = 6,500
Callincrement_authorization amount=6500, then capture
WhyThe total is 1,000 over the hold and the card reports increments as available, within one step's cap of 50,000.
Change the hold, the coupon, the shipping and whether the card allows an increment, and see which Stripe call settles the cart. Illustrative cents. Modelled, not measured.

Which Stripe API calls does a cart integration make, in order?#

A cart integration makes its Stripe API calls in a fixed order: create, update, confirm, increment_authorization when eligible, and capture, each returning the PaymentIntent as JSON. Each request is a plain form post, and each reply is the same object with a new status.

Build it from these pages, in this order:

  1. PaymentIntents overview: one intent per cart, with a key that makes retries safe.
  2. Update a PaymentIntent: the new amount, before payment.
  3. Place a hold: manual capture, and capture less.
  4. Increment an authorization: the flag and the call.
  5. Capture a PaymentIntent: the capture call, and Stripe's 7-day default as of 4 October 2026.
  6. Testing: test cards such as pm_card_visa.
bash
V="Stripe-Version: 2026-08-26.dahlia"
curl https://api.stripe.com/v1/payment_intents -u "$STRIPE_SECRET_KEY:" -H "$V" \
  -d amount=4000 -d currency=usd -d "payment_method_types[]=card" \
  -d capture_method=manual
curl https://api.stripe.com/v1/payment_intents/pi_123 -u "$STRIPE_SECRET_KEY:" -H "$V" -d amount=5500
curl https://api.stripe.com/v1/payment_intents/pi_123/confirm -u "$STRIPE_SECRET_KEY:" -H "$V" -d payment_method=pm_card_visa
curl https://api.stripe.com/v1/payment_intents/pi_123/capture -u "$STRIPE_SECRET_KEY:" -H "$V" -d amount_to_capture=5000
json
{
  "id": "pi_123",
  "object": "payment_intent",
  "amount": 5500,
  "amount_capturable": 5500,
  "amount_received": 0,
  "capture_method": "manual",
  "status": "requires_capture"
}

Pin the API version on every call. Our test account defaulted to a 2015 version, which named the first status requires_source rather than requires_payment_method. So each block in this post sends a Stripe-Version header.

So the same calls work from any language, since they are plain HTTP with JSON back. A Stripe cart API integration is these calls, in this order. Because each reply is JSON, a Stripe JSON integration only needs status and amount_capturable. For the wider pattern, see how REST and other API styles compare. If your store takes cards today and the cart code needs work, our API integrations team does that work.

API call sequenceThe Stripe calls a cart makes, in order, and the status each returns. Source: Stripe API reference, accessed 4 October 2026.

How do Adyen and Braintree limit a changed amount?#

Adyen treats card payments as final authorizations by default, which cannot be adjusted, and Braintree marks an authorization expired after a window that varies by card brand. So the rule is not a Stripe quirk, though the calls differ.

For example, Adyen's adjustment page, accessed 4 October 2026, says a final hold means "it doesn't allow you to adjust the authorized amount later". Instead, you ask for a pre-auth up front, with additionalData.authorisationType set to PreAuth.

Adyen's implementation page, accessed 4 October 2026, then gives the call. You send POST /payments/{paymentPspReference}/amountUpdates with the new total, which it describes as "the sum of the original, pre-authorized amount and all later adjustments". Unlike Stripe, the change can go up or down, and the result arrives later as an AUTHORISATION_ADJUSTMENT webhook. Adyen also caps it at "a maximum of 50 adjustments". The same call with an unchanged amount is how you extend the hold: "make a /payments/{paymentPspReference}/amountUpdates request with the same amount as the current balance on the authorization".

Meanwhile, Braintree's status page, accessed 4 October 2026, marks a payment expired once it has "spent too much time in the Authorized status". For a lower total, the same page lists a payment that "was captured partially". This post has no Braintree test account behind it, so it shows no Braintree or Adyen code.

Show data table
Days before an authorization expires at Braintree, by card brand and type. Source: Braintree (PayPal), transaction statuses, accessed 4 October 2026.
Item Value
Visa, default 8
Visa, merchant-initiated recurring or unscheduled 3
Visa, lodging, vehicle rental, cruise 28
Mastercard, preauthorization 30
Mastercard, final authorization 7

Braintree windows run from 3 to 30 days, so the same cart logic needs a clock per brand.

Braintree expiry Days before an authorization expires at Braintree, by card brand and type. Source: Braintree (PayPal), transaction statuses, accessed 4 October 2026. Braintree (PayPal), transaction statuses, accessed 4 October 2026

When is incremental authorization the wrong tool?#

Skip incremental authorization when the card or account is not eligible, when the hold is near expiry, or when the order ships in parts; use a new PaymentIntent or multicapture instead.

First, take a card or account that does not qualify. The flag comes back unavailable, so build the capture plus new intent path and skip the step code. Second, take a hold close to its end. Stripe's increment page says increments "don't extend the validity period", so capture now and charge the gap. Third, take an order that ships in parts. The same page says an intent "partially captured with multicapture" can no longer be raised, so multicapture fits better there.

Also, card brands bar increments where the amount "should be known at the time of authorization", in Stripe's words. Subscriptions are the usual case.

When to skip an increment and what to use instead. Source: Stripe, incremental authorization, accessed 4 October 2026.

CaseWhat Stripe's increment page saysUse instead
Card or account not eligiblethe flag comes back unavailablecapture, then a new PaymentIntent
Hold close to its endincrements don't extend the validity periodcapture now, charge the gap
Order ships in partspartially captured with multicapture, no more incrementsmulticapture
Amount known at authorizationcard brands bar increments, for example subscriptionsa new PaymentIntent
javascript
// Read the charge before you increment; "unavailable" means skip straight to a new intent.
const pi = await fetch(`https://api.stripe.com/v1/payment_intents/${id}?expand[]=latest_charge`, {
  headers: { Authorization: "Basic " + btoa(process.env.STRIPE_SECRET_KEY + ":"), "Stripe-Version": "2026-08-26.dahlia" },
}).then((r) => r.json());
const inc = pi.latest_charge?.payment_method_details?.card?.incremental_authorization?.status;
console.log(inc === "available" ? "increment" : "capture, then a new PaymentIntent");

What should the cart check before every change?#

Check the status before every cart change, keep one PaymentIntent per cart, and reconcile the final total once at capture. So that one rule covers the added item, the coupon and the shipping change.

javascript
// Before every cart change: read the intent, then route by its status.
const pi = await fetch(`https://api.stripe.com/v1/payment_intents/${cart.paymentIntentId}`, {
  headers: { Authorization: "Basic " + btoa(process.env.STRIPE_SECRET_KEY + ":"), "Stripe-Version": "2026-08-26.dahlia" },
}).then((r) => r.json());
console.log(pi.status, amountRoute(pi, cart.total));   // amountRoute from the status section

If the real question is who should own the checkout, headless vs traditional ecommerce covers when the payment logic is yours to build. For card sales in a store, where holds work in a different way, read cloud POS systems for retail. If you want the whole checkout built, our ecommerce development team takes that on.

Still, the Stripe pages linked above are enough to build all of it yourself.

Frequently asked questions

Can you update payment intent amount after confirmation in Stripe?
Stripe documents the update call for the amount before payment, not after. In requires_capture, Stripe lowers it with amount_to_capture and raises it with increment_authorization on cards that qualify.
How do you increase the amount on an authorized Stripe payment?
Call increment_authorization with the new total while the status is requires_capture. Before that, the intent must be created with request_incremental_authorization set to if_available. Stripe's increment_authorization API reference, accessed 4 October 2026, allows 10 attempts per intent, including declines.
Can you capture less than the authorized amount in Stripe?
Yes, pass amount_to_capture below the held amount, and Stripe's hold guide says the rest is released.
How long does a Stripe authorization hold last before it expires?
Stripe's hold guide, accessed 4 October 2026, says an online card hold is usually valid for 7 days. But some Visa payments you start yourself get 5 days, and an extended hold can last longer.
What happens if a Stripe incremental authorization is declined?
If it is declined, Stripe returns card_declined, and the intent can still be captured for the amount held before. Then capture that and charge the gap on a new PaymentIntent.
Can you change the amount of a Stripe payment after it has succeeded?
No, because Stripe's lifecycle page sends refunds through the Refunds API, so a lower total is a refund, and a higher one is a new intent.

Keep reading