Перейти к основному содержимому

Создание платежа

Пример

Запрос

URL

POSThttps://api-merchant.alikassa.io/v1/payment📋

Заголовки:

  • Content-Type: application/json
  • Account: UUID вашего счета (доступен по адресу: Счета проекта)
  • Sign: Подпись запроса

Перейдите в Настройки API сертификатов и сгенерируйте «API сертификат на оплаты». Сохраните и распакуйте архив:

  • password.txt
  • private.pem
  • public.pem

Мы сохраняем только public.pem для проверки подписи.

Оберните все POST-данные в JSON (в том же порядке) и подпишите:

$data = json_encode($data);

$privateKey = openssl_pkey_get_private(
file_get_contents('private.pem'),
file_get_contents('password.txt')
);

if ($privateKey === false) {
throw new \Exception('Ошибка сертификата.');
}

openssl_sign($data, $sign, $privateKey);
$sign = base64_encode($sign);
import { readFileSync } from 'fs';
import { createSign } from 'crypto';

const dataStr = JSON.stringify(data);
const privateKeyPem = readFileSync('private.pem', 'utf8');
const passphrase = readFileSync('password.txt', 'utf8').trim();
const signer = createSign('SHA1');
signer.update(dataStr);
signer.end();
const signature = signer.sign(
{ key: privateKeyPem, passphrase: passphrase },
'base64'
);
import json
import base64
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

data_bytes = json.dumps(data).encode('utf-8')
with open('password.txt', 'rb') as f:
password = f.read().strip()
with open('private.pem', 'rb') as f:
private_key = serialization.load_pem_private_key(
f.read(),
password=password
)
signature = private_key.sign(
data_bytes,
padding.PKCS1v15(),
hashes.SHA1()
)
sign = base64.b64encode(signature).decode('utf-8')
import java.io.FileReader;
import java.nio.charset.StandardCharsets;
import java.security.Signature;
import java.util.Base64;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;

ObjectMapper mapper = new ObjectMapper();
String dataStr = mapper.writeValueAsString(data);
char[] pass = new String(java.nio.file.Files.readAllBytes(
java.nio.file.Paths.get("password.txt")
)).toCharArray();
PEMParser parser = new PEMParser(new FileReader("private.pem"));
PEMEncryptedKeyPair ckp = (PEMEncryptedKeyPair) parser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
PrivateKey privateKey = converter.getKeyPair(
ckp.decryptKeyPair(
new JcePEMDecryptorProviderBuilder().build(pass)
)
).getPrivate();
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initSign(privateKey);
sig.update(dataStr.getBytes(StandardCharsets.UTF_8));
String sign = Base64.getEncoder().encodeToString(sig.sign());
package main

import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"io/ioutil"
)

func main() {
dataBytes, _ := json.Marshal(data)
pemBytes, _ := ioutil.ReadFile("private.pem")
passBytes, _ := ioutil.ReadFile("password.txt")
block, _ := pem.Decode(pemBytes)
der, _ := x509.DecryptPEMBlock(block, passBytes)
priv, _ := x509.ParsePKCS1PrivateKey(der)
hash := sha1.Sum(dataBytes)
sigBytes, _ := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA1, hash[:])
sign := base64.StdEncoding.EncodeToString(sigBytes)
}

Полученную подпись $sign передайте в заголовке Sign.


Обязательные поля

NameTypeDescription
amount *decimal (11.2)Amount
order_id *string (128)Your unique ID
service *string (100)Service
descstring (128)Description
lifetimeintLifetime in seconds (900–3600)
customer_ip *ipPayer IP address
customer_accountstring (50)Customer ID in your system
customer_emailstring (50)Email address
customer_first_namestring (50)First name
customer_last_namestring (50)Last name
customer_addressstring (50)Address
customer_phonestring (12)Phone number
customer_post_codeint (12)Postal code
customer_statestring (50)State
customer_citystring (20)City
customer_browser_user_agent*string (2000)Browser user agent
success_redirect_idintRedirect ID after success
fail_redirect_idintRedirect ID after failure
notification_endpoint_idintNotification ID
success_redirect_urlstring (max 255)Redirect URL after success
fail_redirect_urlstring (max 255)Redirect URL after failure
notification_endpoint_urlstring (max 255)Callback URL for status notifications
project_urlstringProject URL (for aggregators)

Ответ

НазваниеОписание
idID платежа AliKassa
uuidUUID платежа AliKassa
urlСсылка на оплату
payment_statusСтатус платежа

Изначально payment_status всегда wait. Проверяйте статус через API или ожидайте уведомления.

Пример успешного ответа (HTTP 200):

{
"url": "https://pay-merchant.alikassa.io/bd291fe1-5c19-4113-ae62-a2d3c4d01d20",
"payment_status": "wait",
"id": 100001524,
"uuid": "h12a5a34-7e21-3789-bf53-96fe96131601"
}

Пример ошибки (HTTP 400):

{
"message": "The given data was invalid.",
"errors": {
...
}
}

После получения URL переадресуйте клиента по ссылке на оплату.

Проверка статуса платежа

При создании всегда ждите, проверяйте статус платежа через API или ждите получение уведомления!


Уведомления

Настройка уведомлений

Если вы передали notification_endpoint_id, то вы получите уведомление о смене статуса оплаты


Пример кода

Скачанный архив распакуйте в папку «путь до скрипта/cert/payment/»

function requestPayment(string $method, string $account, array $data)
{
$data = json_encode($data);

$privateKey = openssl_pkey_get_private(
file_get_contents(__DIR__ . '/cert/payment/private.pem'),
file_get_contents(__DIR__ . '/cert/payment/password.txt')
);

if ($privateKey === false) {
throw new \Exception('Ошибка сертификата.');
}

openssl_sign($data, $sign, $privateKey);
$sign = base64_encode($sign);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api-merchant.alikassa.io/' . $method);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Account: ' . $account,
'Sign: ' . $sign,
]);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, 'AliKassa2.0 API');
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

$response = curl_exec($ch);

return json_decode($response, true);
}

$payment = requestPayment('v1/payment', '93d5df06-996c-48c3-9847-348d6b580b80', [
'order_id' => (string)time(),
'amount' => 500,
'customer_browser_user_agent' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0',
'customer_ip' => '18.191.80.10',
'success_redirect_id' => 1,
'fail_redirect_id' => 1,
'notification_endpoint_id' => 5,
'service' => 'payment_card_rub_hpp',
]);

var_dump($payment);
import { readFileSync } from 'fs';
import { createSign } from 'crypto';
import https from 'https';

async function requestPayment(method, account, data) {
const dataStr = JSON.stringify(data);
const privateKeyPem = readFileSync('cert/payment/private.pem', 'utf8');
const passphrase = readFileSync('cert/payment/password.txt', 'utf8').trim();
const signer = createSign('SHA1');
signer.update(dataStr);
signer.end();
const sign = signer.sign({ key: privateKeyPem, passphrase }, 'base64');

const options = {
hostname: 'api-merchant.alikassa.io',
path: `/${method}`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
Account: account,
Sign: sign,
'User-Agent': 'AliKassa2.0 API',
},
timeout: 30000,
};

return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
let body = '';
res.on('data', (chunk) => (body += chunk));
res.on('end', () => resolve(JSON.parse(body)));
});
req.on('error', reject);
req.write(dataStr);
req.end();
});
}

(async () => {
const payment = await requestPayment(
'v1/payment',
'93d5df06-996c-48c3-9847-348d6b580b80',
{
order_id: String(Date.now()),
amount: 500,
customer_browser_user_agent:
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0',
customer_ip: '18.191.80.10',
success_redirect_id: 1,
fail_redirect_id: 1,
notification_endpoint_id: 5,
service: 'payment_card_rub_hpp',
}
);
console.log(payment);
})();
import json
import base64
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
import requests

def request_payment(method: str, account: str, data: dict):
data_bytes = json.dumps(data).encode('utf-8')
with open('cert/payment/password.txt', 'rb') as f:
password = f.read().strip()
with open('cert/payment/private.pem', 'rb') as f:
private_key = serialization.load_pem_private_key(f.read(), password=password)
signature = private_key.sign(data_bytes, padding.PKCS1v15(), hashes.SHA1())
sign = base64.b64encode(signature).decode('utf-8')
headers = {
'Content-Type': 'application/json',
'Account': account,
'Sign': sign,
'User-Agent': 'AliKassa2.0 API',
}
resp = requests.post(f'https://api-merchant.alikassa.io/{method}', data=data_bytes, headers=headers, timeout=30)
return resp.json()

payment = request_payment('v1/payment', '93d5df06-996c-48c3-9847-348d6b580b80', {
'order_id': str(int(__import__('time').time())),
'amount': 500,
'customer_browser_user_agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0',
'customer_ip': '18.191.80.10',
'success_redirect_id': 1,
'fail_redirect_id': 1,
'notification_endpoint_id': 5,
'service': 'payment_card_rub_hpp',
})
print(payment)
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Signature;
import java.util.Base64;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import java.io.FileReader;

public class Example {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
var data = Map.of(
"order_id", String.valueOf(System.currentTimeMillis()),
"amount", 500,
"customer_browser_user_agent", "Mozilla/5.0 ...",
"customer_ip", "18.191.80.10",
"success_redirect_id", 1,
"fail_redirect_id", 1,
"notification_endpoint_id", 5,
"service", "payment_card_rub_hpp"
);
String dataStr = mapper.writeValueAsString(data);
char[] pass = Files.readString(Paths.get("cert/payment/password.txt")).toCharArray();
PEMParser parser = new PEMParser(new FileReader("cert/payment/private.pem"));
PEMEncryptedKeyPair ckp = (PEMEncryptedKeyPair) parser.readObject();
var kp = new JcaPEMKeyConverter().getKeyPair(
ckp.decryptKeyPair(new JcePEMDecryptorProviderBuilder().build(pass))
);
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initSign(kp.getPrivate());
sig.update(dataStr.getBytes(StandardCharsets.UTF_8));
String sign = Base64.getEncoder().encodeToString(sig.sign());
HttpRequest request = HttpRequest.newBuilder()
.uri(java.net.URI.create("https://api-merchant.alikassa.io/v1/payment"))
.header("Content-Type", "application/json")
.header("Account", "93d5df06-996c-48c3-9847-348d6b580b80")
.header("Sign", sign)
.header("User-Agent", "AliKassa2.0 API")
.POST(HttpRequest.BodyPublishers.ofString(dataStr))
.build();
var client = HttpClient.newHttpClient();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(mapper.readValue(response.body(), Object.class));
}
}
package main

import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"io/ioutil"
"net/http"
"time"
"bytes"
"fmt"
)

func signData(data interface{}) (string, error) {
dataBytes, _ := json.Marshal(data)
pemBytes, _ := ioutil.ReadFile("cert/payment/private.pem")
passBytes, _ := ioutil.ReadFile("cert/payment/password.txt")
block, _ := pem.Decode(pemBytes)
der, _ := x509.DecryptPEMBlock(block, passBytes)
priv, _ := x509.ParsePKCS1PrivateKey(der)
hash := sha1.Sum(dataBytes)
sigBytes, _ := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA1, hash[:])
return base64.StdEncoding.EncodeToString(sigBytes), nil
}

func requestPayment(method, account string, data interface{}) (map[string]interface{}, error) {
sign, _ := signData(data)
dataBytes, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api-merchant.alikassa.io/"+method, bytes.NewReader(dataBytes))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Account", account)
req.Header.Set("Sign", sign)
req.Header.Set("User-Agent", "AliKassa2.0 API")
client := &http.Client{Timeout: 30 * time.Second}
resp, _ := client.Do(req)
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
return result, nil
}

func main() {
payment, _ := requestPayment("v1/payment", "93d5df06-996c-48c3-9847-348d6b580b80", map[string]interface{}{
"order_id": time.Now().Unix(),
"amount": 500,
"customer_browser_user_agent": "Mozilla/5.0 ...",
"customer_ip": "18.191.80.10",
"success_redirect_id": 1,
"fail_redirect_id": 1,
"notification_endpoint_id": 5,
"service": "payment_card_rub_hpp",
})
fmt.Println(payment)
}