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.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
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:
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.
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.