POST /api/payments/confirm
Confirms a payment intent and attempts to complete the payment. This endpoint should be called after creating a payment intent to actually charge the customer’s payment method.
You may want to confirm separately from creation when you need to:
Collect additional customer information before charging
Verify inventory availability before completing the payment
Implement a two-step checkout process
Handle 3D Secure authentication flows
When to Use Manual Confirmation
By default, payment intents created through this API require manual confirmation. This gives you control over when the payment is actually processed:
Separate confirmation : Create the payment intent first, then confirm it in a separate step (use this endpoint)
Auto-confirmation : Pass confirm: true when creating the payment intent to skip this step
Request Body
The payment intent ID to confirm. Must be a valid Stripe payment intent ID starting with pi_. Example: pi_3OJxRe2eZvKYlo2C0XYZ1234
Response
Indicates if the request was successful
Human-readable message describing the result Example: Pago confirmado correctamente
The confirmed Stripe PaymentIntent object Show PaymentIntent Object
Unique identifier for the payment intent (starts with pi_)
Three-letter ISO currency code
The customer ID associated with this payment
The updated status after confirmation: processing, requires_action, succeeded, or canceled
Information about the charges made Array of charge objects (each with ID starting with ch_)
The ID of the most recent charge (starts with ch_)
Success Response
{
"status" : true ,
"message" : "Pago confirmado correctamente" ,
"data" : {
"id" : "pi_3OJxRe2eZvKYlo2C0XYZ1234" ,
"object" : "payment_intent" ,
"amount" : 100000 ,
"currency" : "eur" ,
"customer" : "cus_NffrFeUfNV2Hib" ,
"payment_method" : "pm_1Nvmn6LkdIwHu7ix" ,
"status" : "succeeded" ,
"charges" : {
"object" : "list" ,
"data" : [
{
"id" : "ch_3OJxRe2eZvKYlo2C0ABC5678" ,
"object" : "charge" ,
"amount" : 100000 ,
"status" : "succeeded" ,
"paid" : true
}
]
},
"latest_charge" : "ch_3OJxRe2eZvKYlo2C0ABC5678" ,
"created" : 1672531200 ,
"livemode" : false
}
}
Error Responses
400 Bad Request
402 Payment Required
500 Internal Server Error
{
"status" : false ,
"message" : "paymentId es requerido" ,
"code" : null
}
Code Examples
curl -X POST https://api.example.com/api/payments/confirm \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"paymentId": "pi_3OJxRe2eZvKYlo2C0XYZ1234"
}'
Payment Flow Example
// Step 1: Create payment intent
const createResponse = await fetch ( '/api/payments/create' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
amount: 5000 ,
customer_id: 'cus_NffrFeUfNV2Hib' ,
payment_method: 'pm_1Nvmn6LkdIwHu7ix'
})
});
const { data : paymentIntent } = await createResponse . json ();
// Step 2: Confirm the payment
const confirmResponse = await fetch ( '/api/payments/confirm' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
paymentId: paymentIntent . id
})
});
const { data : confirmedPayment } = await confirmResponse . json ();
if ( confirmedPayment . status === 'succeeded' ) {
console . log ( 'Payment completed!' );
}
If the payment requires additional customer action (like 3D Secure authentication), the status will be requires_action instead of succeeded. You’ll need to handle this on the client side using Stripe.js.