/stripe-guides

How to retrieve a customer from Stripe API?

Learn how to retrieve customer data from the Stripe API with step-by-step guides, code examples in multiple languages, error handling, and best practices.

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 retrieve a customer from Stripe API?

How to Retrieve a Customer from Stripe API: A Comprehensive Tutorial

 

Introduction

 

In this tutorial, we'll learn how to retrieve customer information from the Stripe API. Stripe is a widely used payment processing platform that provides a robust API for managing customers, payments, subscriptions, and more. We'll cover different methods of retrieving a single customer by ID as well as listing multiple customers with various filtering options.

 

Prerequisites

 

Before getting started, ensure you have:

  • A Stripe account (create one at https://stripe.com if you don't have it)
  • Stripe API keys (available in your Stripe Dashboard)
  • Basic understanding of your programming language of choice (we'll provide examples in multiple languages)
  • The appropriate Stripe library/SDK installed for your programming language

 

Step 1: Set Up Your Environment

 

First, you need to install the Stripe library for your programming language:

For Node.js:

npm install stripe

For Python:

pip install stripe

For PHP:

composer require stripe/stripe-php

For Ruby:

gem install stripe

 

Step 2: Configure Your API Keys

 

You'll need to initialize the Stripe client with your API key. For security, we recommend using your secret key in server-side code only, never in client-side code.

Node.js:

const stripe = require('stripe')('sk_test_YOUR_SECRET_KEY');
// For async/await support
const stripeAsync = require('stripe')('sk_test_YOUR_SECRET_KEY');

Python:

import stripe
stripe.api_key = "sk_test_YOUR_SECRET\_KEY"

PHP:

\Stripe\Stripe::setApiKey('sk_test_YOUR_SECRET_KEY');

Ruby:

require 'stripe'
Stripe.api_key = 'sk_test_YOUR_SECRET\_KEY'

 

Step 3: Retrieve a Single Customer by ID

 

To retrieve a specific customer, you'll need their customer ID. Stripe customer IDs typically start with "cus_".

Node.js:

// Using promises
stripe.customers.retrieve('cus\_123456789')
  .then(customer => {
    console.log(customer);
  })
  .catch(error => {
    console.error('Error:', error);
  });

// Using async/await
async function getCustomer() {
  try {
    const customer = await stripe.customers.retrieve('cus\_123456789');
    console.log(customer);
  } catch (error) {
    console.error('Error:', error);
  }
}

Python:

try:
    customer = stripe.Customer.retrieve('cus\_123456789')
    print(customer)
except stripe.error.StripeError as e:
    print(f"Error: {e}")

PHP:

try {
    $customer = \Stripe\Customer::retrieve('cus\_123456789');
    print\_r($customer);
} catch (\Stripe\Exception\ApiErrorException $e) {
    echo 'Error: ' . $e->getMessage();
}

Ruby:

begin
  customer = Stripe::Customer.retrieve('cus\_123456789')
  puts customer
rescue Stripe::StripeError => e
  puts "Error: #{e.message}"
end

 

Step 4: Retrieve Expanded Customer Data

 

Sometimes you might want to retrieve a customer with related objects like their payment methods, subscriptions, or default card. The expand parameter allows you to include this additional information.

Node.js:

// Retrieve customer with expanded payment methods and subscriptions
async function getCustomerWithExpanded() {
  try {
    const customer = await stripe.customers.retrieve('cus\_123456789', {
      expand: ['default\_source', 'subscriptions']
    });
    console.log(customer);
    console.log('Default payment source:', customer.default\_source);
    console.log('Subscriptions:', customer.subscriptions.data);
  } catch (error) {
    console.error('Error:', error);
  }
}

Python:

try:
    customer = stripe.Customer.retrieve(
        'cus\_123456789',
        expand=['default\_source', 'subscriptions']
    )
    print(customer)
    print(f"Default payment source: {customer.default\_source}")
    print(f"Subscriptions: {customer.subscriptions.data}")
except stripe.error.StripeError as e:
    print(f"Error: {e}")

PHP:

try {
    $customer = \Stripe\Customer::retrieve([
        'id' => 'cus\_123456789',
        'expand' => ['default\_source', 'subscriptions']
    ]);
    print\_r($customer);
    print_r("Default payment source: " . $customer->default_source);
    print\_r("Subscriptions: " . $customer->subscriptions->data);
} catch (\Stripe\Exception\ApiErrorException $e) {
    echo 'Error: ' . $e->getMessage();
}

Ruby:

begin
  customer = Stripe::Customer.retrieve({
    id: 'cus\_123456789',
    expand: ['default\_source', 'subscriptions']
  })
  puts customer
  puts "Default payment source: #{customer.default\_source}"
  puts "Subscriptions: #{customer.subscriptions.data}"
rescue Stripe::StripeError => e
  puts "Error: #{e.message}"
end

 

Step 5: List Multiple Customers

 

You can also retrieve multiple customers at once with optional filtering.

Node.js:

async function listCustomers() {
  try {
    const customers = await stripe.customers.list({
      limit: 10, // Number of customers to return
      email: '[email protected]', // Optional: filter by email
      created: { // Optional: filter by creation date
        gte: Math.floor(Date.now() / 1000) - 30 _ 24 _ 60 \* 60 // last 30 days
      }
    });
    
    console.log('Total customers:', customers.data.length);
    customers.data.forEach(customer => {
      console.log(`Customer ID: ${customer.id}, Email: ${customer.email}`);
    });
  } catch (error) {
    console.error('Error:', error);
  }
}

Python:

try:
    customers = stripe.Customer.list(
        limit=10,  # Number of customers to return
        email='[email protected]',  # Optional: filter by email
        created={  # Optional: filter by creation date
            'gte': int(time.time()) - 30 _ 24 _ 60 \* 60  # last 30 days
        }
    )
    
    print(f"Total customers: {len(customers.data)}")
    for customer in customers.data:
        print(f"Customer ID: {customer.id}, Email: {customer.email}")
except stripe.error.StripeError as e:
    print(f"Error: {e}")

PHP:

try {
    $customers = \Stripe\Customer::all([
        'limit' => 10, // Number of customers to return
        'email' => '[email protected]', // Optional: filter by email
        'created' => [ // Optional: filter by creation date
            'gte' => time() - 30 _ 24 _ 60 \* 60 // last 30 days
        ]
    ]);
    
    echo 'Total customers: ' . count($customers->data) . "\n";
    foreach ($customers->data as $customer) {
        echo "Customer ID: {$customer->id}, Email: {$customer->email}\n";
    }
} catch (\Stripe\Exception\ApiErrorException $e) {
    echo 'Error: ' . $e->getMessage();
}

Ruby:

begin
  customers = Stripe::Customer.list(
    limit: 10,  # Number of customers to return
    email: '[email protected]',  # Optional: filter by email
    created: {  # Optional: filter by creation date
      gte: Time.now.to\_i - 30 _ 24 _ 60 \* 60  # last 30 days
    }
  )
  
  puts "Total customers: #{customers.data.length}"
  customers.data.each do |customer|
    puts "Customer ID: #{customer.id}, Email: #{customer.email}"
  end
rescue Stripe::StripeError => e
  puts "Error: #{e.message}"
end

 

Step 6: Paginate Through Customers

 

If you have many customers, you'll want to paginate through them:

Node.js:

async function listAllCustomers() {
  let hasMore = true;
  let startingAfter = null;
  let allCustomers = [];
  
  while (hasMore) {
    const params = { 
      limit: 100 
    };
    
    if (startingAfter) {
      params.starting\_after = startingAfter;
    }
    
    const customers = await stripe.customers.list(params);
    allCustomers = allCustomers.concat(customers.data);
    
    hasMore = customers.has\_more;
    if (hasMore && customers.data.length > 0) {
      startingAfter = customers.data[customers.data.length - 1].id;
    }
  }
  
  console.log(`Retrieved ${allCustomers.length} customers in total`);
  return allCustomers;
}

Python:

def list_all_customers():
    all\_customers = []
    has\_more = True
    starting\_after = None
    
    while has\_more:
        params = {'limit': 100}
        if starting\_after:
            params['starting_after'] = starting_after
        
        customers = stripe.Customer.list(\*\*params)
        all\_customers.extend(customers.data)
        
        has_more = customers.has_more
        if has\_more and len(customers.data) > 0:
            starting\_after = customers.data[-1].id
    
    print(f"Retrieved {len(all\_customers)} customers in total")
    return all\_customers

PHP:

function listAllCustomers() {
    $allCustomers = [];
    $hasMore = true;
    $startingAfter = null;
    
    while ($hasMore) {
        $params = ['limit' => 100];
        if ($startingAfter) {
            $params['starting\_after'] = $startingAfter;
        }
        
        $customers = \Stripe\Customer::all($params);
        $allCustomers = array\_merge($allCustomers, $customers->data);
        
        $hasMore = $customers->has\_more;
        if ($hasMore && count($customers->data) > 0) {
            $startingAfter = end($customers->data)->id;
        }
    }
    
    echo "Retrieved " . count($allCustomers) . " customers in total\n";
    return $allCustomers;
}

Ruby:

def list_all_customers
  all\_customers = []
  has\_more = true
  starting\_after = nil
  
  while has\_more
    params = { limit: 100 }
    params[:starting_after] = starting_after if starting\_after
    
    customers = Stripe::Customer.list(params)
    all\_customers.concat(customers.data)
    
    has_more = customers.has_more
    if has\_more && !customers.data.empty?
      starting\_after = customers.data.last.id
    end
  end
  
  puts "Retrieved #{all\_customers.length} customers in total"
  return all\_customers
end

 

Step 7: Search for Customers (New API)

 

Stripe introduced a more powerful search API for customers that allows for more complex queries.

Node.js:

async function searchCustomers() {
  try {
    const customers = await stripe.customers.search({
      query: "email:'gmail.com' AND metadata['customer\_type']:'premium'",
      limit: 20
    });
    
    console.log(`Found ${customers.data.length} matching customers`);
    customers.data.forEach(customer => {
      console.log(`ID: ${customer.id}, Email: ${customer.email}`);
    });
  } catch (error) {
    console.error('Error:', error);
  }
}

Python:

try:
    customers = stripe.Customer.search(
        query="email:'gmail.com' AND metadata['customer\_type']:'premium'",
        limit=20
    )
    
    print(f"Found {len(customers.data)} matching customers")
    for customer in customers.data:
        print(f"ID: {customer.id}, Email: {customer.email}")
except stripe.error.StripeError as e:
    print(f"Error: {e}")

PHP:

try {
    $customers = \Stripe\Customer::search([
        'query' => "email:'gmail.com' AND metadata['customer\_type']:'premium'",
        'limit' => 20
    ]);
    
    echo "Found " . count($customers->data) . " matching customers\n";
    foreach ($customers->data as $customer) {
        echo "ID: {$customer->id}, Email: {$customer->email}\n";
    }
} catch (\Stripe\Exception\ApiErrorException $e) {
    echo 'Error: ' . $e->getMessage();
}

Ruby:

begin
  customers = Stripe::Customer.search(
    query: "email:'gmail.com' AND metadata['customer\_type']:'premium'",
    limit: 20
  )
  
  puts "Found #{customers.data.length} matching customers"
  customers.data.each do |customer|
    puts "ID: #{customer.id}, Email: #{customer.email}"
  end
rescue Stripe::StripeError => e
  puts "Error: #{e.message}"
end

 

Step 8: Error Handling Best Practices

 

It's important to handle errors properly when working with the Stripe API. Here's a more detailed example:

Node.js:

async function retrieveCustomerWithErrorHandling(customerId) {
  try {
    const customer = await stripe.customers.retrieve(customerId);
    return customer;
  } catch (error) {
    if (error.type === 'StripeInvalidRequestError') {
      if (error.statusCode === 404) {
        console.error(`Customer with ID ${customerId} not found`);
      } else {
        console.error(`Invalid request: ${error.message}`);
      }
    } else if (error.type === 'StripeAuthenticationError') {
      console.error('Authentication failed. Check your API key.');
    } else if (error.type === 'StripeRateLimitError') {
      console.error('Rate limit exceeded. Please try again after some time.');
    } else if (error.type === 'StripeConnectionError') {
      console.error('Network connection error. Please check your internet connection.');
    } else if (error.type === 'StripeAPIError') {
      console.error('Stripe API error occurred.');
    } else {
      console.error('Unknown error:', error);
    }
    throw error;
  }
}

Python:

def retrieve_customer_with_error_handling(customer\_id):
    try:
        customer = stripe.Customer.retrieve(customer\_id)
        return customer
    except stripe.error.InvalidRequestError as e:
        if e.http\_status == 404:
            print(f"Customer with ID {customer\_id} not found")
        else:
            print(f"Invalid request: {e.error.message}")
    except stripe.error.AuthenticationError:
        print("Authentication failed. Check your API key.")
    except stripe.error.RateLimitError:
        print("Rate limit exceeded. Please try again after some time.")
    except stripe.error.APIConnectionError:
        print("Network connection error. Please check your internet connection.")
    except stripe.error.StripeError as e:
        print(f"Generic Stripe error: {e.error.message}")
    except Exception as e:
        print(f"Unknown error: {str(e)}")
    raise

 

Step 9: Working with Customer Metadata

 

Stripe allows you to store additional information about customers in metadata. When retrieving customers, you can access this metadata:

Node.js:

async function getCustomerWithMetadata(customerId) {
  try {
    const customer = await stripe.customers.retrieve(customerId);
    
    console.log('Customer:', customer.name);
    console.log('Email:', customer.email);
    
    // Access metadata
    if (customer.metadata) {
      console.log('Metadata:');
      Object.keys(customer.metadata).forEach(key => {
        console.log(`  ${key}: ${customer.metadata[key]}`);
      });
    }
    
    return customer;
  } catch (error) {
    console.error('Error:', error);
    throw error;
  }
}

Python:

def get_customer_with_metadata(customer_id):
    try:
        customer = stripe.Customer.retrieve(customer\_id)
        
        print(f"Customer: {customer.name}")
        print(f"Email: {customer.email}")
        
        # Access metadata
        if customer.metadata:
            print("Metadata:")
            for key, value in customer.metadata.items():
                print(f"  {key}: {value}")
        
        return customer
    except stripe.error.StripeError as e:
        print(f"Error: {e}")
        raise

 

Step 10: Using the Raw HTTP API (Advanced)

 

If you prefer not to use the official libraries, you can make direct HTTP requests to the Stripe API:

Using cURL:

curl https://api.stripe.com/v1/customers/cus\_123456789 \\
  -u sk_test_YOUR_SECRET_KEY:

Using JavaScript fetch API:

async function fetchCustomer(customerId) {
  const apiKey = 'sk_test_YOUR_SECRET_KEY';
  const url = `https://api.stripe.com/v1/customers/${customerId}`;
  
  try {
    const response = await fetch(url, {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    });
    
    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }
    
    const customer = await response.json();
    console.log('Customer retrieved:', customer);
    return customer;
  } catch (error) {
    console.error('Error fetching customer:', error);
    throw error;
  }
}

 

Conclusion

 

In this tutorial, we've covered multiple ways to retrieve customers from the Stripe API, including getting a single customer by ID, listing multiple customers, pagination, searching for customers, handling errors, and working with customer metadata. You should now have a comprehensive understanding of how to interact with Stripe's customer API.

Remember to always use your test API keys when experimenting with the API and only switch to live keys when your application is ready for production. Also, ensure you're handling customer data securely and in compliance with privacy regulations.

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