Bug: @better-auth/stripecustomers.search unavailable in India (and other regions) #2867

Closed
opened 2026-03-13 10:24:39 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @bhagyamudgal on GitHub (Feb 13, 2026).

Originally assigned to: @bytaesu on GitHub.

To Reproduce

  1. Set up a Stripe account registered in India
  2. Configure @better-auth/stripe plugin with subscription management
  3. Call the /api/auth/subscription/upgrade endpoint (or trigger createCustomerOnSignUp)
  4. The Stripe API call fails with: search feature unavailable for merchant

The Stripe Search API (/v1/customers/search) is not available for merchant accounts in certain regions, including India. See: https://docs.stripe.com/search#supported-countries

The @better-auth/stripe plugin uses customers.search in 3 places within dist/index.mjs:

Location Purpose
upgradeSubscription (~line 563) Find org customer by metadata["organizationId"]
upgradeSubscription (~line 603) Find user customer by email, excluding org customers
stripe() database hook (~line 1427) Find existing customer on signup by email

All 3 throw UNABLE_TO_CREATE_CUSTOMER because the customers.search call fails.

Current vs. Expected behavior

Current: The plugin unconditionally uses stripe.customers.search(), which fails with a Stripe API error for merchants in unsupported regions (India, etc.). This makes the entire subscription flow unusable.

Expected: The plugin should fall back to stripe.customers.list() with appropriate filtering when customers.search is unavailable, or use customers.list by default since it works globally. The customers.list API supports email filtering natively, and metadata filtering can be done client-side on a small result set.

Suggested fix

Replace customers.search with customers.list:

For email-based searches:

// Before
client.customers.search({
  query: `email:"${email}" AND -metadata["customerType"]:"organization"`,
  limit: 1
}).data[0]

// After
client.customers.list({ email, limit: 100 })
  .data.find(c => c.metadata?.customerType !== "organization")

For metadata-based searches (org):

// Before
client.customers.search({
  query: `metadata["organizationId"]:"${orgId}"`,
  limit: 1
}).data[0]

// After
client.customers.list({ limit: 100 })
  .data.find(c => c.metadata?.organizationId === orgId)

This is a drop-in replacement that works in all Stripe regions.

What version of Better Auth are you using?

1.4.18 (also affects @better-auth/stripe v1.4.18)

System info

better-auth: 1.4.18
@better-auth/stripe: 1.4.18
Runtime: Node.js 22

Which area(s) are affected?

  • Package (@better-auth/stripe)

Auth config (if applicable)

import { betterAuth } from "better-auth";
import { stripe } from "@better-auth/stripe";

export const auth = betterAuth({
  plugins: [
    stripe({
      stripeSecretKey: process.env.STRIPE_SECRET_KEY,
      stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
      createCustomerOnSignUp: true,
      subscription: {
        enabled: true,
        plans: [/* ... */],
      },
    }),
  ],
});

Additional context

  • Workaround: Patching dist/index.mjs locally to replace all 3 customers.search calls with customers.list equivalents works correctly.
  • The Stripe Search API documentation explicitly lists supported countries: https://docs.stripe.com/search#supported-countries
  • India is a major market and this blocks all Indian Stripe merchants from using Better Auth's subscription features.
  • The customers.list API is available globally and supports email filtering natively. Metadata filtering requires client-side filtering on the result set, but since these queries use limit: 1, the data volume is minimal.
Originally created by @bhagyamudgal on GitHub (Feb 13, 2026). Originally assigned to: @bytaesu on GitHub. ## To Reproduce 1. Set up a Stripe account registered in India 2. Configure `@better-auth/stripe` plugin with subscription management 3. Call the `/api/auth/subscription/upgrade` endpoint (or trigger `createCustomerOnSignUp`) 4. The Stripe API call fails with: `search feature unavailable for merchant` The Stripe Search API (`/v1/customers/search`) is **not available** for merchant accounts in certain regions, including India. See: https://docs.stripe.com/search#supported-countries The `@better-auth/stripe` plugin uses `customers.search` in 3 places within `dist/index.mjs`: | Location | Purpose | |----------|---------| | `upgradeSubscription` (~line 563) | Find org customer by `metadata["organizationId"]` | | `upgradeSubscription` (~line 603) | Find user customer by email, excluding org customers | | `stripe()` database hook (~line 1427) | Find existing customer on signup by email | All 3 throw `UNABLE_TO_CREATE_CUSTOMER` because the `customers.search` call fails. ## Current vs. Expected behavior **Current:** The plugin unconditionally uses `stripe.customers.search()`, which fails with a Stripe API error for merchants in unsupported regions (India, etc.). This makes the entire subscription flow unusable. **Expected:** The plugin should fall back to `stripe.customers.list()` with appropriate filtering when `customers.search` is unavailable, or use `customers.list` by default since it works globally. The `customers.list` API supports `email` filtering natively, and metadata filtering can be done client-side on a small result set. ### Suggested fix Replace `customers.search` with `customers.list`: **For email-based searches:** ```js // Before client.customers.search({ query: `email:"${email}" AND -metadata["customerType"]:"organization"`, limit: 1 }).data[0] // After client.customers.list({ email, limit: 100 }) .data.find(c => c.metadata?.customerType !== "organization") ``` **For metadata-based searches (org):** ```js // Before client.customers.search({ query: `metadata["organizationId"]:"${orgId}"`, limit: 1 }).data[0] // After client.customers.list({ limit: 100 }) .data.find(c => c.metadata?.organizationId === orgId) ``` This is a drop-in replacement that works in all Stripe regions. ## What version of Better Auth are you using? 1.4.18 (also affects `@better-auth/stripe` v1.4.18) ## System info ``` better-auth: 1.4.18 @better-auth/stripe: 1.4.18 Runtime: Node.js 22 ``` ## Which area(s) are affected? - Package (`@better-auth/stripe`) ## Auth config (if applicable) ```typescript import { betterAuth } from "better-auth"; import { stripe } from "@better-auth/stripe"; export const auth = betterAuth({ plugins: [ stripe({ stripeSecretKey: process.env.STRIPE_SECRET_KEY, stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET, createCustomerOnSignUp: true, subscription: { enabled: true, plans: [/* ... */], }, }), ], }); ``` ## Additional context - **Workaround:** Patching `dist/index.mjs` locally to replace all 3 `customers.search` calls with `customers.list` equivalents works correctly. - The Stripe Search API documentation explicitly lists supported countries: https://docs.stripe.com/search#supported-countries - India is a major market and this blocks all Indian Stripe merchants from using Better Auth's subscription features. - The `customers.list` API is available globally and supports `email` filtering natively. Metadata filtering requires client-side filtering on the result set, but since these queries use `limit: 1`, the data volume is minimal.
GiteaMirror added the plugin label 2026-03-13 10:24:39 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Feb 13, 2026):

Hi @bhagyamudgal! I'm Dosu and I’m helping the better-auth team.

This is a confirmed bug: the unconditional use of Stripe's customers.search API in @better-auth/stripe breaks subscription flows for merchants in India and other unsupported regions, since the Search API is region-restricted and unavailable there. The plugin currently uses customers.search in three places: to find organization customers by metadata, to find user customers by email (excluding orgs), and to find existing customers on signup. All three fail with UNABLE_TO_CREATE_CUSTOMER in unsupported regions, blocking all Indian Stripe merchants from using subscription features.

Switching to customers.list with client-side filtering is a safe and effective fix. customers.list is globally available, supports email filtering natively, and metadata filtering can be done in code on a small result set (limit: 100). This approach is already validated by local patches and is recommended by Stripe's own documentation. There are no technical or performance blockers for this change, and it will not impact other subsystems.

To implement the fix: replace all customers.search calls with customers.list (using email or limit as needed), and filter results in code for metadata matches. The test suite will need to be updated to mock customers.list instead of customers.search and to verify the new filtering logic, but this is straightforward since the tests already mock both methods and do not enforce the use of customers.search specifically.

This issue is critical and should be prioritized, as it blocks a major market. Let me know if you want a code snippet or more details on updating the implementation or tests.

Reference: Stripe Search API region restriction and workaround
Reference: Code and test review confirming fix feasibility

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Feb 13, 2026): <!-- Greeting --> Hi @bhagyamudgal! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a confirmed bug: the unconditional use of Stripe's customers.search API in @better-auth/stripe breaks subscription flows for merchants in India and other unsupported regions, since the Search API is region-restricted and unavailable there. The plugin currently uses customers.search in three places: to find organization customers by metadata, to find user customers by email (excluding orgs), and to find existing customers on signup. All three fail with UNABLE_TO_CREATE_CUSTOMER in unsupported regions, blocking all Indian Stripe merchants from using subscription features. Switching to customers.list with client-side filtering is a safe and effective fix. customers.list is globally available, supports email filtering natively, and metadata filtering can be done in code on a small result set (limit: 100). This approach is already validated by local patches and is recommended by Stripe's own documentation. There are no technical or performance blockers for this change, and it will not impact other subsystems. To implement the fix: replace all customers.search calls with customers.list (using email or limit as needed), and filter results in code for metadata matches. The test suite will need to be updated to mock customers.list instead of customers.search and to verify the new filtering logic, but this is straightforward since the tests already mock both methods and do not enforce the use of customers.search specifically. This issue is critical and should be prioritized, as it blocks a major market. Let me know if you want a code snippet or more details on updating the implementation or tests. [Reference: Stripe Search API region restriction and workaround](https://docs.stripe.com/search#supported-countries) [Reference: Code and test review confirming fix feasibility](https://github.com/better-auth/better-auth/blob/0669ed804d8e0ada004c5ba266a6a12be6557cfc/packages/stripe/test/stripe.test.ts#L148-L5204) <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/0ed5e0d0-5976-4eb5-8330-82c9c3ccab66?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/0ed5e0d0-5976-4eb5-8330-82c9c3ccab66?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/0ed5e0d0-5976-4eb5-8330-82c9c3ccab66?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/0ed5e0d0-5976-4eb5-8330-82c9c3ccab66?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/0ed5e0d0-5976-4eb5-8330-82c9c3ccab66?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/0ed5e0d0-5976-4eb5-8330-82c9c3ccab66?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/0ed5e0d0-5976-4eb5-8330-82c9c3ccab66?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20a%20confirmed%20bug%3A%20the%20unconditional%20use%20of%20Stripe%27s%20customers.search%20API%20in%20%40better-auth/stripe%20breaks%20subscription%20flows%20for%20merchants%20in%20India%20and%20other%20unsupported%20regions%2C%20since%20the%20Search%20API%20is%20region-restricted%20and%20unavailable%20there.%20The%20plugin%20currently%20uses%20customers.search%20in%20three%20places%3A%20to%20find%20organization%20customers%20by%20metadata%2C%20to%20find%20user%20customers%20by%20email%20%28excluding%20orgs%29%2C%20and%20to%20find%20existing%20customers%20on%20signup.%20All%20three%20fail%20with%20UNABLE_TO_CREATE_CUSTOMER%20in%20unsupported%20regions%2C%20blocking%20all%20Indian%20Stripe%20merchants%20from%20using%20subscription%20features.%0A%0ASwitching%20to%20customers.list%20with%20client-side%20filtering%20is%20a%20safe%20and%20effective%20fix.%20customers.list%20is%20globally%20available%2C%20supports%20email%20filtering%20natively%2C%20and%20metadata%20filtering%20can%20be%20done%20in%20code%20on%20a%20small%20result%20set%20%28limit%3A%20100%29.%20This%20approach%20is%20already%20validated%20by%20local%20patches%20and%20is%20recommended%20by%20Stripe%27s%20own%20documentation.%20There%20are%20no%20technical%20or%20performance%20blockers%20for%20this%20change%2C%20and%20it%20will%20not%20impact%20other%20subsystems.%0A%0ATo%20implement%20the%20fix%3A%20replace%20all%20customers.search%20calls%20with%20customers.list%20%28using%20email%20or%20limit%20as%20needed%29%2C%20and%20filter%20results%20in%20code%20for%20metadata%20matches.%20The%20test%20suite%20will%20need%20to%20be%20updated%20to%20mock%20customers.list%20instead%20of%20customers.search%20and%20to%20verify%20the%20new%20filtering%20logic%2C%20but%20this%20is%20straightforward%20since%20the%20tests%20already%20mock%20both%20methods%20and%20do%20not%20enforce%20the%20use%20of%20customers.search%20specifically.%0A%0AThis%20issue%20is%20critical%20and%20should%20be%20prioritized%2C%20as%20it%20blocks%20a%20major%20market.%20Let%20me%20know%20if%20you%20want%20a%20code%20snippet%20or%20more%20details%20on%20updating%20the%20implementation%20or%20tests.%0A%0A%5BReference%3A%20Stripe%20Search%20API%20region%20restriction%20and%20workaround%5D%28https%3A//docs.stripe.com/search%23supported-countries%29%0A%5BReference%3A%20Code%20and%20test%20review%20confirming%20fix%20feasibility%5D%28https%3A//github.com/better-auth/better-auth/blob/0669ed804d8e0ada004c5ba266a6a12be6557cfc/packages/stripe/test/stripe.test.ts%23L148-L5204%29)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/7959)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2867