0
votes

I am trying to create a new Stripe customer by sending the required information to Stripe through a Parse Cloud Code function. My methods are as follows:

Android:

private void createCustomer(Token token) {
    String token3 = token.getId();

    Map<String, Object> params = new HashMap<>();
    params.put("email", username);
    params.put("source", token3);
    params.put("name", firstName);
    params.put("objectId", parseID);
    params.put("description", "myExample customer");

    Log.e("createCustomer method", "about to call cloud code function with " + token.getId());
    ParseCloud.callFunctionInBackground("createCustomer", params, new FunctionCallback<Object>() {
        @Override
        public void done(Object object, ParseException e) {
            if (e == null) {
                Toast.makeText(SignUpActivity.this, object.toString(), Toast.LENGTH_LONG).show();
            } else {
                Log.e("createCustomer method", e.toString());
            }
        }
    });

}

And the Cloud Code that my method calls to:

var Stripe = require('stripe');
Stripe.initialize(STRIPE_SECRET_KEY);

Parse.Cloud.define("createCustomer", function(request, response) { 

    Stripe.Customers.create({
		card: request.params.token,
        description: request.params.description,
        metadata: {
            name: request.params.name,
            userId: request.params.objectId, // e.g PFUser object ID
        }
    }, {
        success: function(httpResponse) {
            response.success(customerId); // return customerId
        },
        error: function(httpResponse) {
            console.log(httpResponse);
            response.error("Cannot create a new customer.");
        }
    });
});

When I do this it calls to the Cloud Code just fine, but it triggers the error response "Cannot create a new customer".

If I try to send the token directly (instead of getting the ID value as a string) and send it that way, like so:

private void createCustomer(Token token) {
    //String token3 = token.getId();
    Map<String, Object> params = new HashMap<>();
    params.put("email", username);
    params.put("source", token);
    params.put("name", firstName);
    params.put("objectId", parseID);
    params.put("description", "myExample customer");

    Log.e("createCustomer method", "about to call cloud code function with " + token.getId());
    ParseCloud.callFunctionInBackground("createCustomer", params, new FunctionCallback<Object>() {
        @Override
        public void done(Object object, ParseException e) {
            if (e == null) {
                Toast.makeText(SignUpActivity.this, object.toString(), Toast.LENGTH_LONG).show();
            } else {
                Log.e("createCustomer method", e.toString());
            }
        }
    });
}

It returns this error:

01-12 07:31:27.999 16953-16953/com.stripetestapp.main E/createCustomerMethod: com.parse.ParseException: java.lang.IllegalArgumentException: invalid type for ParseObject: class com.stripe.android.model.Token

So from the above error I understand that sending the pure token is creating an error, however if I send the token ID in its place it also triggers an error (though a different one). I can't help but think that I am missing something obvious here.

EDIT: I've tried to convert the token to a String as shown below:

    String token3 = token.toString();
    Map<String, Object> params = new HashMap<>();
    params.put("source", token3);

and it still responds with the error response "Cannot create a new customer".

EDIT2: The console.log for the cloud code method createCustomer:

E2016-01-12T21:09:54.487Z]v13 Ran cloud function createCustomer for user 1xjfnmg0GN with: Input: {"description":"myExample customer","email":"[email protected]","name":"hff","objectId":"1xjfnmg0GN","token":"\u003ccom.stripe.android.model.Token@1107376352 id=\u003e JSON: {\n \"card\": {\n \"address_city\": null,\n \"address_country\": null,\n \"address_line1\": null,\n \"address_line2\": null,\n \"address_state\": null,\n \"address_zip\": null,\n \"country\": \"US\",\n \"cvc\": null,\n \"exp_month\": 2,\n \"exp_year\": 2019,\n \"fingerprint\": null,\n \"last4\": \"4242\",\n \"name\": null,\n \"number\": null,\n \"type\": null\n },\n \"created\": \"Jan 12, 2016 1:09:53 PM\",\n \"id\": \"tok_17SZOnJQMWHHKlPAwdveiUde\",\n \"livemode\": false,\n \"used\": false\n}"} Result: Cannot create a new customer. I2016-01-12T21:09:55.274Z]{"name":"invalid_request_error"}

EDIT3: It was suggested to change 'source' to 'token' and send the tokenId instead of the token.toString, which worked. I did have to change one other line in my cloud code, changing:

success: function(httpResponse) {
        response.success(customerId); // return customerId

to

success: function(httpResponse) {
        response.success(httpResponse); // return customerId

and it worked exactly as required.

1
params.put("source", token); => try converting the Token to a String. Parse does not know how to accept the Token objectOneCricketeer
i've edited my post with your suggestionBlaasd
That is your error response, not the actual response. Where does console.log(httpResponse); show up for that Stripe method?OneCricketeer
I've added it to my post i see a {"name:invalid_request_error"}?Blaasd
According to the documentation - "Invalid request errors arise when your request has invalid parameters", so your parameters for card, description, and metadata aren't right.OneCricketeer

1 Answers

2
votes

Error 1

Parse only know how to save certain Java datatypes (String, int, boolean, etc.), so this error message

com.parse.ParseException: java.lang.IllegalArgumentException: invalid type for ParseObject: class com.stripe.android.model.Token

Is referring to this code

private void createCustomer(Token token) {
    Map<String, Object> params = new HashMap<>();
    params.put("source", token);

Solution: Store the token object differently


Error 2

The Stripe API expects certain parameters and will throw an invalid_request_error when your request has invalid parameters.

Result: Cannot create a new customer.
{"name":"invalid_request_error"}`

The reason it you have invalid parameters is because your Java code is putting a "source" key into the param map (same code as above), but the JavaScript is expecting a key of "token" in this code

Stripe.Customers.create({
    card: request.params.token,

Solution: Either rename the "source" key in Java to "token" or rename the value in JavaScript from request.params.token to request.params.source.


Combination of Solutions

Once Error 2 is fixed, you still need to solve Error 1. As I suggested in the comments above, you should just store the ID of the Token in Parse. When you need the Stripe customer object, query the Stripe API for it using the ID. Otherwise, you are duplicating the data.

To do that, if you renamed "source" to "token" in Java, you can do this

private void createCustomer(Token token) {
    Map<String, Object> params = new HashMap<>();
    params.put("token", token.getId());