# How to retrieve a customer from Stripe API

- Tool: Stripe
- Difficulty: Beginner
- Time required: 10 minutes
- Compatibility: Stripe API v2024-12+, Node.js 18+, any backend framework
- Last updated: March 2026

## 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.

## Before you start

- 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.

```
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

const customer = await stripe.customers.retrieve('cus_ABC123');
console.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.

```
const customers = await stripe.customers.list({
  email: 'jane@example.com',
  limit: 1,
});

if (customers.data.length > 0) {
  const customer = customers.data[0];
  console.log('Found:', customer.id, customer.name);
} else {
  console.log('No customer found with that email');
}
```

**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.

```
const customer = await stripe.customers.retrieve('cus_ABC123', {
  expand: ['default_source', 'subscriptions'],
});

console.log('Subscriptions:', customer.subscriptions.data.length);
console.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.

```
let hasMore = true;
let startingAfter = undefined;

while (hasMore) {
  const batch = await stripe.customers.list({
    limit: 100,
    starting_after: startingAfter,
  });
  
  for (const customer of batch.data) {
    console.log(customer.id, customer.email);
  }
  
  hasMore = batch.has_more;
  if (batch.data.length > 0) {
    startingAfter = batch.data[batch.data.length - 1].id;
  }
}
```

**Expected result:** All customers are iterated through in batches of 100.

## Complete code example

File: `retrieve-customer.js`

```javascript
const express = require('express');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

const app = express();
app.use(express.json());

// Retrieve customer by ID
app.get('/api/customers/:id', async (req, res) => {
  try {
    const customer = await stripe.customers.retrieve(req.params.id, {
      expand: ['subscriptions', 'default_source'],
    });

    if (customer.deleted) {
      return res.status(404).json({ error: 'Customer has been deleted' });
    }

    res.json({
      id: customer.id,
      email: customer.email,
      name: customer.name,
      metadata: customer.metadata,
      subscriptions: customer.subscriptions?.data || [],
    });
  } catch (err) {
    if (err.code === 'resource_missing') {
      return res.status(404).json({ error: 'Customer not found' });
    }
    res.status(500).json({ error: err.message });
  }
});

// Search customer by email
app.get('/api/customers', async (req, res) => {
  try {
    const { email, limit = 10 } = req.query;

    if (!email) {
      return res.status(400).json({ error: 'Email query parameter is required' });
    }

    const customers = await stripe.customers.list({
      email,
      limit: parseInt(limit, 10),
    });

    res.json(customers.data);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

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

## Common mistakes

- **Not handling deleted customers** — undefined Fix: A retrieved customer may have deleted: true if they were deleted. Always check customer.deleted before using the record.
- **Assuming email search returns a single customer** — undefined Fix: stripe.customers.list({ email }) returns an array because Stripe allows duplicate emails. Always handle the array, even if you expect one result.
- **Making too many expand calls** — undefined Fix: 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

## 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.

---

Source: https://www.rapidevelopers.com/stripe-guide/how-to-retrieve-a-customer-from-stripe-api
© RapidDev — https://www.rapidevelopers.com/stripe-guide/how-to-retrieve-a-customer-from-stripe-api
