Getting Started
YouCan Pay offers an easy way to receive credit card payment in your application. In this guide we'll see how to get started quickly. To follow along, you need to have an account in YouCan Pay for integration keys.
YouCan Pay SDK: https://github.com/youcan-shop/youcan-payment-php-sdk
Private and Public keys
pri_xxx
and pub_xxx
to help distinguish between the two.
Be careful, your private key should never be exposed or shared with anyone.
Payment Flow
To better understand the payment flow, the diagram on the right illustrates the different steps to complete a payment by your customer through YouCan Pay.
When the customer arrive to the payment page, and you want to display the YouCan Pay form you need to generate a token for the current transaction. This token will allow you encapsulate you order info (amount, currency, order ID, etc)
In this step, you include the JS and HTML for display for credit card form where the user will input his card info.
When the customer click on the pay button, a request will be sent to YouCan Pay server to process the payment. If the customer card has 3DS enabled, he will be redirected to the bank page to validate the transaction and come back to YouCan Pay server. If the customer card doesn't have 3DS enabled, YouCan Pay will process the transaction directly.
When the transaction is processed the customer will be redirected to your application.
Depending on the transaction status (success/error)
it will redirect to the endpoint you defined.
Tokenization
The tokenization is the process of generating a token for your current transaction. This token will hold you order data (order ID, amount, currency). The amount should be in smallest currency unit (e.g., 100 cents to charge $1.00) Since this process is critical, it should be done in your backend using our SDK.
Identifier of the order you want to be paid.
Integer amount: The amount, Example: 25 USD is 2500.
Currency: Uppercase currency.
Customer Address IP
This URL is returned when the payment is successfully processed.
This URL is returned when payment is invalid.
Data of the customer who wishes to make this purchase.
You can use it to send data to retrieve after the response or in the webhook.
composer require youcanpay/payment-sdk
use YouCan\Pay\YouCanPay;
$youCanPay = YouCanPay::instance()->useKeys('pri_key', 'pub_key');
// Data of the customer who wishes to make this purchase.
$customerInfo = [
'name' => '',
'address' => '',
'zip_code' => '',
'city' => '',
'state' => '',
'country_code' => '',
'phone' => '',
'email' => '',
];
$metadata = [
// Can you insert what you want here...
//'key' => 'value'
];
// generate a token for a new payment
$token = $youCanPay->token->create(
"order-id",
"2000",
"USD",
"123.123.123.123",
"https://yourdomain.com/orders-status/success",
"https://yourdomain.com/orders-status/failed",
$customerInfo,
$metadata
);
echo $token->getId();
Creating an instance of YCPay
The first step is to include the YouCan Pay JS code in your markup.
When the code is loaded, we're ready to render the payment form using the code snippet on the right.
The seller's YouCanPay account public key. This lets us know who is receiving the payment.
Extra configuration options to tailor the integration to your needs.
The CSS selector for the container in which we will render the integration. If no container is found, the integration won't render.
The language in which to display the forms and error messages. Currently supports en, ar, and fr. If no locale is specified, it will be automatically inferred from the browser or fall back to en as a default locale.
Specified whether or not to run the integration in Sandbox Mode, this is useful for testing your integration. It is recommended to set this to false or omit it entirely in production, as it is false by default.
The CSS selector for the container in which we will all errors related to the usage of the integration. This is set to "#ycp-error-container" by default. If no container is found, no errors will be displayed.
CSS code to style the integration to your liking.
In case you a single static payment token, you can pass it here in the constructor. By doing so you can not pass it down to the ".pay()" method. Token can be updated using the ".setToken()" method.
<script src="https://youcanpay.com/js/ycpay.js"></script>
<div id="error-container"></div>
<div id="payment-container"></div>
<button id="pay">Pay</button>
<script type="text/javascript">
const ycPay = new YCPay('pub_key', {
formContainer: '#payment-container',
locale: 'en',
isSandbox: false,
errorContainer: '#error-container',
customCSS: '',
token: 'token_x6gf0_....'
});
</script>
Form Display
The next step is to render the form in your markup, this is done by using one of the render
methods
that the instantiated ycPay
object provides.
Renders the Credit Card form. Takes in an optional theme parameter.
Renders the CashPlus form. Takes in an optional theme parameter.
Takes in an array of gateway names as an additional parameters, current supported gateways are "CashPlus", "CreditCard". If an empty array is provided, renders all available gateways for the account. Takes in an optional theme parameter.
renderAvailableGateways()
method.
If only a single gateway is available, it will be rendered directly without prompting the user to pick a method.
In some cases you might want to refresh the visuals of the form once the payment is done, or perhaps for another use case of yours, for that, this method allows you to do just that.
When setting the token from the constructor, you are kind of limited on how you want to handle your payment especially if your token gets updated regularly and you don't have the ability to set it via the ".pay()" method. In that case, you utilize this method to update it, guaranteeing your token always being updated.
<script src="https://youcanpay.com/js/ycpay.js"></script>
<div id="error-container"></div>
<div id="payment-container"></div>
<button id="pay">Pay</button>
<script type="text/javascript">
const ycPay = new YCPay('pub_key', {
locale: 'en',
isSandbox: false,
errorContainer: '#error-container',
formContainer: '#payment-container'
});
// render the payment methods
ycPay.renderAvailableGateways([], 'default')
</script>
Start Payment
The tokenId
on line 11 is the one generated in the tokenization section.
The successCallback is called when the transaction is successful,
and you get the final transaction ID that you can submit with your order details.
Similarly, errorCallback is called with an error occur during the payment,
and you get the error message as a parameter to show to customer.
Congrats, now you're ready to accept payments from customers using YouCan Pay π.
<script type="text/javascript">
const ycPay = new YCPay('pub_key', {
formContainer: '#payment-container',
});
// render the form
ycPay.renderCreditCardForm();
// start the payment on button click
document.getElementById('pay').addEventListener('click', function() {
// execute the payment
ycPay.pay(tokenId)
.then(successCallback)
.catch(errorCallback);
})
function successCallback(response) {
//your code here
}
function errorCallback(response) {
//your code here
}
</script>
Payment Processed
Once the payment is done,
you can get the details of the transaction in your backend to validate the amount, order ID, etc.
When the payment is proceeded by a Moroccan card, the transaction currency is converted to MAD.
You can get the submitted original amount and currency from
getBaseAmount()
, getBaseCurrency()
in the Transaction
object.
use YouCan\Pay\YouCanPay;
$youCanPay = YouCanPay::instance()->useKeys('pri_key', 'pub_key');
$transaction = $youCanPay->transaction->get("transaction-id");
if (is_null($transaction)) {
// invalid transaction ID
}
// fetch your order
$order = Order::first();
// the amount is in smallest currency unit
$amount = $transaction->getBaseAmount() ?? $transaction->getAmount();
if (bccomp($amount, $order->getAmount()) !== 0) {
// the YouCan Pay transaction amount is different than the order amount
}
Webhooks
YouCan Pay uses webhooks to notify your application when an event happens in your account. Webhooks are useful for handling reactions to asynchronous events on your backend, such as successful payments, failed payments, successful refunds, and many other real time events. A webhook enables YouCan Pay to push real-time notifications to your application by delivering JSON payloads over HTTPS.
These notifications can be used to map YouCan Pay events to suitable reactions on your backend. For example, everytime you receive a notification of a paid transaction, you can programmatically mark an order as paid in your backend and update its information to match the transaction's. You can start receiving webhook notifications by following these steps:
Event objects
Every time an event is triggered in our system, all of your configured webhooks are automatically notified with a JSON payload of the corresponding event.
The object's unique identifier.
The event type following the pattern of "event_resource.event_action".
Whether the event was triggered in a sandbox environment or not.
An object containing sub-objects pertaining to the event's resource.
{
"id": "f9dc2ad2-a2ac-4608-878c-066f5ceb2ab3",
"event_name": "transaction.paid",
"sandbox": false,
"payload": {
"token": {
"id": "31b72661-e51f-4cb3-8aec-d990aec3ae63"
},
"customer": {
"id": "e85efd21-7a28-4cfa-9d43-b64355db1292",
"city": null,
"name": null,
"email": null,
"phone": null,
"state": null,
"address": null,
"zip_code": null,
"country_code": null
},
"metadata": {
"type": "checkout",
"cart.id": "uuid"
},
"transaction": {
"id": "5d47a625-4e1e-4505-94e0-8328a371fe67",
"amount": "500",
"status": 1,
"currency": "MAD",
"order_id": "12",
"created_at": "2022-05-13T10:36:08.000000Z",
"base_amount": null,
"base_currency": null
},
"payment_method": {
"id": 1,
"card": {
"id": "2c546131-e228-44e0-8fb4-733d6dd9daa7",
"brand": "VISA",
"fingerprint": "1f3decbcf2fb9a2e50e8a64ec5b2c83e",
"last_digits": "1881",
"country_code": "MA",
"is_3d_secure": false
},
"name": "credit_card"
}
}
}
Standalone Integration
Standalone integration is another way of using YouCan Pay. The main difference from the widget integration is that the payment is done completely on YouCan Pay and the customer gets redirected back to your platform when done. Here's how all of this works:
Generate Token
composer require youcanpay/payment-sdk
use YouCan\Pay\YouCanPay;
$youCanPay = YouCanPay::instance()->useKeys('pri_key', 'pub_key');
// generate a token for a new payment
$token = $youCanPay->token->create(
"order-id",
"2000",
"USD",
"123.123.123.123",
"https://mywebsite.com/success_callback",
"https://mywebsite.com/error_callback"
);
Redirect Customer
// redirect automatically
header(sprintf("Location:%s", $token->getPaymentURL()));
// or, return a link for the customer to click on
echo sprintf('Complete your order', $token->getPaymentURL());
Sandbox
YouCan Pay Sandbox offers an easy way for developers to test YouCan Pay in their test environment.
Note: when trying to switch to the sandbox mode,
you need to always use the sandbox keys that you can find on the settings page,
which have the following format: pub_sandbox_xxx
and pri_sandbox_xxx
Set up YouCan Pay Sandbox
ycPay.setSandboxMode(true)
in the Javascript integration
<script src="https://youcanpay.com/js/ycpay.js"></script>
<div id="error-container"></div>
<div id="payment-container"></div>
<button id="pay">Pay</button>
<script type="text/javascript">
const ycPay = new YCPay('pub_sandbox_key', {
formContainer: '#payment-container',
locale: 'en',
isSandbox: true,
errorContainer: '#error-container',
});
</script>
Testing and test cards
After the integration, the payment form will be rendered in the the specified div element with the following badge
to indicate being in the sandbox mode:
Test Mode
If the card used is protected by 3DS, a confirmation will pop,
which simulates the 3DS verification process that will be shown to the customer in the live mode.
You can use the test cards below in sandbox mode.
Card | CVV | Date | Behaviour |
---|---|---|---|
4242 4242 4242 4242
|
112
|
10/24
|
No 3DS - Success |
4000 0000 0000 3220
|
112
|
10/24
|
3DS - Success |
4000 0084 0000 1629
|
112
|
10/24
|
3DS - Card Rejected |
4000 0000 0000 0077
|
112
|
10/24
|
No 3DS - No Funds |
<script src="https://youcanpay.com/js/ycpay.js"></script>
<div id="error-container"></div>
<div id="payment-container"></div>
<button id="pay">Pay</button>
<script type="text/javascript">
const ycPay = new YCPay('pub_sandbox_key', {
formContainer: '#payment-container',
locale: 'en',
isSandbox: true,
errorContainer: '#error-container',
});
// render the form
ycPay.renderCreditCardForm();
// start the payment on button click
document.getElementById('pay').addEventListener('click', function() {
// execute the payment
ycPay.pay(tokenId)
.then(successCallback)
.catch(errorCallback);
})
function successCallback(response) {
// your code here
}
function errorCallback(response) {
// your code here
}
</script>
Sandbox Backend Integration
On the backend side, after installing our SDK,
you need to indicate that you want to use the sandbox mode by using setIsSandboxMode
static method.
You can then use the following snippet in order to generate a token for a certain transaction,
or view a specific transaction by providing the transaction ID, just like the live mode
Congrats, now you can use the sandbox mode of YouCan Pay!
composer require youcanpay/payment-sdk
// setting the sandbox mode
YouCanPay::setIsSandboxMode(true)
$youCanPay = YouCanPay::instance()->useKeys('my-sandbox-private-key', 'my-sandbox-public-key');
// generate a token for a new payment
$token = $youCanPay->token->create("order-id", "2000", "USD", "123.123.123.123");
var_dump($token->getToken(), $token->getRedirectURL());
// get details of a transaction
$transaction = $youCanPay->transaction->get('transaction-id');
var_dump($transaction->getAmount(), $transaction->getCurrency());
</script>