Accepting payments on the website via CloudPayments

Accepting payments via CloudPayments

CloudPayments allows you to accept payments via bank cards, Google Pay, Apple Pay. The payment data is entered inside the pop-up form.



Connecting the service

To activate the service, we will need to register, add our site in the personal account and get a Public ID and API password for it. You will need the first one for making payments, and the second one for confirming them.

We will add the API password to the settings of our site under the code cloudPaymentsApiCode, we will use it in one of the stored procedures.

General scheme of work

When you click the “pay“ button, the following sequence of actions will occur on the site:

  1. We send an ajax request to create a payment in our system. We get the payment id.
  2. We start the CloudPayments payment, where we pass the payment id.
  3. If the payment was successful, CloudPayments sends a notification to our API.
  4. Using the API password received from CloudPayments as a key, we check the authenticity of the notification, and if everything is fine, we confirm the payment.

Next, we will consider the implementation of each of the steps. For example, we will top up the user's balance on the site.

Adding payment functionality to the page

The payment will be managed using javascript.

In html, you need to connect the CloudPayments script, we will also provide our payment button and a field for entering the amount:

<input type="text" class="balance-input-sum form-control" placeholder="Deposit amount">
<button class="btn btn-primary addBalance">Pay</button>

<script src="https://widget.cloudpayments.ru/bundles/cloudpayments"></script>

The javascript example is below. Making a request to create a payment (initPayment) “Pay” when you click on the button, making a request to create a payment (initPayment). After receiving the payment id, we pass it to the pay function, which will open a dialog for entering payment data.

as.cloudPayments = {
  init: function(){
    $(document).on("click", ".addBalance", function(){
      as.cloudPayments.initPayment();
    });
  },
  //payment creation function
  initPayment: function(){
    //making a request to create a payment
    as.sys.request("finances", "initPayment", {
      data: { sum: Number($('.balance-input-sum').val() || "0") },
      onSuccess: function(data) {
        var paymentID = data.data[0].paymentID;
        //when we received the payment id, we start the payment
        as.cloudPayments.pay(paymentID);
      }
    });
  },
  //payment function
  pay: function(paymentID){
    var widget = new cp.CloudPayments();
    //calling the payment dialog
    widget.charge({ // options
            publicId: 'pk_1111111111111111111111',  //public id from your personal account
            description: 'Example of payment (money will not be withdrawn)', // purpose
            amount: Number($('.balance-input-sum').val() || "0"), //amount
            currency: 'RUB', //currency
            invoiceId: paymentID, //payment id
            accountId: $('.as-username').val(), //username payer
            skin: "mini", //widget design
            data: {
                //username: 'myProp value' //an arbitrary set of parameters
            }
        },
        function (options) { // success
            //action on successful payment
            //updating the page
            location.reload();
        },
        function (reason, options) { // fail
            //action in case of unsuccessful payment
        });
  }
}

$(function(){
  as.cloudPayments.init();
});

After the payment is made, CloudPayments must send a notification about the payment to our api. Let's look at creating an API below.

Receiving ajax requests to create a payment

To create payments, a finances_initPayment request is made.

Below is an example of the procedure for the request. Creating a new payment for our user in the fin_finances table with the status "Preliminary". The only parameter for the request is sum (payment amount).

We return the payment ID

CREATE PROCEDURE [dbo].[request_finances_initPayment]
    @parameters DictionaryParameter READONLY,
    @username nvarchar(32)
AS
BEGIN
    select '' Msg, 1 Result

    declare @counteragentID int = (select id from ctr_contragents where username=@username)
    declare @accountID int = (select id from fin_accounts where contragentID=@counteragentID)

    declare @statusID int
    select @statusID = id from fin_financeStatuses where name = N'Preliminary'

    declare @sum decimal = (select Value from @parameters where [Key]='sum')

    insert into fin_finances (accountToID, sum, typeID, statusID,  created)
    values (@accountID, @sum, 1, @statusID, getdate())

    declare @paymentID int = scope_identity()

    select @paymentID paymentID
END

API for receiving payment notifications

Adding the incoming API method.

The entity code in our case is finances, the code is confirmPayment.

“Without Token?” - yes.

The address of the received API must be specified in the site settings in the CloudPayments personal account in the “Pay notification" ”.

The full list of parameters that are included in the notification and will be available in the stored procedure is available in the service documentation https://developers.cloudpayments.ru/#pay.

Inside the stored procedure, we will need to confirm the authenticity of the notification and confirm our payment. For more details, see the comments inside the example.

The text of the stored procedure for the API: 

CREATE PROCEDURE [dbo].[api_finances_confirmPayment]
@parameters ExtendedDictionaryParameter READONLY,
@username nvarchar(256)
as
begin
    --part 1 - confirming the authenticity of the notification
    --you need to calculate the hash of the notification using the API password as the key, and compare it with what came in the Content-HMAC parameter

    --full text of the notification (request body)
    declare @notificationBody nvarchar(max) = (select Value2 from @parameters where [Key]='InputStream')
    --API password (we get it from the settings)
    declare @notificationKey nvarchar(max) = (select value from as_settings where code='cloudPaymentsApiCode')

    --calculating the hash
    declare @notificationHash varbinary(64) = dbo.as_HMAC('SHA2_256', dbo.as_NCharToUTF8Binary(@notificationKey, 1), dbo.as_NCharToUTF8Binary(@notificationBody, 1))

    --we encode the hash in the form of base64
    declare @notificationHashBase64 nvarchar(128) = dbo.as_binaryToBase64(@notificationHash)

    --the reference hash, with which we will compare the one that we got
    declare @notificationHmac nvarchar(128) = (select Value2 from @parameters where [Key]='Content-HMAC')

    --if they match, this variable will be equal to 1. In this case, we confirm the payment.
    declare @notificationIsCorrect bit = case when @notificationHmac=@notificationHashBase64 then 1 else 0 end
    declare @paymentStatus nvarchar(64) = (select Value2 from @parameters where [Key]='Status')
    if (@notificationIsCorrect = 1 and @paymentStatus='Completed') begin
        --part 2-payment confirmation
        declare @paymentID int = (select Value2 from @parameters where [Key]='InvoiceID')
        declare @paymentUsername nvarchar(256) = (select Value2 from @parameters where [Key]='AccountID')
        declare @sum decimal = (select Value2 from @parameters where [Key]='Amount')
        declare @counteragentID int = (select id from ctr_contragents where username=@paymentUsername)
        declare @accountID int = (select id from fin_accounts where contragentID=@counteragentID)

        declare @statusDoneID int
        select @statusDoneID = id from fin_financeStatuses where name = 'Проведен'

        --updating the payment status from "preliminary" to " completed"
        update fin_finances
        set statusID=@statusDoneID,
            completed=getdate()
        where accountToID=@accountID and id=@paymentID

        --adding the payment amount to the user's balance
        update fin_accounts set balance = isnull(balance,0) + @sum where id = @accountID
    end

    -- SELECT 1 - output of metadata about the result of an API method operation
    select '' Msg, 1 Result, 0 errorCode

    -- SELECT 2 -  output of the data itself to the API (in case of problems, check that this request comes non-empty)
    select 1 where 1=0
end


Testing

After adding the payments, you can test.

In the documentation https://developers.cloudpayments.ru/#testirovanie there is a set of test bank cards on which you can check the operation of the system.

For example, the payment to the card number 4242 4242 4242 4242 must always be successful. The term of the card is indicated any not expired.

Switching to Cloud Payments mode

Occurs in manual mode via the CloudPayment system operator.

At the same time, the site is checked for compliance with the requirements described here -  https://cloudpayments.ru/wiki/podkluchenie/poryadok_podkluchenia/requirements

Basic requirements: 

  • working contacts, 
  • the contract of the offer on the website, 
  • transparent payment scheme
  • the refund procedure is described

Also, an agreement with CloudPayments must be signed before this moment.

Working hours of the Marketplace CloudPayments

There is an agent (site) and subagents (suppliers on the site).

An agency agreement is signed with the agent. Subagents work with CloudPayments according to the offer.

For each subagent, information is transmitted to CloudPayments (apparently in the form of a certain document, a questionnaire) with legal data and bank details of the subagent.

When a user pays on the site, the supplier ID is transmitted, on the basis of which the payment is made.

Payments are made on the next business day.

Links

Falcon Space is a functional web development platform on a narrow stack MS SQL/Bootstrap. Falcon Space Gettting started
{sp-shortDemostandLinks}

Falcon Space Platform

This is a reduction in the cost of ownership

at the expense of fewer people to support

This is a quick change

while using the program

This is a modern interface

full adaptation for mobile devices

Note