Integrations

CannPay provides two environments to interact with, Production and Test. The below examples use Test endpoints. Be sure to change these to Production endpoints when needed.

Prerequisites

Initial steps

  • Find your merchant ID on the Gateways page of the Merchant Admin.
  • Generate a public and private key pair either via one of our plugins/extensions or with custom code. See below for more information.
  • Add the public key to the gateway page in the Merchant Admin.

Plugins

WooCommerce

  • Download the latest WooCommerce CannPay plugin.
  • Install the plugin via the WordPress plugin install page
  • Enable the plugin
  • Go to WooCommerce > Settings > Payments > CannPay > Set up (or Manage)
  • Under Key Generator click Generate to create the public and private keys.
  • Enter your Merchant ID.
  • Enable Test Mode if you are integrating with CannPay’s Test environment.
  • Click Save.
  • Take the newly generated public key and enter it into the gateway page in the Merchant Admin.
  • Go back to WooCommerce > Settings > Payments and enable CannPay as a payment method.
  • Go through the process of making a purchase on your store and CannPay should now be listed as a payment option.

Magento

Coming soon.

Joomla

Coming soon.

Custom

If you plan on writing your own custom integrations to CannPay, below are code examples that will help you.

Endpoints

Checkout URL: https://test-pay.cannpay.co/checkout
CannPay public key: https://test-api.cannpay.co/v1/key

General Process Flow

The general process flow for making a checkout request is the following:

1. Generate and store your public/private keys
This should be done ahead of time. Store your keys securely.

2. Request CannPay public key
A GET request to https://api.cannpay.co/v1/key will return the CannPay public key. This should be done for every checkout.

3. Create your payload
The payload will consist of product, billing and delivery details. Full details are in the code sample below.

4. Encrypt the payload
The payload must be encrypted using your private key from step 1 and the CannPay public key from step 2.

5. Post encrypted payload to /checkout
Posting the encrypted payload (via a form) to https://pay.cannpay.co/checkout will direct the user to our payment details form page. When this form is submitted the customer will be redirected to a page of your choosing.

6. Inspect the payload sent to your callback URL for success or failure of transaction
Your callback endpoint should deal with the success or failure of the transaction and respond with the URL to redirect the customer to.

7. Show the customer a confirmation of their payment or a failure message
Generally you’d want to show a success or failure page to your customers but you can choose any page to display.

Generate public and private keys

The following example will provide you with a public and a private key pair.

Store these securely as they will be needed to process transactions through CannPay.

The public key should be added to your Gateway in the Merchant Admin.

<?php

$keyPair = sodium_crypto_box_keypair();
$yourPrivateKey = sodium_crypto_box_secretkey($keyPair);
$yourPublicKey = sodium_crypto_box_publickey($keyPair);

echo 'Your base64 encoded public key: ' .base64_encode($yourPublicKey). '<br>';
echo 'Your base64 encoded private key: ' .base64_encode($yourPrivateKey). '<br>';

Construct order and post to /checkout

This example requests the CannPay public key via curl, constructs the payload for /checkout which consists of items, billing address and delivery address and populates a form which is submitted to /checkout.

<?php

// The endpoint to obtain the CannPay public key
$cannpayPublicKeyUrl = 'https://test-api.cannpay.co/v1/key';

// The endpoint to send your encrypted order payload
$checkoutUrl = 'https://test-pay.cannpay.co/checkout';

// The endpoint on your application/store to record success of failure of the payment
$callbackUrl = 'https://your-store/callback.php';

// Your merchant ID
$merchantId = 'XX-XXXX-XXXX-XXXX-XXXX';

// Your pre-generated base64 public key
$yourPublicKeyEncoded = 'xxxxxxxxxxxxxxxxxxxxxx';

// Your pre-generated base64 private key
$yourPrivateKeyEncoded = 'yyyyyyyyyyyyyyyyyyyyyy';

// Decoded keys
$yourPublicKey = base64_decode($yourPublicKeyEncoded);
$yourPrivateKey = base64_decode($yourPrivateKeyEncoded);

function getCannPayPublicKey($keyUrl) {
  $keyRequest = curl_init($keyUrl);
  $keyRequestOptions = array(
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => array('Content-type: application/json'),
    CURLOPT_SSL_VERIFYPEER => false
  );
  curl_setopt_array($keyRequest, $keyRequestOptions);
  $keyResponse = curl_exec($keyRequest);
  curl_close($keyRequest);
  $keyResponseData = json_decode($keyResponse, true);
  return $keyResponseData['data']['public'];
}

// Your customer's order...

// Items in the order
$items = [
  [
    'product'  => 'A product',
    'quantity' => 1,
    'amount'   => 500,
  ],
  [
    'product'  => 'Another product',
    'quantity' => 2,
    'amount'   => 300,
  ]
];

// Order details
$order = [
  'merchant_id' => $merchantId,
  'public_key' => $yourPublicKeyEncoded,
  'callback_url' => $callbackUrl,
  'nonce' => bin2hex(random_bytes(16)), // Create a unique nonce which can only be used once
  'order_id' => '100000', // Your store order ID - Required - Integer
  'amount' => 1100, // Amount in pence - Required - Integer
  'currency' => 'GBP', // Currency code - Required - Will depend on your gateway but will be one of GBP, USD, EUR
  'items' => $items,

  'billing_firstname' => 'Billing First Name',
  'billing_lastname'  => 'Billing Last Name',
  'billing_address_1' => 'Billing Address 1',
  'billing_address_2' => 'Billing Address 2',
  'billing_city'      => 'Billing City',
  'billing_state'     => 'Billing State',
  'billing_postcode'  => 'Billing Post Code',
  'billing_country'   => 'Billing Country',
  'billing_phone'     => 'Billing Phone',
  'billing_email'     => 'customers@email.com', // Receipt email - Required - A valid email address

  'delivery_firstname' => 'Delivery First Name',
  'delivery_lastname'  => 'Delivery Last Name',
  'delivery_address_1' => 'Delivery Address 1',
  'delivery_address_2' => 'Delivery Address 2',
  'delivery_city'      => 'Delivery City',
  'delivery_state'     => 'Delivery State',
  'delivery_postcode'  => 'Delivery Post Code',
  'delivery_country'   => 'Delivery Country',
  'delivery_phone'     => 'Delivery Phone'
];

// Request CannPay public key - This should be done with each order and not cached
$cannpayPublicKeyEncoded = getCannPayPublicKey($cannpayPublicKeyUrl);

// Decoded for use in sodium method calls
$cannpayPublicKey = base64_decode($cannpayPublicKeyEncoded);

// Create a key pair - Note: The decoded keys are used
$keyPair = sodium_crypto_box_keypair_from_secretkey_and_publickey($yourPrivateKey, $cannpayPublicKey);

// Random nonce for transaction
$nonce = random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES);

$payload = base64_encode($nonce . sodium_crypto_box(json_encode($order), $nonce, $keyPair));

// Construct form to show payload and merchant ID
echo '
  <form method="post" id="woocommerce_cannpay_auto_submit" name="redirect" action="' . $checkoutUrl . '">
    Encrypted payload:
    <br />
    <textarea style="width: 80%; height: 300px;" name="payload">' . $payload . '</textarea>
    <br />
    Merchant ID:
    <br />
    <input type="text" name="merchant_id" style="width: 80%;" value="' . $merchantId . '">
    <br />
    <input type="submit" value="Post to payment form" />
  </form>
';

Deal with callback and show customer the status of the transaction

The following two files are to deal with the callback request and to show the customer a confirmation of the success or failure of their payment.

Callback

<?php

// The payload is base64 encoded so decode it
$payload = base64_decode($_POST['payload']);

// The endpoint to obtain the CannPay public key
$cannpayPublicKeyUrl = 'https://test-api.cannpay.co/v1/key';

// The URLs to redirect to on successful/unsuccessful payment
$successUrl = 'https://your-store/status.php?status=success';
$failureUrl = 'https://your-store/status.phpstatus=fail';

// Your pre-generated base64 private key
$yourPrivateKeyEncoded = 'yyyyyyyyyyyyyyyyyyyyyy';

// Decoded private key
$yourPrivateKey = base64_decode($yourPrivateKeyEncoded);

function getCannPayPublicKey($keyUrl) {
  $keyRequest = curl_init($keyUrl);
  $keyRequestOptions = array(
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => array('Content-type: application/json'),
    CURLOPT_SSL_VERIFYPEER => false,
  );
  curl_setopt_array($keyRequest, $keyRequestOptions);
  $keyResponse = curl_exec($keyRequest);
  curl_close($keyRequest);
  $keyResponseData = json_decode($keyResponse, true);
  return $keyResponseData['data']['public'];
}

// Request CannPay public key - This should be done with each order and not cached
$cannpayPublicKeyEncoded = getCannPayPublicKey($cannpayPublicKeyUrl);

// Decoded for use in sodium method calls
$cannpayPublicKey = base64_decode($cannpayPublicKeyEncoded);

// Create a key pair - Note: The decoded keys are used
$keyPair = sodium_crypto_box_keypair_from_secretkey_and_publickey($yourPrivateKey, $cannpayPublicKey);

// Decrypt payload...

// Retrieve the nonce
$nonce = mb_substr($payload, 0, 24, '8bit');

// Retrieve the payload
$cipherText = mb_substr($payload, 24, null, '8bit');
$plainText = sodium_crypto_box_open($cipherText, $nonce, $keyPair);

// DECODE PAYLOAD TO JSON OBJECT
$result = json_decode($plainText, true);
$status = $result['status'];

if ($status === 'success') {

  // If the payment was successful, redirect to success page
  echo '{ "success": true, "data": { "redirect": "' . $successUrl . '" } }';

} else if ($status === 'fail') {

  // If the payment was unsuccessful, redirect to failure page
  echo '{ "success": true, "data": { "redirect": "' . $failureUrl . '" } }';

}

Status

<h1>STATUS</h1>

<?php

if ($_GET['status'] === 'success') {
  echo 'Thank you!';
} else if ($_GET['status'] === 'fail') {
  echo 'Your payment failed...';
}

The above examples are available to download here.