Skip to main content

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

paymentId
string
required
The payment intent ID to confirm. Must be a valid Stripe payment intent ID starting with pi_.Example: pi_3OJxRe2eZvKYlo2C0XYZ1234

Response

status
boolean
Indicates if the request was successful
message
string
Human-readable message describing the resultExample: Pago confirmado correctamente
data
object
The confirmed Stripe PaymentIntent object

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

{
  "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.

Build docs developers (and LLMs) love