Skip to main content
RapidDev - Software Development Agency
stripe-guide

How to retrieve a customer from Stripe API

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.

What you'll learn

  • How to retrieve a customer by their cus_ ID
  • How to search for customers by email address
  • How to expand related objects like payment methods and subscriptions
  • How to paginate through customer lists
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner5 min read10 minutesStripe API v2024-12+, Node.js 18+, any backend frameworkMarch 2026RapidDev Engineering Team
TL;DR

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

1

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.

typescript
1const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
2
3const 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.

2

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.

typescript
1const customers = await stripe.customers.list({
2 email: 'jane@example.com',
3 limit: 1,
4});
5
6if (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.

3

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.

typescript
1const customer = await stripe.customers.retrieve('cus_ABC123', {
2 expand: ['default_source', 'subscriptions'],
3});
4
5console.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.

4

Paginate through all customers

Use the starting_after parameter for cursor-based pagination to iterate through large customer lists.

typescript
1let hasMore = true;
2let startingAfter = undefined;
3
4while (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

retrieve-customer.js
1const express = require('express');
2const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
3
4const app = express();
5app.use(express.json());
6
7// Retrieve customer by ID
8app.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 });
13
14 if (customer.deleted) {
15 return res.status(404).json({ error: 'Customer has been deleted' });
16 }
17
18 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});
32
33// Search customer by email
34app.get('/api/customers', async (req, res) => {
35 try {
36 const { email, limit = 10 } = req.query;
37
38 if (!email) {
39 return res.status(400).json({ error: 'Email query parameter is required' });
40 }
41
42 const customers = await stripe.customers.list({
43 email,
44 limit: parseInt(limit, 10),
45 });
46
47 res.json(customers.data);
48 } catch (err) {
49 res.status(500).json({ error: err.message });
50 }
51});
52
53const 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.

ChatGPT Prompt

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.

Stripe Prompt

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.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.