Find a payment by customer email in Stripe by searching the Dashboard (Payments → search bar → enter email) or via the API by first finding the customer with stripe.customers.list({ email }), then listing their PaymentIntents with stripe.paymentIntents.list({ customer }). Both methods let you trace any transaction back to a buyer.
Looking Up Payments by Customer Email
When a customer contacts you about a charge, you need to quickly find the corresponding payment. Stripe lets you search by email in both the Dashboard and the API. The Dashboard search bar matches email across customers, payments, and invoices. The API approach requires two steps: find the customer by email, then list their payment intents. For more complex queries, Stripe Search lets you combine email, amount, status, and date filters.
Prerequisites
- A Stripe account with existing payments or test transactions
- Node.js 18 or newer installed (for API method)
- Your Stripe secret key (sk_test_...) from Dashboard → Developers → API keys
- At least one payment linked to a customer with an email address
Step-by-step guide
Search in the Stripe Dashboard
Search in the Stripe Dashboard
Log in to the Stripe Dashboard, go to Payments in the left sidebar, and type the customer's email in the search bar at the top. Stripe shows all matching payments, including successful, failed, and refunded charges.
Expected result: A list of payments associated with the email appears, showing amount, status, date, and payment method.
Find the customer by email via API
Find the customer by email via API
To search programmatically, first find the customer record by email. This returns the cus_ ID you need to filter payments.
1const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);23const customers = await stripe.customers.list({4 email: 'jane@example.com',5 limit: 1,6});78if (customers.data.length === 0) {9 console.log('No customer found with that email');10}Expected result: Returns the customer object or an empty array if no match.
List payments for that customer
List payments for that customer
Use the customer's cus_ ID to list their PaymentIntents. You can filter by date range and limit results.
1const customerId = customers.data[0].id;23const payments = await stripe.paymentIntents.list({4 customer: customerId,5 limit: 20,6});78for (const payment of payments.data) {9 console.log(10 payment.id,11 payment.amount / 100, // convert cents to dollars12 payment.currency,13 payment.status14 );15}Expected result: A list of PaymentIntents for the customer, showing ID, amount, currency, and status.
Use Stripe Search for advanced queries
Use Stripe Search for advanced queries
Stripe Search lets you query payments directly by email, amount, or status without needing the customer ID first.
1const results = await stripe.paymentIntents.search({2 query: "customer_email:'jane@example.com' AND status:'succeeded'",3 limit: 10,4});56console.log(`Found ${results.data.length} successful payments`);Expected result: Returns PaymentIntents matching the email and status filter.
Complete working example
1const express = require('express');2const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);34const app = express();5app.use(express.json());67// Find payments by customer email8app.get('/api/payments/search', async (req, res) => {9 try {10 const { email, status, limit = 20 } = req.query;1112 if (!email) {13 return res.status(400).json({ error: 'Email is required' });14 }1516 // Build search query17 let query = `customer_email:'${email}'`;18 if (status) {19 query += ` AND status:'${status}'`;20 }2122 const results = await stripe.paymentIntents.search({23 query,24 limit: parseInt(limit, 10),25 });2627 const payments = results.data.map((pi) => ({28 id: pi.id,29 amount: pi.amount / 100,30 currency: pi.currency,31 status: pi.status,32 created: new Date(pi.created * 1000).toISOString(),33 description: pi.description,34 }));3536 res.json({ total: payments.length, payments });37 } catch (err) {38 console.error('Payment search error:', err.message);39 res.status(500).json({ error: err.message });40 }41});4243// Fallback: find via customer list44app.get('/api/payments/by-customer', async (req, res) => {45 try {46 const { email } = req.query;47 const customers = await stripe.customers.list({ email, limit: 1 });4849 if (customers.data.length === 0) {50 return res.json({ total: 0, payments: [] });51 }5253 const payments = await stripe.paymentIntents.list({54 customer: customers.data[0].id,55 limit: 50,56 });5758 res.json({59 customer: customers.data[0].id,60 total: payments.data.length,61 payments: payments.data.map((pi) => ({62 id: pi.id,63 amount: pi.amount / 100,64 currency: pi.currency,65 status: pi.status,66 })),67 });68 } catch (err) {69 res.status(500).json({ error: err.message });70 }71});7273const PORT = process.env.PORT || 3000;74app.listen(PORT, () => console.log(`Server on port ${PORT}`));Common mistakes when findding a payment using customer email in Stripe
Why it's a problem: Searching PaymentIntents by email directly without using Stripe Search
How to avoid: stripe.paymentIntents.list() does not accept an email parameter. Either find the customer first, or use stripe.paymentIntents.search() with the customer_email field.
Why it's a problem: Expecting Stripe Search results to be instantly available
How to avoid: Stripe Search has a slight indexing delay. For real-time lookups immediately after payment, use the customer ID approach instead.
Why it's a problem: Not converting amounts from cents to dollars in results
How to avoid: Stripe stores all amounts in the smallest currency unit (cents for USD). Divide by 100 before displaying to users.
Best practices
- Use Stripe Search for one-off lookups and the customer-based approach for real-time queries
- Always set receipt_email on PaymentIntents so payments are searchable by email even without a customer record
- Store the Stripe customer ID in your database to avoid email lookups entirely
- Convert amounts from cents when displaying to users (amount / 100 for USD)
- Use date filters to narrow results when searching for specific transactions
- Paginate results using the has_more flag and starting_after cursor for large result sets
- Log search queries for audit purposes when looking up customer payment data
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Write a Node.js function that takes a customer email and returns all their Stripe payments. Use stripe.paymentIntents.search() with the customer_email field. Return the payment ID, amount in dollars, status, and date for each result.
Add a payment lookup endpoint to my app. Accept an email query parameter, search Stripe payments by that email, and return the results with amount converted from cents to dollars. Support optional status filtering.
Frequently asked questions
Can I search payments by email if the payment was made without a customer record?
Yes, if receipt_email was set on the PaymentIntent or Charge. Stripe Search indexes receipt_email. Without either a customer or receipt_email, you cannot search by email.
How far back can I search for payments?
Stripe retains payment data indefinitely. There is no time limit on searching. For very old transactions, API pagination or CSV export may be more practical.
Can I search by partial email?
The Dashboard search supports partial matching. The API's stripe.paymentIntents.search() requires exact email values in the query. For partial matches, use the Dashboard.
Is Stripe Search available in test mode?
Yes. Stripe Search works identically in test and live modes. Search test mode data using your test secret key.
What if I need a custom payment lookup system for my support team?
For building internal tools that let support agents search, filter, and manage Stripe payments, the RapidDev team can help create a custom admin dashboard integrated with the Stripe API.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation