📜 ⬆️ ⬇️

We accept payments by cryptocurrency using PayKassa aggregator

Hi, Habr! In my last article, I told you how to connect a cryptocurrency receipt with your own hands without using third-party services. In this article I will explain how you can accept payments with cryptocurrency without raising a full node and without the associated difficulties.


But, as it always happens, you will have to pay for the convenience. PayKassa is considered as an aggregator, as it allows you to accept payments anonymously with average market commissions, without the need to confirm your identity and company data.


Registration and setup


Registration is very simple, setting up is somewhat more complicated.


I advise you to create 2 stores, one for development and testing, and the second - "combat". For local development, it is very convenient to use ngrok and specify the appropriate domain (having checked beforehand that it is free).


Making the store as simple as possible:



In the form that opens, most of the fields should not cause difficulties:



For a test store, it will be most convenient to specify any free ngrok domain. Handler URL is the address where PayKassa will knock to notify that the order status has changed. "URL successful / unsuccessful payment" - the address where the user will be sent after the payment. They can accommodate a simple page describing what the user needs to do after a successful / unsuccessful payment.


After creation, we need the store ID:



Further, if you wish, you can specify in the settings who pays the commission and which payment systems you want to connect.


This is all that is required to start accepting payments.


Getting a URL for payment


The article will use the true value for the test parameter in all requests. To go into combat mode is enough not to specify it.


PayKassa has a simple PHP wrapper for working with the API , but for other languages, writing such a wrapper should also not cause difficulties. And for a better understanding of the process, all examples will be accompanied by an example of queries using curl.


I did not find the possibility of using ready-made pages with a choice of payment method, but this is not always required. Moreover, to make it yourself is quite simple. On the developer page there is a correspondence between payment systems and internal ID:



As a currency, we will use Bitcoin everywhere (system: 11, currency: "BTC").


PayKassa payment API is located at https://paykassa.pro/sci/0.3/index.php (at the time of writing) and supports two methods: sci_create_order to get the payment URL and sci_confirm_order to check the status of the payment.


An example of getting a payment URL using curl:


 curl https://paykassa.pro/sci/0.3/index.php -d 'func=sci_create_order&amount=0.1&currency=BTC&order_id=1&comment=test&system=4&sci_id=SCI_ID&sci_key=SCI_KEY&domain=DOMAIN&test=false' -H 'Content-type: application/x-www-form-urlencoded' 

Using the PHP library ( link to paykassa_sci.class.php ):


 <?php require_once('paykassa_sci.class.php'); $paykassa = new PayKassaSCI( $paykassa_shop_id, //   $paykassa_shop_password //   ); // : , ,  , ,   $res = $paykassa->sci_create_order(0.01, "BTC", 1, "Test Payment", 11); if ($res['error']) { echo $res['message']; // $res['message'] -     //    } else { //     $redirect_uri = $res['data']['url']; header("Refresh: 0; url=$redirect_uri"); } ?> 

To work with the API in other languages, it will be convenient to write a small wrapper and use it:


For ruby:


 # paykassa.rb require 'net/http' class Paykassa BASE_SCI_URI = URI('https://paykassa.pro/sci/0.3/index.php') #   Ruby On Rails   #  secrets.yml    : # paykassa: # sci_id: SCI_ID # sci_key: SCI_SECRET_KEY # domain: SCI_DOMAIN #     RoR -       : # def initialize(auth) #        auth    sci_id, sci_key  domain def initialize(auth = Rails.application.secrets[:paykassa]) @_auth = auth end #    ,       JSON    def create_order(amount:, currency:, order_id:, comment:, system:) make_request( func: :sci_create_order, amount: amount, currency: currency, order_id: order_id, comment: comment, system: system ) end #    def confirm_order(private_hash) make_request(func: :sci_confirm_order, private_hash: private_hash) end private def make_request(data) res = Net::HTTP.post_form(BASE_SCI_URI, data.merge(@_auth)) JSON.parse(res.body).deep_symbolize_keys end end 

Getting url for payment:


  paykassa = Paykassa.new #   secrets.yml      : # paykassa = Paykassa.new(sci_id: 0, sci_key: '123', domain: 'habrashop.ngrok.io') result = paykassa.create_order( amount: 0.01, currency: 'BTC', order_id: 1, comment: "Payment №1", system: 11 ) #    raise StandardError.new(result[:message]) if result[:error] url = result[:data][:url] #       url: redirect_to url 

For node.js:


 var https = require('https'); var querystring = require('querystring'); function mergeArray(array1,array2) { for(item in array1) { array2[item] = array1[item]; } return array2; } function PayKassaApi(sci_id, sci_key, domain, test) { this.sci_id = sci_id; this.sci_key = sci_key; this.domain = domain; this.test = test || false; }; PayKassaApi.methods = [ 'sci_create_order', 'sci_confirm_order' ] PayKassaApi.prototype.sendRequest = function(method, params, callback) { if (PayKassaApi.methods.indexOf(method) === -1) { throw new Error('wrong method name ' + method) }; if (callback == null) { callback = params; }; var data = { method: method, sci_id: this.sci_id, sci_key: this.sci_key, domain: this.domain, test: this.test } data = mergeArray(params, data) var body = querystring.stringify(data); var options = { host: 'paykassa.pro', port: 443, path: '/sci/0.3/index.php', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }; var request = https.request(options, function (response) { var result = ''; response.setEncoding('utf8'); response.on('data', function (chunk) { result += chunk; }); // Listener for intializing callback after receiving complete response response.on('end', function () { try { callback(JSON.parse(result)); } catch (e) { console.error(e); callback(result); } }); }); request.write(body) request.end() }; for (var i = 0; i < PayKassaApi.methods.length; i++) { PayKassaApi.prototype[PayKassaApi.methods[i]] = function (method) { return function (params, callback) { this.sendRequest(method, params, callback) } }(PayKassaApi.methods[i]) } module.exports = PayKassaApi 

Using:


 var PayKassa = require("./paykassa") var paykassa = new Api({ sci_id: 0, sci_key: '123', domain: 'habratest.ngrok.io', test: true }) paykassa.sci_create_order({ amount: 0.01, currency: 'BTC', order_id: 1, comment: 'test order №1', system: 1 }, function (res) { if (res.error) { //   -  Exception throw new Error(res.message) } else { //       /   console.log(res.data.url) } }) 

For python:


 import httplib import urllib import json class PayKassa: sci_domain = 'paykassa.pro' sci_path = '/sci/0.3/index.php' def __init__(self, sci_id, sci_key, domain, test): self.sci_id = sci_id self.sci_key = sci_key self.domain = domain self.test = test and 'true' or 'false' def sci_create_order(self, amount, currency, order_id, comment, system): return self.make_request({ 'func': 'sci_create_order', 'amount': amount, 'currency': currency, 'order_id': order_id, 'comment': comment, 'system': system }) def sci_confirm_order(self, private_hash): return self.make_request({ 'func': 'sci_confirm_order', 'private_hash': private_hash }) def make_request(self, params): fields = {'sci_id': self.sci_id, 'sci_key': self.sci_key, 'domain': self.domain, 'test': self.test}.copy() fields.update(params) encoded_fields = urllib.urlencode(fields) headers = {'Content-Type': 'application/x-www-form-urlencoded'} conn = httplib.HTTPSConnection(self.sci_domain) conn.request('POST', self.sci_path, encoded_fields, headers) response = conn.getresponse() return json.loads(response.read()) 

Using:


 paykassa = PayKassa(0, '123', 'habratest.ngrok.io', False) result = paykassa.sci_create_order(0.001, 'BTC', 1, 'Order number 1', 11) if result['error']: print(result['message']) else: print(result['data']['url']) 

The request itself is a regular multipart form / data POST request.


Description of parameters:



In response, you will receive a similar JSON:


 { "error": false, "message": "  ", "data": { "url": "https://paykassa.pro/sci/redir.php?hash=HASH", "method": "GET", "params": { "hash": "HASH" } } } 

From it we are interested in the error key and data.url . If error is false , then you can redirect the user to the address specified in data.url .


If you go to this address in non-test mode, you can see the payment page:


Payment page


Check payment


After making the payment, PayKassa will contact you at the server address specified in the field "Handler URL" when creating the store. This appeal will contain only the order ID, without its status. To get the status of the order (successfully processed or not) - you need to make a request indicating the received identifier:


 curl https://paykassa.pro/sci/0.3/index.php -d 'func=sci_confirm_order&private_hash=PRIVATE_HASH&sci_id=SCI_ID&sci_key=SCI_KEY&domain=DOMAIN&test=true' -H 'Content-type: application/x-www-form-urlencoded' 

Example for ruby:


  paykassa = Paykassa.new private_hash = params[:private_hash] #  RoR / sinatra result = paykassa.confirm_order(private_hash) #    raise StandardError.new(result[:message]) if result[:error] order_id = res[:data][:order_id] # ID  amount = res[:data][:amount] #   

Python example:


 paykassa = PayKassa(0, '123', 'habratest.ngrok.io', False) result = paykassa.confirm_order(request.POST['private_hash']) #   Django if result['error']: print(result['message']) else: print(result['data']['order_id']) print(result['data']['amount']) 

Well, an example for node.js:


 var PayKassa = require("./paykassa") var paykassa = new Api({ sci_id: 0, sci_key: '123', domain: 'habratest.ngrok.io', test: true }) paykassa.sci_confirm_order({ private_hash: req.body.private_hash //   express }, function (res) { if (res.error) { //   -  Exception throw new Error(res.message) } else { //       console.log(res.data.order_id) console.log(res.data.amount) } }) 

In response, a similar JSON will come:


 {"error":false,"message":"  ","data":{"transaction":"XXX","shop_id":"XXX","order_id":"1","amount":"0.01","currency":"BTC","system":"bitcoin","hash":"HASH"}} 

Everything is standard here - if error is false - it means that the payment for the data.order_id order for the amount of data.amount was successful. data.amount contains the actual payment amount received. Depending on your logic of processing orders and issuing payments, it is sometimes necessary to check it (for example, transfer of funds, where the user himself specifies the amount), sometimes not (for example, if the user cannot in any way directly affect the amount of the order or we credit the amount without commission).


Also, it is worth noting that at about the same time the user is redirected to the URL of a successful / unsuccessful payment.


On this process, the basic integration can be considered successfully completed. As you can see, the integration of the aggregator turned out to be much simpler than the implementation of receiving payments by yourself. If your volumes are less than $ 100- $ 1000 per month - then this method is likely to be more profitable for you.


')

Source: https://habr.com/ru/post/351550/


All Articles