37

I have stripe check out with php. It creates customers and charges them. I want to create a donation form where if same customer comes back and gives with same email address that Stripe doesn't create another customer but charges the existing customer with additional payments. Is this possible? Or does the checkout always create new customer with new customer id?

Here is my charge.php

<?php
    require_once('config.php');

    $token  = $_POST['stripeToken'];

    if($_POST) {
      $error = NULL;

      try{
        if(!isset($_POST['stripeToken']))
          throw new Exception("The Stripe Token was not generated correctly");
            $customer = Stripe_Customer::create(array(
              'card'  => $token,
              'email' =>  $_POST['stripeEmail'],
              'description' => 'Thrive General Donor'
            ));

            $charge = Stripe_Charge::create(array(
              'customer' => $customer->id,
              'amount'   => $_POST['donationAmount'] * 100,
              'currency' => 'usd'
            ));
      }
      catch(Exception $e) {
        $eror = $e->getMessage();
      }


    }

?>
Thrive Ministry
  • 473
  • 1
  • 4
  • 6
  • can you post some of your code? – Alex Oct 16 '14 at 17:29
  • sure, I just added the charge.php – Thrive Ministry Oct 16 '14 at 18:49
  • 2
    Supposedly you can search by email now, but Stripe still stupidly allows multiple customers with the same email, so we'll need to handle duplicates in the results: https://stackoverflow.com/a/40482496/470749 – Ryan May 25 '17 at 20:13
  • Here you can find explanations about this behavior : https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-customer_creation – Lenor Jun 16 '23 at 14:39

2 Answers2

28

You will need to store the relationship between email address and Stripe customer ID in a database. I've determined this by looking at Stripe's API on Customers.

First, when creating a new customer every field is optional. This leads me to believe that every single time you POST to /v1/customers, it will "[create] a new customer object."

Also, when retrieving a customer the only field available is the id. This leads me to believe that you cannot retrieve a customer based on an email address or other field.


If you can't store this information in a database, you can always list all the customers with GET /v1/customers. This will require you to paginate through and check all customer objects until you find one with a matching email address. You can see how this would be quite inefficient if done every time you tried to create a customer.

Sam
  • 20,096
  • 2
  • 45
  • 71
  • Do you store customer info through webhook and store it in your own database? – Thrive Ministry Oct 16 '14 at 19:22
  • 2
    You could potentially use a webhook; however, I personally save the information as soon as you create the customer object (in your code, `$customer = Stripe_Customer::create(array(...));`). This returns the customer object, from which you can retrieve the Stripe ID to relate in your database to the email address submitted. – Sam Oct 16 '14 at 19:32
  • Is it safe to save the token id from stripe to mysql or any sorts of database during the submit process? or just save customer id to mysql? – Thrive Ministry Oct 16 '14 at 19:41
  • The card token is safe (that is why it was created by Stripe, so "your" server doesn't need to hold/process any actual credit card data) but it is not worth saving as it logically should be attached to a customer. No point in saving the customer ***and*** the card token. – Sam Oct 16 '14 at 19:47
  • Thanks so much Sam. Do you have any sample code from past projects? – Thrive Ministry Oct 16 '14 at 19:48
  • 2
    Let me enhance that last comment with [data from Stripe](https://stripe.com/docs/api#token_object): *"Note that tokens are not meant to be stored or used more than once—to store these details for use later, you should create Customer or Recipient objects"* (not necessarily "insecure", but not "meant" to be stored). – Sam Oct 16 '14 at 19:48
  • Sorry, but nothing I can share. I've only used Stripe in a production project that is under confidentiality. I would recommend the documentation I've been linking to. They have some great examples :) – Sam Oct 16 '14 at 19:49
  • You been a great help! Thanks so much for your time! – Thrive Ministry Oct 16 '14 at 19:54
  • 1
    This can now be done using the List All Customers API here https://stripe.com/docs/api/customers/list by using the `email` parameter. Stripe still allows duplicates, however – Rob Apr 07 '20 at 23:32
  • Now this is possible in Stripe, have a look at this solution I provided with NodeJS https://stackoverflow.com/a/65342417/5391427 – sediq khan Dec 17 '20 at 14:25
6

You can list all users for a given email address. https://stripe.com/docs/api#list_customers

In JavaScript you could do this:

const customerAlreadyExists = (email)=>{
    return  doGet(email)
                .then(response => response.data.length > 0);
}

const doGet = (url: string)=>{
    return fetch('https://api.stripe.com/v1/customers' + '?email=' + email, {
        method: 'GET',
        headers: {
            Accept: 'application/json',
            Authorization: 'Bearer ' + STRIPE_API_KEY
        }
    }).then(function (response) {
        return response.json();
    }).catch(function (error) {
        console.error('Error:', error);
    });
}
Jorciney
  • 674
  • 10
  • 11
  • There is a default limit on listing `all` to `10` and a cap at `100`. This wouldn't actually work. – amarinediary Feb 10 '22 at 17:34
  • This doesn't return values for any customers within Connect sub-accounts – Kemal Ahmed Dec 29 '22 at 23:07
  • @amarinediary It should work for most cases. The docs say `email` is a "filter" but it is really a query applied to the entire result rather than the returned records. It seems very likely there are fewer than 10 customer ids assigned to a single email. – Ford Davis Feb 03 '23 at 20:13