Handle alternative payment methods

On top of helping you accept payments using credit cards, ProcessOut also lets you accept payments through alternative payment methods, such as PayPal or cryptocurrencies with coinpayments.


Native to the payment modal

Before getting into the white-label integration, it is important to note that the ProcessOut modal ↗ comes with the alternative payment methods right from the start, without any additional work needed. The modal is a perfect fit if you want a simple solution out of the box.

Alternative payment methods flow

Because of their nature, most alternative payment methods are asynchronous. This means that you normally wouldn’t be able to synchronously tell the customer if its payment correctly made it through until you receive a confirmation from the payment method webhooks (such as from the PayPal IPN). This is mainly due to the fact that a redirection is usually required.

ProcessOut tries to bridge that gap by letting merchants keep control of their customer flow, even after a redirection. The customer is transparently redirected to the payment method’s payment page in a new window, and once the payment is completed, the alternative payment method’s window is closed and the original merchant payment page is notified of the payment via Javascript.

Fetch the available alternative payment methods

Before showing the payment methods to the customer, they need to be fetched from your ProcessOut configuration. This lets you dynamically enable and disable payment options without having to update any of your code.

In order to fetch your ProcessOut gateways configuration, we’ll also need to create an invoice, as some of the gateways will need some information before the payment actually takes place.

Please keep in mind that when using the ProcessOut sandbox, your gateway configurations aren’t returned, but instead a single entry sandbox is. Its main purpose is to provide you with a way to easily test successful and errored checkouts. Because this guide provides you with a generic implementation that works with all alternative payments available on ProcessOut, switching over to production should not break any of your logic, and alternative payment solutions such as PayPal should work right out of the box.

# Let's first create an invoice
curl https://api.processout.com/invoices \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d name="Awesome invoice" \
    -d amount="9.99" \
    -d currency=USD

# And fetch the gateways
curl -X GET -G https://api.processout.com/gateway-configurations \
    -u proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    --data-urlencode expand[]=gateway \
    --data-urlencode filter="tags: redirection flows: one-off"
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// Let's first create an invoice
client.newInvoice().create({
    name:     "Amazing item",
    amount:   "4.99",
    currency: "USD",

    expand: ["project"]
}).then(function(invoice) {
    // And now fetch the project available gateways for one-off payments
    client.newGatewayConfiguration().all({
        expand: ["gateway"],
        filter: "tags: redirection flows: one-off"
    }).then(function(gateways) {
        //

    }, function(err) {
        // Couldn't fetch the project's gateways
    });

}, function(err) {
    // An error occured

});
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# Let's first create an invoice
invoice = client.new_invoice().create({
    "name":     "Amazing item",
    "amount":   "4.99",
    "currency": "USD",

    "expand": ["project"]
})

# And now fetch the project's available gateways
gateways = client.new_gateway_configuration().all({
    expand: ["gateway"],
    filter: "tags: redirection flows: one-off"
})
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

# Let's first create an invoice
invoice = client.invoice.create(
    name:     "Amazing item",
    amount:   "4.99",
    currency: "USD",

    expand: ["project"]
)

# And now fetch the project's available gateways
gateways = client.gateway_configuration.all({
    expand: ["gateway"],
    filter: "tags: redirection flows: one-off"
})
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

// Let's first create an invoice
$invoice = $client->newInvoice()->create(array(
    "name"     => "Amazing item",
    "amount"   => "4.99",
    "currency" => "USD",

    "expand" => array("project")
));

// And now fetch the project's available gateways
$gateways = $client->newGatewayConfiguration()->all(array(
    "expand" => array("gateway"),
    "filter" => "tags: redirection flows: one-off"
));
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

// Let's first create an invoice
iv, err := client.NewInvoice().Create(processout.InvoiceCreateParameters{
    Invoice: &processout.Invoice{
        Name:     processout.String("Amazing item"),
        Amount:   processout.String("4.99"),
        Currency: processout.String("USD"),
    },
    Options: &processout.Options{
        Expand: []string{"project"},
    },
})
if err != nil {
    panic(err)
}

// And now fetch the project available gateways for one-off payments
gateways, erri := client.NewGatewayConfiguration().All(processout.GatewayConfigurationAllParameters{
    Options: &processout.Options{
        Expand: []string{"gateway"},
        Filter: "tags: redirection flows: one-off",
    },
})

The gateways variable fetched in the previous steps now contains all the available alternative payment gateways that were configured and activated on your project. We also created a new Invoice that we’ll use to redirect the customer to the payment page.

A payment link for an alternative payment gateway is as follows:

<form action="/your-capture-endpoint" method="POST" id="payment-form">
  <!-- Loop through all your gateway configurations and display the link
       below.
       ProcessOut-checkout-domain/:project_id/:invoice_id/redirect/:gateway_configuration_id -->
  <a href="https://checkout.processout.com/test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x/iv_tIWEiBcrXIFHzJeXcZzqyp8EpY0xwmuT/redirect/gway_conf_vMFNzz1GnWYRUJWFgUhn4HajCYmJiMsi"
    class="alternative-payment-link">

    Pay now!
  </a>
</form>

Note: The links are put in a form so that we can later post the token representing the payment back to the merchant’s backend.

We could technically stop there and simply redirect the customer to the checkout pages, but the merchant would lose control over its customer checkout flow. ProcessOut.js lets you control the redirection from your payment page so you can cancel the payment at any time, and be notified synchronously of a new payment.

<script src="https://js.processout.com/processout.js"></script>
<script type="text/javascript">
  document.addEventListener("DOMContentLoaded", function() {
    var client = new ProcessOut.ProcessOut("test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x");
    // Let's hook every link:
    var formElement = document.getElementById("payment-form");
    var links = formElement.querySelectorAll(".alternative-payment-link");
    for(var i = 0; i < links.length; i++) {
      links[i].addEventListener("click", processoutRedirectHandler);
    }
  });
</script>

Note: Remember to replace the project ID in the example with your own. When testing, prepend your project ID with test- like so: test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x.

We also still have to add the handler, which we’ll do just now:

Handle the redirection

When a customer will click on the alternative gateway link, the processoutRedirectHandler function will be called. Let’s define it:

function processoutRedirectHandler(e) {
  var el = e.target;
  // Prevent from doing the default redirection
  e.preventDefault();

  var action = client.handleAction(el.getAttribute("href"),
    function(token) {
      // The customer completed the gateway payment flow,
      // we can send the token back to our backend to finish the
      // capture
      var field   = document.createElement("input");
      field.type  = "hidden";
      field.name  = "token";
      field.value = token;
      formElement.appendChild(field);
      formElement.submit();
    }, function(err) {
      // An error occured during checkout. This could just be the
      // customer that canceled the payment, or an error with
      // the payment gateway.
      alert(err);
    });

  return false;
}

Handle the capture on the server

ProcessOut.js sent the token back to our server so we need to finish its capture. We’ll need both the token and the invoice ID we created earlier and used to redirect the customer.

The code to capture the token returned by ProcessOut.js during an alternative gateway checkout is identical to the capture of a card token.

curl https://api.processout.com/invoices/iv_tIWEiBcrXIFHzJeXcZzqyp8EpY0xwmuT/capture \
    -u test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x:key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8 \
    -d source="gway_req_V2UncmUgaGlyaW5nIQ=="
var ProcessOut = require("processout");
var client = new ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x",
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

invoice.capture("gway_req_V2UncmUgaGlyaW5nIQ==").then(
    function(transaction) {
        //

    }, function(err) {
        // The invoice could not be captured
    });
import processout
client = processout.ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

transaction = invoice.capture("gway_req_V2UncmUgaGlyaW5nIQ==")
require "processout"
client = ProcessOut::Client.new(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

transaction = invoice.capture("gway_req_V2UncmUgaGlyaW5nIQ==")
<?php
$client = new \ProcessOut\ProcessOut(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8");

$transaction = $invoice->capture("gway_req_V2UncmUgaGlyaW5nIQ==");
import "gopkg.in/processout.v4"
client := processout.New(
    "test-proj_gAO1Uu0ysZJvDuUpOGPkUBeE3pGalk3x", 
    "key_sandbox_jqSPvwq3AG5MlYAgqxlwwgOcAC3Zy7d8")

tr, _ := iv.Capture("gway_req_V2UncmUgaGlyaW5nIQ==")

Note: The gateway request token sent by ProcessOut.js is actually only an abstraction of the request done by the customer on the gateway. The content of the token is therefore directly encoded inside it, in base64.

The capture should return a transaction if it was successful. It is strongly advised to check its status attribute is set to completed to make sure the payment made it through. We highly recommand you to set up a way to receive webhooks ↗ as this will make you able to handle updates on payments made using alternative payment methods.