/stripe-guides

How to create a payment intent in Stripe API?

Learn how to create a Payment Intent in Stripe API with step-by-step instructions, code examples, and best practices for secure payment processing.

Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

Book a free consultation

How to create a payment intent in Stripe API?

How to Create a Payment Intent in Stripe API

 

Introduction

 

Creating a Payment Intent is a crucial step in processing payments with Stripe. Payment Intents track the lifecycle of a customer payment, handling everything from initial authorization to capture. This tutorial provides detailed instructions for implementing Payment Intents using Stripe's API in different programming languages.

 

Step 1: Set Up Your Stripe Account

 

Before creating Payment Intents, you need to set up your Stripe account:

  • Sign up for a Stripe account at https://dashboard.stripe.com/register
  • Verify your email address and complete the onboarding process
  • Navigate to the Developers section in your Stripe Dashboard
  • Locate your API keys (you'll need both publishable and secret keys)

 

Step 2: Install the Stripe SDK

 

Depending on your programming language, install the appropriate Stripe library:

For Node.js:

npm install stripe

For Python:

pip install stripe

For PHP:

composer require stripe/stripe-php

For Ruby:

gem install stripe

 

Step 3: Initialize the Stripe Client

 

Node.js Example:

const stripe = require('stripe')('sk_test_your_secret_key');

// For ES modules
// import Stripe from 'stripe';
// const stripe = new Stripe('sk_test_your_secret_key');

Python Example:

import stripe
stripe.api_key = "sk_test_your_secret\_key"

PHP Example:

Ruby Example:

require 'stripe'
Stripe.api_key = 'sk_test_your_secret\_key'

 

Step 4: Create a Basic Payment Intent

 

Now, let's create a simple Payment Intent with the minimum required parameters:

Node.js Example:

async function createPaymentIntent() {
  try {
    const paymentIntent = await stripe.paymentIntents.create({
      amount: 2000, // Amount in cents (e.g., $20.00)
      currency: 'usd',
      payment_method_types: ['card'],
    });
    
    console.log('PaymentIntent created successfully');
    console.log('Client secret:', paymentIntent.client\_secret);
    return paymentIntent;
  } catch (error) {
    console.error('Error creating PaymentIntent:', error);
    throw error;
  }
}

// Call the function
createPaymentIntent();

Python Example:

def create_payment_intent():
    try:
        payment\_intent = stripe.PaymentIntent.create(
            amount=2000,  # Amount in cents (e.g., $20.00)
            currency="usd",
            payment_method_types=["card"],
        )
        
        print("PaymentIntent created successfully")
        print(f"Client secret: {payment_intent.client_secret}")
        return payment\_intent
    except Exception as e:
        print(f"Error creating PaymentIntent: {str(e)}")
        raise e

# Call the function
create_payment_intent()

PHP Example:

 2000, // Amount in cents (e.g., $20.00)
            'currency' => 'usd',
            'payment_method_types' => ['card'],
        ]);
        
        echo "PaymentIntent created successfully\n";
        echo "Client secret: " . $paymentIntent->client\_secret . "\n";
        return $paymentIntent;
    } catch (\Exception $e) {
        echo "Error creating PaymentIntent: " . $e->getMessage() . "\n";
        throw $e;
    }
}

// Call the function
createPaymentIntent();

Ruby Example:

def create_payment_intent
  begin
    payment\_intent = Stripe::PaymentIntent.create({
      amount: 2000, # Amount in cents (e.g., $20.00)
      currency: 'usd',
      payment_method_types: ['card'],
    })
    
    puts "PaymentIntent created successfully"
    puts "Client secret: #{payment_intent.client_secret}"
    return payment\_intent
  rescue Stripe::StripeError => e
    puts "Error creating PaymentIntent: #{e.message}"
    raise e
  end
end

# Call the function
create_payment_intent

 

Step 5: Create an Advanced Payment Intent

 

For more complex scenarios, you might want to include additional parameters:

Node.js Example:

async function createAdvancedPaymentIntent() {
  try {
    const paymentIntent = await stripe.paymentIntents.create({
      amount: 2000,
      currency: 'usd',
      payment_method_types: ['card'],
      description: 'Payment for order #123',
      receipt\_email: '[email protected]',
      metadata: {
        order\_id: '123',
        customer\_name: 'John Doe'
      },
      shipping: {
        name: 'John Doe',
        address: {
          line1: '123 Main St',
          city: 'San Francisco',
          state: 'CA',
          postal\_code: '94111',
          country: 'US'
        }
      },
      statement\_descriptor: 'MyStore Purchase',
      capture\_method: 'manual', // Authorize only, capture later
    });
    
    console.log('Advanced PaymentIntent created successfully');
    console.log('Client secret:', paymentIntent.client\_secret);
    return paymentIntent;
  } catch (error) {
    console.error('Error creating advanced PaymentIntent:', error);
    throw error;
  }
}

 

Step 6: Using a Customer and Payment Method

 

If you're working with existing customers and payment methods:

Node.js Example:

async function createPaymentIntentWithCustomer() {
  try {
    // First, create or retrieve a customer
    const customer = await stripe.customers.create({
      email: '[email protected]',
      name: 'John Doe'
    });
    
    // Create a payment method or use an existing one
    const paymentMethod = await stripe.paymentMethods.create({
      type: 'card',
      card: {
        number: '4242424242424242',
        exp\_month: 12,
        exp\_year: 2025,
        cvc: '123',
      },
    });
    
    // Attach payment method to the customer
    await stripe.paymentMethods.attach(
      paymentMethod.id,
      {customer: customer.id}
    );
    
    // Create payment intent using the customer and payment method
    const paymentIntent = await stripe.paymentIntents.create({
      amount: 2000,
      currency: 'usd',
      customer: customer.id,
      payment\_method: paymentMethod.id,
      off\_session: true,
      confirm: true,
    });
    
    console.log('PaymentIntent with customer created successfully');
    console.log('PaymentIntent ID:', paymentIntent.id);
    console.log('Status:', paymentIntent.status);
    return paymentIntent;
  } catch (error) {
    console.error('Error creating PaymentIntent with customer:', error);
    throw error;
  }
}

 

Step 7: Handling the Client Side

 

After creating a Payment Intent on the server, you need to handle it on the client side. Here's how to implement it using Stripe.js:




  Stripe Payment
  
  


  

 

Step 8: Setting Up a Server Endpoint

 

Create a server endpoint to generate the PaymentIntent:

Node.js with Express Example:

const express = require('express');
const app = express();
const stripe = require('stripe')('sk_test_your_secret_key');

app.use(express.static('public'));
app.use(express.json());

app.post('/create-payment-intent', async (req, res) => {
  try {
    const { amount, currency } = req.body;
    
    // Create a PaymentIntent
    const paymentIntent = await stripe.paymentIntents.create({
      amount,
      currency,
      payment_method_types: ['card'],
    });
    
    // Send the client secret to the client
    res.json({
      clientSecret: paymentIntent.client\_secret,
    });
  } catch (err) {
    console.error('Error creating payment intent:', err);
    res.status(500).json({ error: err.message });
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

 

Step 9: Handling Webhooks

 

To ensure you don't miss any payment events, set up a webhook to listen for Stripe events:

Node.js with Express Example:

const express = require('express');
const app = express();
const stripe = require('stripe')('sk_test_your_secret_key');

app.use(express.static('public'));
// Use raw body for webhook signature verification
app.use('/webhook', express.raw({ type: 'application/json' }));
app.use(express.json());

// Your payment intent creation endpoint...

// Webhook endpoint
app.post('/webhook', async (req, res) => {
  const sig = req.headers['stripe-signature'];
  const endpointSecret = 'whsec_your_webhook_signing_secret';
  
  let event;
  
  try {
    event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
  } catch (err) {
    console.error(`Webhook Error: ${err.message}`);
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }
  
  // Handle the event
  switch (event.type) {
    case 'payment\_intent.succeeded':
      const paymentIntent = event.data.object;
      console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`);
      // Update your database, fulfill the order, etc.
      break;
    case 'payment_intent.payment_failed':
      const failedPaymentIntent = event.data.object;
      console.log(`Payment failed: ${failedPaymentIntent.last_payment_error?.message}`);
      // Notify the customer that payment failed
      break;
    default:
      console.log(`Unhandled event type ${event.type}`);
  }
  
  // Return a 200 response to acknowledge receipt of the event
  res.send();
});

 

Step 10: Testing Your Implementation

 

Before going live, thoroughly test your Payment Intent implementation:

  • Use Stripe's test cards (e.g., 4242 4242 4242 4242 for successful payments)
  • Test various scenarios including successful payments, declined cards, and authentication requirements
  • Check if webhooks are correctly receiving and processing events
  • Verify that your database is being updated correctly
  • Test the entire user flow from checkout to completion

 

Step 11: Going Live

 

Once testing is complete:

  • Switch from test API keys to live API keys
  • Update webhook endpoints to use production webhook signing secrets
  • Ensure PCI compliance for your payment form
  • Implement proper error handling and logging
  • Set up monitoring for your payment processing

 

Conclusion

 

You've now learned how to create and implement Payment Intents with Stripe's API. This approach provides a secure, flexible way to process payments while handling authentication requirements and reducing fraud. Remember to keep your API keys secure and follow best practices for payment processing.

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Book a Free Consultation

Client trust and success are our top priorities

When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.

Rapid Dev was an exceptional project management organization and the best development collaborators I've had the pleasure of working with. They do complex work on extremely fast timelines and effectively manage the testing and pre-launch process to deliver the best possible product. I'm extremely impressed with their execution ability.

CPO, Praction - Arkady Sokolov

May 2, 2023

Working with Matt was comparable to having another co-founder on the team, but without the commitment or cost. He has a strategic mindset and willing to change the scope of the project in real time based on the needs of the client. A true strategic thought partner!

Co-Founder, Arc - Donald Muir

Dec 27, 2022

Rapid Dev are 10/10, excellent communicators - the best I've ever encountered in the tech dev space. They always go the extra mile, they genuinely care, they respond quickly, they're flexible, adaptable and their enthusiasm is amazing.

Co-CEO, Grantify - Mat Westergreen-Thorne

Oct 15, 2022

Rapid Dev is an excellent developer for no-code and low-code solutions.
We’ve had great success since launching the platform in November 2023. In a few months, we’ve gained over 1,000 new active users. We’ve also secured several dozen bookings on the platform and seen about 70% new user month-over-month growth since the launch.

Co-Founder, Church Real Estate Marketplace - Emmanuel Brown

May 1, 2024 

Matt’s dedication to executing our vision and his commitment to the project deadline were impressive. 
This was such a specific project, and Matt really delivered. We worked with a really fast turnaround, and he always delivered. The site was a perfect prop for us!

Production Manager, Media Production Company - Samantha Fekete

Sep 23, 2022