i have integrated coinbase api in my web app. When charge is created, users are directed to coinbase commerce website to make payment. How do i check if the user has finished paying or not and if the exact amount has been paid. Below is my code
<?php
require_once __DIR__ . "/vendor/autoload.php";
use CoinbaseCommerce\ApiClient;
use CoinbaseCommerce\Resources\Charge;
/**
* Init ApiClient with your Api Key
* Your Api Keys are available in the Coinbase Commerce Dashboard.
* Make sure you don't store your API Key in your source code!
*/
ApiClient::init("MY API KEY HERE");
$chargeObj = new Charge();
$chargeObj->name = 'Bitcoin Deposit';
$chargeObj->description = 'Testing the payment system';
$chargeObj->local_price = [
'amount' => '100.00',
'currency' => 'USD'
];
$chargeObj->pricing_type = 'fixed_price';
try {
$chargeObj->save();
// insert into database with status pending
$queryobject->insertTransaction($_SESSION['user_id'],$chargeObj->id, $amount, $status, $currentTime,
$chargeObj->name, $chargeObj->currency);
} catch (\Exception $exception) {
echo sprintf("Sorry! payment could not be created. Error: %s \n", $exception->getMessage());
}
if ($chargeObj->id) {
$chargeObj->description = "New description";
// Retrieve charge by "id"
try {
$retrievedCharge = Charge::retrieve($chargeObj->id);
$hosted_url = $retrievedCharge->hosted_url;
header('location: '.$hosted_url);
} catch (\Exception $exception) {
echo sprintf("Enable to retrieve charge. Error: %s \n", $exception->getMessage());
}
}
You need to use webhooks for this, you can create an endpoint for this. Unfortunately Coinbase does not have a sandbox environment so you are going to need a bit of cryptocurrency in your account.
Related
I have two questions, first about the error, Laravel 8.20.1 + Paypal SDK v1.
App Routes:
Route::get('/agreement/execute', [PaymentController::class, 'agreementExecute']);
Route::post('/agreement/create', [PaymentController::class, 'subscribeMonthly']);
Admin Routes:
Route::prefix('paypal')->name('plan.')->group(function () {
Route::get('/monthly/create', [PrivatePaypal::class, 'createMonthly'])
Route::get('/list', [PrivatePaypal::class, 'showPlans'])
Route::get('/plan/{plan}', [PrivatePaypal::class, 'plan'])
Route::get('/delete', [PrivatePaypal::class, 'deletePlan'])
});
Created plan:
Created plan image
Plan code:
public function createMonthly() {
$plan = new \PayPal\Api\Plan();
$plan->setName('Monthly')
->setDescription('Activate partnership for one month.')
->setType('INFINITE'); // or FIXED: The plan has a fixed number of payment cycles
$paymentDefinition = new \PayPal\Api\PaymentDefinition();
$paymentDefinition->setName('Monthly Payments')
->setType('REGULAR') // or TRIAL
->setFrequency('Month') // or WEEK, DAY, YEAR, MONTH
->setFrequencyInterval("1") // The interval at which the customer is charged. Value cannot be greater than 12 months
->setAmount(new \PayPal\Api\Currency(array('value' => 20, 'currency' => 'USD')));
// ->setCycles("12")
$merchantPreferences = new \PayPal\Api\MerchantPreferences();
$merchantPreferences->setReturnUrl(route('account.agreement',['success'=>'true']))
->setCancelUrl(route('account.agreement',['success'=>'false']))
->setAutoBillAmount("yes")
->setInitialFailAmountAction("CONTINUE")
->setMaxFailAttempts("0")
->setSetupFee(new \PayPal\Api\Currency(array('value' => config('settings.price_monthly'), 'currency' => 'USD')))
;
$plan->setPaymentDefinitions(array($paymentDefinition));
$plan->setMerchantPreferences($merchantPreferences);
try {
$createdPlan = $plan->create($this->apiContext);
} catch(\Exception $ex) {
print_r($ex->getMessage());
die();
}
// dd($createdPlan);
$this->activatePlan($createdPlan);
}
After I send data with the form
<form action="https://site.test/agreement/create" method="post">
<input type="hidden" name="_token" value="XSM2gxx0Cqs5dlloYScQfl2GdeGqrz4lkWLfm42a">
<input type="hidden" name="_method" value="POST">
<input type="hidden" name="id" value="P-0UV961714R317531UT5H72WI">
<button class="button compact">Activate</button>
</form>
After succesful redirect to paypal with all data, i click accept (sandbox) and after that i get succesfull rerict back, redirect functions:
if (!empty($request->input('success')))
{
$success = $request->input('success');
if ($success && !empty($request->input('token')))
{
$token = $request->input('token');
$agreement = new \PayPal\Api\Agreement();
try {
// Execute agreement
$agreement->execute($token, $this->apiContext);
} catch (PayPal\Exception\PayPalConnectionException $ex) {
print_r($ex->getMessage());
echo $ex->getCode();
echo $ex->getData();
print_r($ex->getData());
die($ex);
} catch (Exception $ex) {
// die($ex);
}
And when $agreement->execute runs I get errors with no detailed information.
Form subscribe function:
public function subscribeMonthly(Request $request) {
$id = $request->id;
$agreement = new \PayPal\Api\Agreement();
$agreement->setName('Monthly subscription')
->setDescription('Activate partnership for one month.')
->setStartDate(Carbon::now()->addMonth()->toIso8601String());
$plan = new \PayPal\Api\Plan();
$plan->setId($id);
$agreement->setPlan($plan);
$payer = new \PayPal\Api\Payer();
$payer->setPaymentMethod('paypal');
$agreement->setPayer($payer);
try {
$agreement = $agreement->create($this->apiContext);
$approvalUrl = $agreement->getApprovalLink();
} catch(\Exception $ex) {
print_r($ex->getMessage());
die();
}
return redirect($approvalUrl);
}
Error is : PayPal\Exception\PayPalConnectionException
Got Http response code 400 when accessing https://api.sandbox.paypal.com/v1/payments/billing-agreements/EC-1LE052463N345662M/agreement-execute.
https://am.test/account/agreement?ba_token=BA-9X735270PX851462W&success=true&token=EC-1LE052463N345662M
I reviewed a lot of tutorials, re-read the code in PayPal guides several times. I'm new to this and can't figure out what the reason is, it just doesn't work for me. I do everything one to one.
No subscriptions are created in the buyer account or by the administrator, everything is empty.
And the second question, Paypal writes that v1 is deprecated. How can I use the second version with a checkout v2 for subscriptions and where can I find detailed guides with the Laravel about this question.
It's hard for me to fully understand API and code not created by myself, I create a big project on my own, but stuck a few days with that PayPal error. Thank you for reading so much of what I have written, I hope for your support.
The PayPal-PHP-SDK is deprecated, and not compatible with the current version of PayPal Subscriptions. You should not be using it for anything.
Instead, integrate directly with the necessary Product, Plan, and subscription management API calls described in that Subscriptions documentation. (Plus webhooks, if desired--to be notified of future subscription events)
You can also manage Products and Plans manually in the receiver account:
Sandbox: https://www.sandbox.paypal.com/billing/plans
Live: https://www.paypal.com/billing/plans
I am setting up a small Slim 3 application which will be the middleman for processing Web based Stripe payment form. The Slim application will handle the business logic of reaching out to Stripe and conducting the payment, as well as sending the payment data off to some third-party CRM / Applications.
My issue during testing is that when i make a test payment through the StripeJS payment form the slim application is actually logging 3 duplicate requests 1-second apart. Here's what the logging looks like:
test#gmail.com Attempting to make payment 2020-04-27 05:34:39
test#gmail.com Attempting to make payment 2020-04-27 05:34:40
test#gmail.com Attempting to make payment 2020-04-27 05:34:41
test#gmail.com Payment success 2020-04-27 05:34:44
test#gmail.com Payment success 2020-04-27 05:34:45
test#gmail.com Payment success 2020-04-27 05:34:47
This is all from an individual "payment" using the Stripe Test credentials.
The Slim layout is fairly straightforward in terms of the route passing the request directly to my StripeController class. The StripeController class ( in development ) will take the values of the request and pass it to the Stripe API to conduct the payment.
The route layout:
$this->post('/stripe-payment', 'StripeController:stripePayment');
The controller (stripped to essentials for privacy ):
class StripeController extends Controller
{
private $privateKey;
private $httpClient;
public function __construct() {
$this->privateKey = getenv('STRIPE_KEY');
$this->httpClient = new Client();
\Stripe\Stripe::setApiKey($this->privateKey);
}
//
public function stripePayment($request, $response)
{
// Get the request body
$r = (object)$request->getParsedBody();
// Initial Logging
$log = new LogController($r->email_address, 'Attempting to make payment');
$log->saveLog();
// Attempt to find an existing user
$user = User::where('email', $r->email_address)->first();
if($user !== null) {
// If user exists, use their StripeID
$invoice = $this->stripeInvoice($r, $user->stripe_id);
// Log the transaction
$this->savePayment( $user->id, 'stripe-invoice', $invoice->id, $invoice->amount_paid );
// Third party application push
$this->pushUser($r, $invoice->amount_paid);
// Return with success
return $response->withRedirect('example.com/payment-success/');
} else {
// Same as above, just create a user then push.
}
}
public function stripeInvoice(object $r, string $stripe_id)
{
// Try to create the invoice in stripe
try {
\Stripe\InvoiceItem::create([
'customer' => $stripe_id,
'amount' => (int)$r->product,
'currency' => 'USD',
'description' => $plan_desc
]);
} catch ( Exception $e ) {
error_log('STRIPE_INVOICE_EXCEPTION: '.$e->getMessage());
}
// Try to charge the customer the invoice we just created
try {
$invoice = \Stripe\Invoice::create([
'customer' => $stripe_id
]);
$_get_invoice = \Stripe\Invoice::retrieve($invoice->id);
$_get_invoice->pay();
$success = 1;
// Use Stripe's library to make requests...
} catch(\Stripe\Exception\CardException $e) {
$error = $e->getMessage();
// Since it's a decline, \Stripe\Exception\CardException will be caught
} catch (\Stripe\Exception\RateLimitException $e) {
$error = $e->getMessage();
// Too many requests made to the API too quickly
} catch (\Stripe\Exception\InvalidRequestException $e) {
$error = $e->getMessage();
// Invalid parameters were supplied to Stripe's API
} catch (\Stripe\Exception\AuthenticationException $e) {
$error = $e->getMessage();
// Authentication with Stripe's API failed
// (maybe you changed API keys recently)
} catch (\Stripe\Exception\ApiConnectionException $e) {
$error = $e->getMessage();
// Network communication with Stripe failed
} catch (\Stripe\Exception\ApiErrorException $e) {
$error = $e->getMessage();
// Display a very generic error to the user, and maybe send
// yourself an email
} catch (Exception $e) {
// Something else happened, completely unrelated to Stripe
$error = $e->getMessage();
}
if($success != 1) {
return $response->withRedirect('example.com&error='.$error);
} else {
return $_get_invoice;
}
}
}
Is there anything that Slim is doing in the background, like an origin check, that could be causing the duplication issue ?
I'm trying to create a payment with Omnipay and Mollie in my Laravel project. I'm using the following 2 libraries:
https://github.com/barryvdh/laravel-omnipay
https://github.com/thephpleague/omnipay-mollie
I'm doing the following in my code:
$gateway = Omnipay\Omnipay::create('Mollie');
$gateway->setApiKey('test_gSDS4xNA96AfNmmdwB3fAA47zS84KN');
$params = [
'amount' => $ticket_order['order_total'] + $ticket_order['organiser_booking_fee'],
'description' => 'Bestelling voor klant: ' . $request->get('order_email'),
'returnUrl' => URL::action('EventCheckoutController#fallback'),
];
$response = $gateway->purchase($params)->send();
if ($response->isSuccessful()) {
session()->push('ticket_order_' . $event_id . '.transaction_id',
$response->getTransactionReference());
return $this->completeOrder($event_id);
}
The payment works. When the payment is done he goes back to the function fallback. But I don't know what to put in this function and how to go back to the line if($response->isSuccesfull()...).
The most important thing I need to do after the payment is :
session()->push('ticket_order_' . $event_id . '.transaction_id',
$response->getTransactionReference());
return $this->completeOrder($event_id);
Can someone help me figure out how to work with the fallback function and above?
A typical setup using Mollie consists of three separate pages:
a page to create the payment;
a page where Mollie posts the final payment state to in the background; and
a page where the consumer returns to after the payment.
The full flow is described in the Mollie docs. Also take a look at the flow diagram at that page.
DISCLAIMER: I've never used Omnipay myself and did not test the following code, but it should at least give you an idea how to set up your project.
Creating the payment:
$gateway = Omnipay\Omnipay::create('Mollie');
$gateway->setApiKey('test_gSDS4xNA96AfNmmdwB3fAA47zS84KN');
$params = [
'amount' => $ticket_order['order_total'] + $ticket_order['organiser_booking_fee'],
'description' => 'Bestelling voor klant: ' . $request->get('order_email'),
'notifyUrl' => '', // URL to the second script
'returnUrl' => '', // URL to the third script
];
$response = $gateway->purchase($params)->send();
if ($response->isRedirect()) {
// Store the Mollie transaction ID in your local database
store_in_database($response->getTransactionReference());
// Redirect to the Mollie payment screen
$response->redirect();
} else {
// Payment failed: display message to the customer
echo $response->getMessage();
}
Receiving the webhook:
$gateway = Omnipay\Omnipay::create('Mollie');
$gateway->setApiKey('test_gSDS4xNA96AfNmmdwB3fAA47zS84KN');
$params = [
'transactionReference' => $_POST['id'],
];
$response = $gateway->fetchTransaction($params);
if ($response->isPaid()) {
// Store in your local database that the transaction was paid successfully
} elseif ($response->isCancelled() || $response->isExpired()) {
// Store in your local database that the transaction has failed
}
Page where the consumer returns to:
// Check the payment status of your order in your database. If the payment was paid
// successfully, you can display an 'OK' message. If the payment has failed, you
// can show a 'try again' screen.
// Most of the time the webhook will be called before the consumer is returned. For
// some payment methods however the payment state is not known immediately. In
// these cases you can just show a 'payment is pending' screen.
hi i am using stripe api for payment using this tutorial
http://code.tutsplus.com/tutorials/so-you-want-to-accept-credit-cards-online--net-25457
But i am getting this error
pay.php 500 (Internal Server Error)
here it is pay.php code
<?php
// Helper Function: used to post an error message back to our caller
function returnErrorWithMessage($message)
{
$a = array('result' => 1, 'errorMessage' => $message);
echo json_encode($a);
}
// Credit Card Billing
require_once('Stripe.php'); // change this path to wherever you put the Stripe PHP library!
$trialAPIKey = ""; // These are the SECRET keys!
$liveAPIKey = "";
Stripe::setApiKey($trialAPIKey); // Switch to change between live and test environments
// Get all the values from the form
$token = $_POST['stripeToken'];
$email = $_POST['email'];
$firstName = $_POST['firstName'];
$lastName = $_POST['lastName'];
$price = $_POST['price'];
$priceInCents = $price * 100; // Stripe requires the amount to be expressed in cents
try
{
// We must have all of this information to proceed. If it's missing, balk.
if (!isset($token)) throw new Exception("Website Error: The Stripe token was not generated correctly or passed to the payment handler script. Your credit card was NOT charged. Please report this problem to the webmaster.");
if (!isset($email)) throw new Exception("Website Error: The email address was NULL in the payment handler script. Your credit card was NOT charged. Please report this problem to the webmaster.");
if (!isset($firstName)) throw new Exception("Website Error: FirstName was NULL in the payment handler script. Your credit card was NOT charged. Please report this problem to the webmaster.");
if (!isset($lastName)) throw new Exception("Website Error: LastName was NULL in the payment handler script. Your credit card was NOT charged. Please report this problem to the webmaster.");
if (!isset($priceInCents)) throw new Exception("Website Error: Price was NULL in the payment handler script. Your credit card was NOT charged. Please report this problem to the webmaster.");
try
{
// create the charge on Stripe's servers. THIS WILL CHARGE THE CARD!
$charge = Stripe_Charge::create(array(
"amount" => $priceInCents,
"currency" => "usd",
"card" => $token,
"description" => $email)
);
// If no exception was thrown, the charge was successful!
// Here, you might record the user's info in a database, email a receipt, etc.
// Return a result code of '0' and whatever other information you'd like.
// This is accessible to the jQuery Ajax call return-handler in "buy-controller.js"
$array = array('result' => 0, 'email' => $email, 'price' => $price, 'message' => 'Thank you; your transaction was successful!');
echo json_encode($array);
}
catch (Stripe_Error $e)
{
// The charge failed for some reason. Stripe's message will explain why.
$message = $e->getMessage();
returnErrorWithMessage($message);
}
}
catch (Exception $e)
{
// One or more variables was NULL
$message = $e->getMessage();
returnErrorWithMessage($message);
}
?>
even i can't access strip's php files.
Please any idea?
Thanks
I'm sure I'm missing something obvious here, but I can't get my head around how to check for an existing card against a customer.
I'm using the stripe connect api within an laravel app to manage payments on behalf of others, and the basic process is as follows:
a stripe token is created via stripe.js and submitted with the payment form
if the customer exists in the local database, I grab their stripe_id, otherwise a new customer is created using the token as the source/card
a charge is then created using the retrieved or new customer stripe_id
Currently, if the customer returns and uses a different card, as the charge only includes a customer, not source, it'll be charged against their default card regardless.
What I'd like to do is:
create a stripe token
check customer against local database etc
check card fingerprint against customer's cards
if necessary, create new card on customer's record
create charge using both customer and card ids
Simply put: I can't see where in the process a persistent card_id is generated; both those used in the stripe.js response, and when created in the stripe dashboard, appear to be unique, meaning every charge creates a brand-new card object in stripe.
I know I can retrieve a list of cards stored against a customer's account - but where do I get the initial card_id from to search against?
I've seen a question that touches on this here - Can I check whether stripe a card is already existed before going to create new one? - but I don't know Ruby, so can't make head nor tail of it.
EDIT:
Simpler version - is there a way to get the fingerprint as described in the stripe docs here - https://stripe.com/docs/api/php#card_object - without having to first create a card object ?
So the idea here would be to use the fingerprint on the Card object or the Token object and not the id itself as those would be different if you add the same card multiple times.
When you get a new card token you can retrieve it through the Retrieve Token API and look for the fingerprint in the card hash.
You would keep a list of known fingerprints in your database associated with a specific customer and/or card so that you can detect duplicate cards.
NOTE: make sure you are using the secret keys to get those information. otherwise if you are using the publishable key, you might not get the fingerprint value.
I created a function to do this:
$customer is the stripe customer object
$stripe_account is either your account's stripe ID or the connected account's stripe ID
$token comes from stripe.js elements
$check_exp allows you to decide if you want to check the card's expiration date as well, because the fingerprint does not change if the card's number is the same
stripe PHP API 7.0.0
function check_duplicate_card($customer, $stripe_account, $token, $check_exp) {
$loc = "check_duplicate_card >> ";
$debug = true;
if ($debug) {
// see here for an explanation for logging: http://php.net/set_error_handler >> Examples
trigger_error("$loc started", E_USER_NOTICE);
}
try
{
// get token data
$response = \Stripe\Token::retrieve(
$token,
["stripe_account" => $stripe_account]
);
$token_fingerprint = $response->card->fingerprint;
$token_exp_month = $response->card->exp_month;
$token_exp_year = $response->card->exp_year;
if ($debug) {
trigger_error("$loc token_fingerprint = $token_fingerprint; token_exp_month = $token_exp_month; token_exp_year = $token_exp_year", E_USER_NOTICE);
}
// check for duplicate source
if ($debug) {
trigger_error("$loc customer sources = " . json_encode($customer->sources), E_USER_NOTICE);
}
$duplicate_found = false;
foreach ($customer->sources->data as &$value) {
// get data
$fingerprint = $value->fingerprint;
$exp_month = $value->exp_month;
$exp_year = $value->exp_year;
if ($fingerprint == $token_fingerprint) {
if ($check_exp) {
if (($exp_month == $token_exp_month) && ($exp_year == $token_exp_year)) {
$duplicate_found = true;
break;
}
} else {
$duplicate_found = true;
break;
}
}
}
if ($debug) {
trigger_error("$loc duplicate_found = " . json_encode($duplicate_found), E_USER_NOTICE);
}
} catch (Exception $e) {
if ($e instanceof \Stripe\Exception\ApiErrorException) {
$return_array = [
"status" => $e->getHttpStatus(),
"type" => $e->getError()->type,
"code" => $e->getError()->code,
"param" => $e->getError()->param,
"message" => $e->getError()->message,
];
$return_str = json_encode($return_array);
trigger_error("$loc $return_str", E_USER_WARNING);
http_response_code($e->getHttpStatus());
echo $return_str;
} else {
$return_array = [
"message" => $e->getMessage(),
];
$return_str = json_encode($return_array);
trigger_error("$loc $return_str", E_USER_ERROR);
http_response_code(500); // Internal Server Error
echo $return_str;
}
}
if ($debug) {
trigger_error("$loc ended", E_USER_NOTICE);
}
return $duplicate_found;
}