Retrieve a Stripe customer by ID with stripe.customers.retrieve(customerId) or search by email with stripe.customers.list({ email }). These are the two most common lookup patterns. The retrieve call returns the full customer object including payment methods, metadata, and subscription status.
Looking Up Customers in the Stripe API
Once you have created Stripe customers, you need to retrieve their records to display account information, check subscription status, or update payment details. Stripe provides two main approaches: retrieve by ID (when you have the cus_ ID stored in your database) and list/search by email (when you need to look up a customer from user input). Both methods return the full customer object with all associated data.
Prerequisites
- A Stripe account with at least one customer created
- Node.js 18 or newer installed
- The stripe npm package installed (npm install stripe)
- Your Stripe secret key (sk_test_...) from Dashboard → Developers → API keys
Step-by-step guide
Retrieve a customer by ID
Retrieve a customer by ID
If you stored the cus_ ID in your database when the customer was created, use stripe.customers.retrieve() to fetch the full customer object.
1const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);23const customer = await stripe.customers.retrieve('cus_ABC123');4console.log(customer.email, customer.name);Expected result: The full customer object is returned with email, name, metadata, default payment method, and creation date.
Search for a customer by email
Search for a customer by email
When you do not have the cus_ ID, search by email using stripe.customers.list(). This returns an array since multiple customers can share the same email.
1const customers = await stripe.customers.list({2 email: 'jane@example.com',3 limit: 1,4});56if (customers.data.length > 0) {7 const customer = customers.data[0];8 console.log('Found:', customer.id, customer.name);9} else {10 console.log('No customer found with that email');11}Expected result: Returns the first customer matching the email, or an empty array if none found.
Expand related objects
Expand related objects
By default, related objects like payment methods and subscriptions are not included. Use the expand parameter to fetch them in a single API call.
1const customer = await stripe.customers.retrieve('cus_ABC123', {2 expand: ['default_source', 'subscriptions'],3});45console.log('Subscriptions:', customer.subscriptions.data.length);6console.log('Default source:', customer.default_source?.last4);Expected result: The customer object includes full subscription and payment source details instead of just IDs.
Paginate through all customers
Paginate through all customers
Use the starting_after parameter for cursor-based pagination to iterate through large customer lists.
1let hasMore = true;2let startingAfter = undefined;34while (hasMore) {5 const batch = await stripe.customers.list({6 limit: 100,7 starting_after: startingAfter,8 });9 10 for (const customer of batch.data) {11 console.log(customer.id, customer.email);12 }13 14 hasMore = batch.has_more;15 if (batch.data.length > 0) {16 startingAfter = batch.data[batch.data.length - 1].id;17 }18}Expected result: All customers are iterated through in batches of 100.
Complete working example
1const express = require('express');2const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);34const app = express();5app.use(express.json());67// Retrieve customer by ID8app.get('/api/customers/:id', async (req, res) => {9 try {10 const customer = await stripe.customers.retrieve(req.params.id, {11 expand: ['subscriptions', 'default_source'],12 });1314 if (customer.deleted) {15 return res.status(404).json({ error: 'Customer has been deleted' });16 }1718 res.json({19 id: customer.id,20 email: customer.email,21 name: customer.name,22 metadata: customer.metadata,23 subscriptions: customer.subscriptions?.data || [],24 });25 } catch (err) {26 if (err.code === 'resource_missing') {27 return res.status(404).json({ error: 'Customer not found' });28 }29 res.status(500).json({ error: err.message });30 }31});3233// Search customer by email34app.get('/api/customers', async (req, res) => {35 try {36 const { email, limit = 10 } = req.query;3738 if (!email) {39 return res.status(400).json({ error: 'Email query parameter is required' });40 }4142 const customers = await stripe.customers.list({43 email,44 limit: parseInt(limit, 10),45 });4647 res.json(customers.data);48 } catch (err) {49 res.status(500).json({ error: err.message });50 }51});5253const PORT = process.env.PORT || 3000;54app.listen(PORT, () => console.log(`Server on port ${PORT}`));Common mistakes when retrieving a customer from Stripe API
Why it's a problem: Not handling deleted customers
How to avoid: A retrieved customer may have deleted: true if they were deleted. Always check customer.deleted before using the record.
Why it's a problem: Assuming email search returns a single customer
How to avoid: stripe.customers.list({ email }) returns an array because Stripe allows duplicate emails. Always handle the array, even if you expect one result.
Why it's a problem: Making too many expand calls
How to avoid: Each expand adds latency. Only expand the objects you actually need. You can expand up to 4 levels deep.
Best practices
- Store the cus_ ID in your database at creation time to avoid email lookups later
- Use the expand parameter to fetch related objects in a single API call instead of multiple calls
- Handle the resource_missing error code gracefully when a customer ID does not exist
- Check customer.deleted before using retrieved customer data
- Use cursor-based pagination (starting_after) instead of offset for large lists
- Cache frequently accessed customer data to reduce API calls and stay within rate limits
- Use stripe.customers.search() for complex queries combining multiple fields
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Write a Node.js Express API with two endpoints: GET /customers/:id to retrieve a Stripe customer by ID with expanded subscriptions, and GET /customers?email=... to search customers by email. Use the stripe npm package and handle errors properly.
Add customer lookup to my app. Create an endpoint that accepts either a customer ID or email and returns the Stripe customer details including their subscriptions and default payment method. Handle not-found cases gracefully.
Frequently asked questions
What happens if I retrieve a customer that does not exist?
Stripe throws an error with code 'resource_missing' and a 404 status. Wrap your retrieve call in try/catch and check for this error code.
Can I retrieve a customer using their email instead of ID?
Not with stripe.customers.retrieve(), which requires a cus_ ID. Use stripe.customers.list({ email }) or stripe.customers.search() to look up by email.
What is the difference between list and search?
stripe.customers.list() filters by exact email match. stripe.customers.search() supports more complex queries like combining email, name, and metadata filters with a query string syntax.
How do I retrieve a customer's payment methods?
Use stripe.paymentMethods.list({ customer: 'cus_ABC123', type: 'card' }) to fetch all payment methods for a customer, or expand default_source when retrieving the customer.
Is there a cost per API call to retrieve customers?
No. Stripe does not charge per API call. However, there is a rate limit of 100 requests per second in live mode and 25 in test mode.
What if I need help building a customer lookup system for a large user base?
For high-volume applications that need efficient customer lookups, caching strategies, and database synchronization with Stripe, the RapidDev team can help design an optimized architecture.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation