sdieters sdieters - 3 months ago 61
PHP Question

the correct way of sending a stripe token with Android

Lots of info inside!

I am aware there are multiple threads going on about this issue, but non of them are properly answered, and Stripe's own tutorials and references arent much better. so hopefully I (and other) may finaly see the light in this long lasting issue for us hobby developers.

I have been trying to implement Stripe's API for over 2 weeks now, still stuck at the same problem. My Android code is properly working up till the point where I receice my Token back from Stripe.

public class Checkout extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checkout);
}

public void submitCard(View view) throws AuthenticationException {


TextView cardNumberField = (TextView) findViewById(R.id.cardNumber);
TextView monthField = (TextView) findViewById(R.id.month);
TextView yearField = (TextView) findViewById(R.id.year);
TextView cvcField = (TextView) findViewById(R.id.cvc);

Card card = new Card(cardNumberField.getText().toString(), Integer.valueOf(monthField.getText().toString()), Integer.valueOf(yearField.getText().toString()), cvcField.getText().toString());
//Card newCard = new Card("4242 4242 4242 4242", 12, 19, "123");

Stripe stripe = new Stripe("pk_test_key");
stripe.createToken(card, new TokenCallback() {
@Override
public void onError(Exception error) {
//Error
Toast.makeText(getApplicationContext(), error.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}

@Override
public void onSuccess(Token token) {
//send token to server
Toast.makeText(getApplicationContext(), "Succesfully created a token", Toast.LENGTH_LONG).show(); // < this toast works, so my token is fine

DatabaseTask databaseTask = new DatabaseTask("SENDTOKEN", token);
databaseTask.execute();

}
});
}

}


After my token has been created, I start my DatabaseTask which then should send that Token to my server (Currency and Amount are hardcoded in the PHP script atm). This server has a paid SSL certificate, and I am creating a secure connection to my PHP script which should handle the rest.

public class DatabaseTask extends AsyncTask<String, Void, String> {

String command = "";
Token token;

public DatabaseTask(String mCommand, Token mToken){
command = mCommand;
token = mToken;
}

@Override
protected String doInBackground(String... strings) {

String echoData = "";

if (command.equals("SENDTOKEN")) {
try {
URL url = new URL("https://.../StripeConnection.php"); //there is a connection between the code and PHP script. This is tested.
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();


StringBuilder builder = new StringBuilder();
builder.append(URLEncoder.encode("stripeToken", "UTF-8"));
builder.append("=");
builder.append(URLEncoder.encode(token.toString(), "UTF-8"));
String urlParameters = builder.toString();

connection.setRequestMethod("POST");
connection.setDoOutput(true);
DataOutputStream dStream = new DataOutputStream(connection.getOutputStream());

dStream.writeBytes(urlParameters);
dStream.flush();
dStream.close();

BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = "";
StringBuilder responseOutput = new StringBuilder();

while ((line = br.readLine()) != null) {
Log.e("DatabaseTask", line);
responseOutput.append(line);
}
br.close();

echoData = responseOutput.toString();


} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

return echoData;
}

protected void onPostExecute(String mData){
Log.e("DatabaseTask", "onPostExecute result: " + mData);
}


The PHP script this DB task goes for:

<?php

require_once('Stripe/init.php');

\Stripe\Stripe::setApiKey("sk_test_key");

$token = $_POST['stripeToken'];
$price = $_POST['price'];
$description = $_POST['description'];

// Create the charge on Stripe's servers - this will charge the user's card
try {
$charge = Stripe\Charge::create(array(
"amount" => 10000, //"amount" => $price, in cents. //Hardcoded for testing
"currency" => "cny", //Hardcoded for testing
"source" => $token, //Hardcoded for testing
"description" => "omschrijving" //"description" => $description //Hardcoded for testing
));

echo "payment went succesfull";
} catch(\Stripe\Error\Card $e) {
// The card has been declined
echo "card was declined";
}

?>


It seems that it goes wrong somewhere between the moment I execute my DatabaseTask, and the first ECHO in the PHP script, as I never get anything back, except for a huge ERROR message in my console.

08-23 16:04:28.083 20867-20867/... E/DatabaseTask: <br />
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: <b>Fatal error</b>: Uncaught exception 'Stripe\Error\InvalidRequest' with message 'No such token: &lt;com.stripe.android.model.Token@... id=&gt; JSON: { from API request 'req_...'
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;card&quot;: {
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;address_city&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;address_country&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;address_line1&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;address_line2&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;address_state&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;address_zip&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;country&quot;: &quot;US&quot;,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;currency&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;cvc&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;exp_month&quot;: 12,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;exp_year&quot;: 2019,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;fingerprint&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;last4&quot;: &quot;4242&quot;,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;name&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;number&quot;: null,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;type&quot;: null
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: },
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;created&quot;: &quot;Aug 23, 2016 16:04:25&quot;,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;id&quot;: &quot;tok_...&quot;,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;livemode&quot;: false,
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: &quot;used&quot;: false
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: }' in /home/.../Stripe/lib/ApiRequestor.php:108
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: Stack trace:
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: #0 /home...Stripe/lib/ApiRequestor.php(227): Stripe\ApiRequestor-&gt;handleApiError('{\n &quot;error&quot;: {\n...', 400, Array, Array)
08-23 16:04:28.083 20867-20867/... E/DatabaseTask: #1 /home/.../Stripe/lib/ApiRequestor.php(65): Stripe\ApiRequestor-&gt;_interpretRe in <b>/home/.../Stripe/lib/ApiRequestor.php</b> on line <b>108</b><br />
08-23 16:04:28.093 20867-20867/... E/Checkout: <br /><b>Fatal error</b>: Uncaught exception 'Stripe\Error\InvalidRequest' with message 'No such token: &lt;com.stripe.android.model.Token@... id=&gt; JSON: { from API request 'req_...' &quot;card&quot;: { &quot;address_city&quot;: null, &quot;address_country&quot;: null, &quot;address_line1&quot;: null, &quot;address_line2&quot;: null, &quot;address_state&quot;: null, &quot;address_zip&quot;: null, &quot;country&quot;: &quot;US&quot;, &quot;currency&quot;: null, &quot;cvc&quot;: null, &quot;exp_month&quot;: 12, &quot;exp_year&quot;: 2019, &quot;fingerprint&quot;: null, &quot;last4&quot;: &quot;4242&quot;, &quot;name&quot;: null, &quot;number&quot;: null, &quot;type&quot;: null }, &quot;created&quot;: &quot;Aug 23, 2016 16:04:25&quot;, &quot;id&quot;: &quot;tok_...&quot;, &quot;livemode&quot;: false, &quot;used&quot;: false}' in /home/.../Stripe/lib/ApiRequestor.php:108Stack trace:#0 /home/.../Stripe/lib/ApiRequestor.php(227): Stripe\ApiRequestor-&gt;handleApiError('{\n &quot;error&quot;: {\n...', 400, Array, Array)#1 /home/.../Stripe/lib/ApiRequestor.php(65): Stripe\ApiRequestor-&gt;_interpretRe in <b>/home/.../Stripe/lib/ApiRequestor.php</b> on line <b>108</b><br />


(links, ID's, tokens and other personal stuff is replaced with ...)

So I have tried pretty much everything I could find online about the message "No such Token: ", but to no avail.

What did I check:
- Both my keys are ok, no missmatch here
- There is a proper connection between my app and my PHP script
- The token is created properly and verified by Stripe
- My server has a paid SSL certificate and made a secure connection with HttpsURLConnection

What have I tried:
- refreshed the keys over and over again
- sending my token as a string in a POST method
- tried sending my token as a JSONtoken (never got it to work) > Passing Stripe tokens to server and handling on server
- took the POST method outside the asyncTask (read that it wasnt needed)
- re-read the entire documentation of Stripe over and over again > https://stripe.com/docs/mobile/android
- discected the example project over and over again > https://github.com/stripe/stripe-android/tree/master/example
- searched for video tutorials, but only found tutorials for integration on websites
- searched for online courses, again only for web integration

So now I really wanna know what Stripe means with this seamingly impossible task:


Set up an endpoint on your server that can receive an HTTP POST call
for the token. In the onActivityResult method (for Android Pay) or the
onSuccess callback (when using your own form), you’ll need to POST the
supplied token to your server. Make sure any communication with your
server is SSL secured to prevent eavesdropping.


If you need any more information, please dont hesitate to ask, because this is the last step to finishing my first proper application. Also, please keep in mind that I have gathered all my knowledge over the past 3 years by trail and error, and even though I know quite some things, I might miss out on some basic knowledge.

Thanks.

Answer

The error here is that instead of passing the token id tok_XXX you pass the entire Token object you got back from Stripe's SDK. The request then fails with the error

Uncaught exception 'Stripe\Error\InvalidRequest' with message 'No such token: <com.stripe.android.model.Token@... id=> JSON: { from API request 'req_...'

You need to change your code to send the token id instead to your PHP script which should fix the issue.

builder.append(URLEncoder.encode(token.getId(), "UTF-8"));