Embedded example - Payment link

Frontend - Checkout form

To prevent card data being submitted by mistake the card input fields should not have name arguments but instead be identified by data-quickpay="cardnumber", data-quickpay="expiration" and data-quickpay="cvd"

When form is submitted card data will first be submitted directly to QuickPay for authorization. If the authorization is successful it will submit the form to your defined action.

We highly recommend that you verify the payment acceptance status through QuickPay API inside your action.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<form id="checkout-form" class="form-horizontal" action="/shop/pay" method="post">
  <label for="name">Name</label>
  <input type="text" name="name" value="">

  <label for="address">Address</label>
  <input type="text" name="address" value="">

  <label for="zipcode">Zipcode</label>
  <input type="text" name="zipcode" value="">

  <labe for="city">City</label>
  <input type="text" name="city" value="">

  <label>Card number</label>
  <div class="card">
    <div class="card-brand"></div>
    <input type="text" autocomplete="off" data-quickpay="cardnumber">
  </div>

  <label>Expiration</label>
  <input type="text" placeholder="MM" autocomplete="off" data-quickpay="exp-month">
  <input type="text" placeholder="YY" autocomplete="off" data-quickpay="exp-year">

  <label>CVV/CVD</label>
  <input type="text" maxlength="4" autocomplete="off" data-quickpay="cvd">

  <button class="btn btn-primary" type="submit">Pay</button>
</form>

<style type="text/css">
  .card {
    position: relative;
  }

  .card-brand {
    position: absolute;
    right: 5px;
    top: 5px;
    font-weight: bold;
  }

  input.error {
    border: 1px solid red;
  }
</style>

<script src="https://payment.quickpay.net/embedded/v2/quickpay.js"></script>
<script type="text/javascript">
  QuickPay.Embedded.Form(document.querySelector("#checkout-form"), {
    payment_link: "https://payment.quickpay.net/payments/abee7c551dfd98ca4ed76421c182ef71a06854b98801e581820a0a533a7a0122",
    brandChanged: function(brand) {
      document.querySelector(".card-brand").innerHTML = brand;
    },
    beforeCreate: function(form) {
      var button = document.querySelector("#checkout-form button");
      button.setAttribute("disabled", "disabled");
      button.innerHTML = "Please wait...";
    },
    validChanged: function(form, isValid, fields) {
      if (isValid) {
        var inputs = document.querySelectorAll("input.error");
        for (var i = 0; i < inputs.length; i++) {
          inputs[i].classList.remove("error");
        }
      }
    },
    success: function(form, data) {
      return true; // Return false to prevent form submit
    },
    failure: function(form, type, message, data) {
      switch (type) {
        case "validation":
          for (var i = 0; i < data.length; i++) {
            document.querySelector('input[data-quickpay=' + data[i] + ']').classList.add('error');
          }
          break;
        default:
          alert(type + ': ' + message);
      }

      document.querySelector("#checkout-form button").innerHTML = "Pay";
    }
  });
</script>

Backend

These are simplified examples that will almost certainly not fit your shop system. However, it should give an idea on how to use the Embedded payment form.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
require 'sinatra/base'
require 'quickpay/api/client' # Find the QuickPay Ruby client at https://learn.quickpay.net/tech-talk/opensource

class App < Sinatra::Base
  enable :sessions

  get '/shop/checkout' do
    order = Order.new(
      name:    params[:name],
      address: params[:address],
      zipcode: params[:zipcode],
      city:    params[:city]
    )
    order.save!

    # See https://learn.quickpay.net/tech-talk/api/services
    client = QuickPay::API::Client.new(api_key: ENV['QUICKPAY_API_KEY'])

    payment = client.post('/payments', {
      order_id: order.order_id, # MUST be unique
      currency: 'EUR'
    })

    order.payment_id = payment['id']
    order.save!

    @link = client.put("/payments/#{order.payment_id}/link", {
      amount: 12345, # 123.45
    })

    session[:order_id] = order.id

    erb :form
  end

  post '/shop/pay' do
    order = Order.find(session[:order_id])

    client = QuickPay::API::Client.new(api_key: ENV['QUICKPAY_API_KEY'])

    payment = client.get("/payments/#{order.payment_id}")

    if payment['approved']
      order.authorized = true
    end

    order.qp_status_code = payment['operations'].last['qp_status_code']
    order.qp_status_msg  = payment['operations'].last['qp_status_msg']
    order.aq_status_code = payment['operations'].last['aq_status_code']
    order.aq_status_msg  = payment['operations'].last['aq_status_msg']
    order.save!

    if order.authorized?
      redirect to('/shop/receipt')
    else
      erb :error
    end
  end

  get '/shop/receipt' do
    @order = Order.find(session[:order_id])
    erb :receipt
  end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php

/**
 * This is only an very simple mocked example.
 */

require_once 'QuickPay'; // Find the QuickPay PHP client at https://learn.quickpay.net/tech-talk/opensource

use QuickPay/QuickPay as Client;
use Models/Order;

class PaymentController
{
    public function form(Request $request)
    {
        $order = new Order([
            'name'    => $request('name'),
            'address' => $request('address'),
            'zipcode' => $request('zipcode'),
            'city'    => $request('city')
        ]);
        $order->save();

        // See https://learn.quickpay.net/tech-talk/api/services
        $client = new Client(":{$this->config('API_KEY')}");

        $payment = $client->request->post("/payments", [
            'order_id' => $order->order_id, // Must be unique
            'currency' => 'EUR'
        ])->as_object();

        $order->payment_id = $payment->id;
        $order->save();

        $link = $client->request->put("/payments/{$payment->id}/link", [
          'amount' => 12345
        ])->as_object();

        $this->session->set('order_id', $order->id);

        $this->render('form', ['payment_link' => $link->url]);
    }

    public function pay(Request $request)
    {
        $client = new Client(":{$this->config('API_KEY')}");

        $order_id = $this->session->get('order_id');
        $order = Order::find($order_id);

        $payment = $client->request->get("/payments/{$order->payment_id}");

        if ($payment->accepted) {
            $order->authorized = true;
        }

        $authorize = end($payment->operations);

        $order->qp_status_code = $authorize->qp_status_code;
        $order->qp_status_msg  = $authorize->qp_status_msg;
        $order->aq_status_code = $authorize->aq_status_code;
        $order->aq_status_msg  = $authorize->aq_status_msg;
        $order->save();

        if ($order->authorized()) {
            $this->session('order_id', $order->id);
            $this->redirectTo('/payment/receipt');
        } else {
            $this->render('error');
        }
    }

    public function receipt()
    {
        $order = Order::find($this->session('order_id'));
        $this->render('receipt', compact('order'));
    }
}