dobson
dobson

Reputation: 466

Adding products to a payment with PaymentIntents API

I just finished setting up payments through stripe on PHP using their payment intents API and forgot about having to add the products/items the user has just purchased.

Looking through the API Reference I didn't see anything where I could add items to the payment intent so I could retreive what was purchased later on in the webhook.

Do I need to do my own magic and somehow add the items to the metadata array or is there something that i'm missing here?

Upvotes: 15

Views: 11074

Answers (3)

german_goncharov
german_goncharov

Reputation: 3430

The previous answer is not entirely correct. Perhaps the Stripe API documentation has changed. So what needs to be done:

  1. Create an invoice by passing the customer_id. Docs
  2. Create an invoice element by passing the customer_id, invoice_id (from step 1) + either price_id or amount and currency. Docs
  3. Then finalize the invoice (it will receive the status="open") and automatically receive the payment intent. Docs
  4. Request the desired payment intent, and get its secret_key. Docs
// Step 1: Create an invoice by passing the customer_id.
const stripe = require('stripe')('YOUR_STRIPE_SECRET_KEY');

async function createInvoice(customer_id) {
  try {
    const invoice = await stripe.invoices.create({
      customer: customer_id,
    });
    return invoice;
  } catch (error) {
    console.error('Error creating invoice:', error);
    throw error;
  }
}

// Step 2: Create an invoice item for the invoice obtained from the previous step, by passing the customer_id, invoice_id, and either price_id or amount and currency.
async function createInvoiceItem(customer_id, invoice_id, price_id, amount, currency) {
  try {
    const invoiceItem = await stripe.invoiceItems.create({
      customer: customer_id,
      invoice: invoice_id,
      price: price_id, // or amount and currency, depending on your choice
    });
    return invoiceItem;
  } catch (error) {
    console.error('Error creating invoice item:', error);
    throw error;
  }
}

// Step 3: Finalize the invoice to set its status to "open" and automatically receive the payment intent.
async function finalizeInvoice(invoice_id) {
  try {
    const finalizedInvoice = await stripe.invoices.finalizeInvoice(invoice_id);
    return finalizedInvoice;
  } catch (error) {
    console.error('Error finalizing invoice:', error);
    throw error;
  }
}

// Step 4: Request the payment intent for the invoice.
async function getPaymentIntent(invoice_id) {
  try {
    const paymentIntent = await stripe.paymentIntents.create({
      invoice: invoice_id,
    });
    return paymentIntent;
  } catch (error) {
    console.error('Error getting payment intent:', error);
    throw error;
  }
}

// Usage of all steps:
async function main() {
  try {
    const customer_id = 'YOUR_CUSTOMER_ID';
    
    // Step 1: Create an invoice
    const invoice = await createInvoice(customer_id);
    console.log('Created invoice:', invoice);

    // Step 2: Create an invoice item
    const price_id = 'YOUR_PRICE_ID'; // or use amount and currency if not using Price API
    const invoiceItem = await createInvoiceItem(customer_id, invoice.id, price_id, 1000, 'usd');
    console.log('Created invoice item:', invoiceItem);

    // Step 3: Finalize the invoice and get the payment intent
    const finalizedInvoice = await finalizeInvoice(invoice.id);
    console.log('Finalized invoice:', finalizedInvoice);

    // Step 4: Request the payment intent
    const paymentIntent = await getPaymentIntent(invoice.id);
    console.log('Payment intent:', paymentIntent);
  } catch (error) {
    console.error('Error:', error);
  }
}

main();

Upvotes: 4

srmark
srmark

Reputation: 8162

I'm using node.js. Here's what worked for me:

Steps

  1. Create customer object
  2. Create invoice item
  3. Create invoice
  4. Finalize invoice (returns a payment intent id but not a secret)
  5. Retrieve the payment intent object by id (secret key must be used).

Step #5 response will contain the client_secret value that can be sent to the client for payment capture.

Nodes.js code

const customer = ...
const invoiceItem = await stripe.invoiceItems.create({
  customer: ...
  price_data: { ... }
})
const invoice = await stripe.invoices.create({
  customer: ...
})
const finalInvoice = await stripe.invoices.finalizeInvoice(
  invoice.id
)
const paymentIntent = await stripe.paymentIntents.retrieve(
  finalInvoice.payment_intent
)

res.send({ secret: paymentIntent.client_secret })

Upvotes: 14

taintedzodiac
taintedzodiac

Reputation: 2906

PaymentIntents do not track any sort of product that's connected to the purchase (just an amount). In order to link Products to a payment, you'd want to use Invoices which will generate a PaymentIntent as part of the process.

Upvotes: 21

Related Questions