API использует JSON формат для обмена данными. Все запросы должны содержать обязательные заголовки для аутентификации и подписи.
Базовый URL: https://your-api-domain.com (уточните у администратора)
Формат данных: JSON
Кодировка: UTF-8
Каждый запрос должен содержать следующие заголовки:
| Заголовок | Описание | Обязательность |
|---|---|---|
X-Key-ID |
Идентификатор ключа (выдается администратором) | Обязательно |
X-Signature |
Подпись тела запроса в формате base64 | Обязательно (если требуется для ключа) |
Пример заголовков:
X-Key-ID: your-key-id-12345
X-Signature: base64-encoded-signature
Подпись X-Signature обеспечивает целостность и аутентичность данных запроса. Процесс формирования подписи состоит из следующих шагов:
Пример тела запроса:
{"order_id":"order-12345","amount":10000,"external_id":"ext-12345"}
Вычислите SHA-256 хеш от байтового представления тела запроса:
hash = SHA256(body_bytes)
Подпишите хеш с помощью приватного RSA ключа, соответствующего X-Key-ID. Используется алгоритм RSA PKCS#1 v1.5:
signature_bytes = RSA_Sign(hash, private_key, PKCS1v15)
Параметры:
Закодируйте полученную подпись в base64:
X-Signature = base64_encode(signature_bytes)
Поддерживаются два варианта кодирования:
X-Key-ID. Убедитесь, что используете правильный приватный ключ, соответствующий сертификату.Эндпоинт: POST /check
Описание: Проверяет существование заказа и возвращает его данные (сумму, телефон, описание, статус).
Заголовки:
X-Key-ID: your-key-id
X-Signature: base64-encoded-signature
Тело запроса:
{
"order_id": "order-12345"
}
Параметры:
order_id (string, обязательно) - идентификатор заказа мерчанта{
"success": true,
"amount": 10000,
"phone": "+79991234567",
"description": "Оплата заказа",
"status": "new"
}
Поля ответа:
success (boolean) - всегда true при успешном ответеamount (integer) - сумма заказа в минимальных единицах валюты (копейки для RUB)phone (string) - номер телефонаdescription (string) - описание заказаstatus (string) - статус заказа (см. раздел Статусы заказов)Если заказ найден, но есть ошибка валидации (например, заказ уже оплачен):
{
"success": false,
"amount": 10000,
"phone": "+79991234567",
"description": "Оплата заказа",
"status": "completed",
"error": "validation error: completed"
}
Если заказ просрочен:
{
"success": false,
"amount": 10000,
"phone": "+79991234567",
"description": "Оплата заказа",
"status": "expired",
"expired_at": "2024-12-31T23:59:59Z",
"error": "validation error: expired"
}
Если заказ не найден или данные недоступны:
{
"success": false,
"error": "system error"
}
curl -X POST "https://api.example.com/check" \
-H "X-Key-ID: your-key-id" \
-H "X-Signature: base64-encoded-signature" \
-H "Content-Type: application/json" \
-d '{"order_id":"order-12345"}'
Эндпоинт: POST /pay
Описание: Инициирует и завершает транзакцию оплаты заказа.
Важно: Параметр external_id является обязательным и должен быть уникальным для каждой попытки оплаты.
Заголовки:
X-Key-ID: your-key-id
X-Signature: base64-encoded-signature
Тело запроса (успешная оплата):
{
"order_id": "order-12345",
"amount": 10000,
"external_id": "ext-12345"
}
Параметры:
order_id (string, обязательно) - идентификатор заказа мерчантаamount (integer, обязательно) - сумма платежа в минимальных единицах валюты. Должна быть больше 0external_id (string, обязательно) - внешний идентификатор транзакции (уникальный для каждой попытки оплаты){
"success": true,
"transaction_id": "txn-12345",
"status": "completed"
}
Поля ответа:
success (boolean) - всегда true при успешном ответеtransaction_id (string) - идентификатор созданной транзакцииstatus (string) - финальный статус заказа после обработки транзакции (см. раздел Статусы заказов и транзакций)Если транзакция была создана, но есть ошибка валидации:
{
"success": false,
"transaction_id": "txn-12345",
"status": "declined",
"error": "validation error: transaction amount not match order amount: 10000, 5000"
}
Если транзакция не была создана:
{
"success": false,
"error": "system error"
}
curl -X POST "https://api.example.com/pay" \
-H "X-Key-ID: your-key-id" \
-H "X-Signature: base64-encoded-signature" \
-H "Content-Type: application/json" \
-d '{
"order_id": "order-12345",
"amount": 10000,
"external_id": "ext-12345"
}'
API возвращает статус заказа в поле status ответов. Доступны следующие статусы:
| Статус | Значение | Финальный | Описание |
|---|---|---|---|
new |
Новый заказ | Нет | Заказ создан и готов к оплате. В этом статусе заказ может быть оплачен через эндпоинт /pay |
in_progress |
Заказ в процессе | Нет | Заказ находится в процессе оплаты. Транзакция создана, но еще не завершена |
completed |
Заказ завершен | Да | Заказ успешно оплачен. Транзакция завершена без ошибок |
declined |
Заказ отклонен | Да | Заказ отклонен из-за ошибки при оплате. Транзакция завершена с ошибкой |
expired |
Заказ просрочен | Нет | Срок действия заказа истек (TTL). Заказ автоматически переходит в этот статус при истечении срока действия |
1. Создание заказа
└─> status: "new"
2. Начало оплаты (POST /pay)
├─> Заказ: status: "in_progress"
3. Завершение оплаты
├─> Если успешно (error отсутствует):
│ ├─> Заказ: status: "completed"
│
└─> Если ошибка (error указан):
├─> Заказ: status: "declined"
4. Истечение срока действия (TTL)
└─> Заказ: status: "expired" (автоматически)
5. Оплата просроченного заказа (POST /pay для заказа со статусом expired)
├─> Если успешно (error отсутствует):
│ ├─> Заказ: status: "completed"
│
└─> Если ошибка (error указан):
├─> Заказ: status: "declined"
new или expired. Если заказ уже в статусе in_progress, completed или declined, попытка оплаты вернет ошибку. При оплате заказа в статусе expired статус изменится в соответствии с результатом транзакции (completed или declined).expired. Заказ в статусе expired может быть оплачен.completed или declined) заказ не может быть оплачен повторно. Для новой попытки оплаты необходимо создать новый заказ./check возвращает текущий статус заказа. Если заказ в статусе new, он готов к оплате./pay возвращает финальный статус заказа после завершения транзакции (completed или declined).| Код | Описание |
|---|---|
| 200 OK | Запрос успешно обработан |
| 400 Bad Request | Ошибка валидации, проверки подписи или бизнес-логики |
| 500 Internal Server Error | Внутренняя ошибка сервера |
Все ошибки возвращаются в формате JSON:
{
"success": false,
"error": "Описание ошибки"
}
"order_id is required" - не указан обязательный параметр order_id"external_id is required" - не указан обязательный параметр external_id (только для эндпоинта /pay)"validation error: X-Key-ID header is required" - не указан заголовок X-Key-ID"validation error: X-Signature header is required" - не указан заголовок X-Signature (если требуется для ключа)"signature verification failed: signature is required for key {key_id}, but certificate is empty" - для ключа требуется подпись, но сертификат не настроен"failed to decode signature: ..." - неверный формат подписи (не base64)"signature verification failed: public key MD5 hash: {hash}" - подпись не прошла проверку. В сообщении об ошибке указан MD5 хеш публичного ключа для отладки. Для проверки соответствия ключа и сертификата см. раздел Проверка соответствия ключа и сертификата"system error" - внутренняя ошибка сервера (может возникать, если заказ не найден)"validation error: completed" - заказ уже имеет статус completed и не может быть оплачен"validation error: declined" - заказ имеет статус declined и не может быть оплачен"validation error: in_progress" - заказ находится в процессе оплаты и не может быть оплачен повторно"validation error: expired" - срок действия заказа истек, заказ имеет статус expired. Заказ в статусе expired может быть оплачен через /pay"validation error: transaction amount not match order amount: {order_amount}, {request_amount}" - сумма в запросе не совпадает с суммой заказаПри возникновении проблем:
X-Key-IDX-Key-IDДля работы с API необходимо сгенерировать пару ключей (приватный ключ и сертификат). Приватный ключ используется для формирования подписи запросов, а сертификат передается администратору API для настройки вашего X-Key-ID.
Выполните команды последовательно:
# 1. Генерация приватного ключа
openssl genrsa -out private_key.pem 2048
# 2. Генерация самоподписанного сертификата
openssl req -new -x509 -key private_key.pem -out certificate.crt -days 36500 \
-subj "/C=RU/ST=Moscow/L=Moscow/O=OOO MAP/CN=OOO MAP"
Параметры команды генерации ключа:
genrsa - команда генерации RSA ключа-out private_key.pem - имя выходного файла с приватным ключом2048 - размер ключа в битах (рекомендуется 2048 или больше)Параметры команды генерации сертификата:
req -new -x509 - создание нового самоподписанного сертификата-key private_key.pem - путь к приватному ключу-out certificate.crt - имя выходного файла с сертификатом-days 36500 - срок действия сертификата в днях (примерно 100 лет)-subj - параметры субъекта сертификата:
C=RU - Country (страна)ST=Moscow - State/Province (регион/область)L=Moscow - Locality/City (город)O=OOO MAP - Organization (организация)CN=OOO MAP - Common Name (имя сертификата)Результат:
private_key.pem - приватный ключ (хранить в безопасности, использовать для формирования подписи)certificate.crt - публичный сертификат (передать администратору API для настройки)Важно:
X-Key-IDopenssl x509 -in certificate.crt -text -noout
openssl x509 -in certificate.crt -noout -dates
# MD5 хеш публичного ключа из сертификата
openssl x509 -noout -modulus -in certificate.crt | openssl md5
# MD5 хеш публичного ключа из приватного ключа
openssl rsa -noout -modulus -in private_key.pem | openssl md5
Хеши должны совпадать, если ключ и сертификат соответствуют друг другу.
Используйте эту команду для проверки соответствия ключа и сертификата, если сервер возвращает следующую ошибку:
{
"success": false,
"error": "signature verification failed: public key MD5 hash: e0916118770af2f7dca5403adf4a9ef9"
}
Сравните MD5 хеш из ошибки с хешем, полученным из вашего приватного ключа. Если хеши не совпадают, значит используется неправильный приватный ключ или сертификат.
Ниже приведен практический пример формирования подписи для запроса к API.
В примерах ниже указаны приватный и публичный ключ (сертификат), соответствующие друг другу. MD5 hash публичного и приватного ключа: e0916118770af2f7dca5403adf4a9ef9.
Тело запроса (payload):
{"order_id":"order-12345","amount":10000,"external_id":"ext-12345"}
#!/bin/bash
# Тело запроса
PAYLOAD='{"order_id":"order-12345","amount":10000,"external_id":"ext-12345"}'
# Сохраняем payload
echo -n "$PAYLOAD" > payload.json
# Сохраняем приватный ключ
cat > private_key.pem << 'EOF'
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAsW+Lcu8SSUVHDL0GMsEAOQVkjMrBLoCUcpb+icwbRG8aI+En
OWv5lg6x6tayXR/8accVtKiT9aPeGRW00NGFwm5Uhyx0wlUfAH/ZYWYfbQndRdOI
nI6mEJrgO3Q3lNMhfdXIdVVDij5KGdF7OVfGETRGceqKgXVU6Ku1BiJBsHxf7dKO
/f++kXdVNF4QW7N+tp5LluE/GsA0NNWvRQrM5rlqwstwsCiTbMQugnKRYTy8gKRk
kNLaZma+v/854z9zbtbmCe8iHedLNx4Q9A+kRr5cJDQG1QOsoh95hj62dtlKA8Cp
ZVNil1zrBZ8fqXWG1Q9p4qeg05EwGLbKuPgrHwIDAQABAoIBAE3xlwttE9ZV9WkW
HAPtnmBuCwaCBqyb1RolVDlKDOxZ9dyvCmECGoidefCUUZPw+hupVdKffyeXzXet
flmAwMZxWvZqQ/weEllQ0Dgl+UYX4DjNPKSxUSfYMQpM+iGJQZwabk2En/+5bym6
SOwer6ZdFVjzU9acqSjwTLweDkctD8gsTakDMAp55I3uYClpqJF+9eHyeoLednUj
uhJEsBwaCMhUH3kwmT0RXJdImbOgswRB3tVT9ADnLRTF7fVfWU3H90nscPKQVWK8
XfyJi0t96U9PiPOnS3LLCqdOt7R8TZxGiYy5munHb34WIRDksNnfItNZgXHPtUEW
nH2mgiECgYEA5vsCiar55c3273CWL6RqK9MdgPvNjQw0IiL73PcEVI9106H5xuxQ
w1+843GzxYOcA5Z6hSC4W+rcoVxTUPxeaujd3aI0jjzB1bKhnjnJyzl3devlD82N
g0BH5myWDAL/Drnt+AIuCRhmXA+bL58Sop11Zvy7pHGG6RcF/He+TLECgYEAxKfC
zKjsdXLgM+X9cbBTSs3hmS7qtz8wLMAIA9pGyyOJTEmZkEARTnCd4xmXZ1YfpSN+
PfPGAWny7+xtBqKOj2sLZ1cYAEtPDr+vLBaR7obC8szxwziUkoYXcaT0BNmG208M
5PykpVf+eFxuYscMFA/DqBX2wZomLACmxSEEqM8CgYALXcTFM4Wymk0RgU/SrluP
JodoJnv5+eTC3UfZmso6wwiATpM1B8H9q0NnSdwX1x8hShFjZbXMyCTtR9bNwG2B
A06ProC5kyHSu0SavatBdeV8Bwyxl2LkV5ByNVu44Zjdh6a/MpRDXFEFLLttP32y
RN9XHw64y+FgrQJdZyMVMQKBgCLaVKTu/1FldaTdCwj+JhTo3iXG8eReN4yG0CTW
p5tTBf9WP/gX0rljLihUnce7tMoQu0wBi0Mu4tZwwXXek4OJhjDfd6p9rlo/0Kzw
pxZuHdjoR6TAv1wklb0XbgP6BXOS1Ac1W3zOVpRAVXP+MP7ROGzuz5fKWR+NUgE3
89pzAoGAF9h3ORH0mzEPYPYlZgiVj78aXsySSpz0AIo62qaFTvYUDE6310wdlzkF
zUULvRilHWR0lMEUzij55d/cGx79oJ2sg7jKtBt8Wi2p/JlKlsITiXitOVAUSKmO
p5Qz2mJsvXiNBGZClWBcmOqA97JzIHc4B5V2SPP9JNsAObjsZi4=
-----END RSA PRIVATE KEY-----
EOF
# Вычисляем SHA-256 хеш и подписываем его
SIGNATURE=$(openssl dgst -sha256 -sign private_key.pem payload.json | base64)
# Выводим результат
echo "X-Signature: $SIGNATURE"
# Очистка
rm -f payload.json private_key.pem
После выполнения скрипта вы получите подпись в формате base64, которую нужно использовать в заголовке X-Signature:
X-Signature: JU2Y+dqw1pk5pENGjeos6TjfNPheSUEFh2wjt2QE+QSw+UeQQ38+54VOEtF4VbQPXx2hcpZXmeNcO9vmn+L6VqIrd4G6OTEonYKbde49izWJexIrvC7rTPUf1DTSSQjQcwgjeCTR/VbJ9RcasHv3jPAntPgJe6WnDcTaOiD58TOCIK2onGBJLJrktnhPIqkbQeOwQsytWiu0qYfVOVAJhHmTIHKgfh01aktyFCxZwml1vPuW5S3nXy1286+COSmPCwLqG12WmrXxkj3oAzhvO3JEaABZyzMt8/xlOiWC5SSGgP9OfY2Osk280928K65NNfW8ddG3i78taW7rTpCZRg==
Пример готового запроса:
curl -X POST "https://api.example.com/pay" \
-H "X-Key-ID: your-key-id" \
-H "X-Signature: JU2Y+dqw1pk5pENGjeos6TjfNPheSUEFh2wjt2QE+QSw+UeQQ38+54VOEtF4VbQPXx2hcpZXmeNcO9vmn+L6VqIrd4G6OTEonYKbde49izWJexIrvC7rTPUf1DTSSQjQcwgjeCTR/VbJ9RcasHv3jPAntPgJe6WnDcTaOiD58TOCIK2onGBJLJrktnhPIqkbQeOwQsytWiu0qYfVOVAJhHmTIHKgfh01aktyFCxZwml1vPuW5S3nXy1286+COSmPCwLqG12WmrXxkj3oAzhvO3JEaABZyzMt8/xlOiWC5SSGgP9OfY2Osk280928K65NNfW8ddG3i78taW7rTpCZRg==" \
-H "Content-Type: application/json" \
-d '{"order_id":"order-12345","amount":10000,"external_id":"ext-12345"}'
Для проверки корректности формирования подписи можно использовать следующий скрипт. Скрипт проверяет, что подпись была создана с помощью приватного ключа, соответствующего публичному ключу из сертификата.
#!/bin/bash
# Параметры
PAYLOAD='{"order_id":"order-12345","amount":10000,"external_id":"ext-12345"}'
SIGNATURE="JU2Y+dqw1pk5pENGjeos6TjfNPheSUEFh2wjt2QE+QSw+UeQQ38+54VOEtF4VbQPXx2hcpZXmeNcO9vmn+L6VqIrd4G6OTEonYKbde49izWJexIrvC7rTPUf1DTSSQjQcwgjeCTR/VbJ9RcasHv3jPAntPgJe6WnDcTaOiD58TOCIK2onGBJLJrktnhPIqkbQeOwQsytWiu0qYfVOVAJhHmTIHKgfh01aktyFCxZwml1vPuW5S3nXy1286+COSmPCwLqG12WmrXxkj3oAzhvO3JEaABZyzMt8/xlOiWC5SSGgP9OfY2Osk280928K65NNfW8ddG3i78taW7rTpCZRg=="
CERT="-----BEGIN CERTIFICATE-----
MIIDiTCCAnGgAwIBAgIUE1slBc9rLKOtRSAKpTOZuByJ3UswDQYJKoZIhvcNAQEL
BQAwUzELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9z
Y293MRAwDgYDVQQKDAdPT08gTUFQMRAwDgYDVQQDDAdPT08gTUFQMCAXDTI1MTEw
ODE1MTUwNFoYDzIxMjUxMDE1MTUxNTA0WjBTMQswCQYDVQQGEwJSVTEPMA0GA1UE
CAwGTW9zY293MQ8wDQYDVQQHDAZNb3Njb3cxEDAOBgNVBAoMB09PTyBNQVAxEDAO
BgNVBAMMB09PTyBNQVAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx
b4ty7xJJRUcMvQYywQA5BWSMysEugJRylv6JzBtEbxoj4Sc5a/mWDrHq1rJdH/xp
xxW0qJP1o94ZFbTQ0YXCblSHLHTCVR8Af9lhZh9tCd1F04icjqYQmuA7dDeU0yF9
1ch1VUOKPkoZ0Xs5V8YRNEZx6oqBdVToq7UGIkGwfF/t0o79/76Rd1U0XhBbs362
nkuW4T8awDQ01a9FCszmuWrCy3CwKJNsxC6CcpFhPLyApGSQ0tpmZr6//znjP3Nu
1uYJ7yId50s3HhD0D6RGvlwkNAbVA6yiH3mGPrZ22UoDwKllU2KXXOsFnx+pdYbV
D2nip6DTkTAYtsq4+CsfAgMBAAGjUzBRMB0GA1UdDgQWBBTZpDlJyLzXMhMaBReB
rK2OKvZehDAfBgNVHSMEGDAWgBTZpDlJyLzXMhMaBReBrK2OKvZehDAPBgNVHRMB
Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAZssMBGG4xp7i4zp5ZOOWmYBSS
Wb5DYdytreSRbEeB+mXC2Kp1hZ7sET2YANjTctDX3KS42IreiCK5VUK+JDvIZsE3
25/6eI92QdWIzpjUI9QI92pPgyyPqPhI0GQ7kkHF2HYrsvtNlKD5sA0Q4o6xjZrK
bN4StPPs9qSu+66+PqB9ZRN7F7orOAfa2bmLBOBXpt/3aRb2Ua1+gNYlJSfEF9wP
r6hnARwAZNj20DkxuN36FXqf9BQ07BgieWvYtl9COnaBnM+/pWrPKSyvzU2FR98o
KZxQPNQmDWQ33g149rG6j19rkaZWSvfAR9PbqJI8Rpr1tcnPNE2SiSOtZ9EI
-----END CERTIFICATE-----"
# Временные файлы
TMP_CERT=$(mktemp)
TMP_PUBKEY=$(mktemp)
TMP_SIGNATURE=$(mktemp)
TMP_PAYLOAD=$(mktemp)
trap "rm -f $TMP_CERT $TMP_PUBKEY $TMP_SIGNATURE $TMP_PAYLOAD" EXIT
# Запись сертификата во временный файл
echo "$CERT" > "$TMP_CERT"
# Запись payload во временный файл
echo -n "$PAYLOAD" > "$TMP_PAYLOAD"
# Декодирование base64 подписи во временный файл
if ! echo "$SIGNATURE" | base64 -d > "$TMP_SIGNATURE" 2>/dev/null; then
echo "✗ Ошибка: не удалось декодировать подпись из base64"
exit 1
fi
# Извлечение публичного ключа из сертификата
if ! openssl x509 -in "$TMP_CERT" -pubkey -noout > "$TMP_PUBKEY" 2>/dev/null; then
echo "✗ Ошибка: не удалось извлечь публичный ключ из сертификата"
exit 1
fi
# Проверка подписи (RSA с SHA256, как в коде)
if openssl dgst -sha256 -verify "$TMP_PUBKEY" -signature "$TMP_SIGNATURE" "$TMP_PAYLOAD"; then
echo "✓ Подпись верна"
exit 0
else
echo "✗ Подпись неверна"
exit 1
fi
Скрипт выполняет следующие действия:
openssl dgst для проверки подписи с алгоритмом SHA-256 и RSA PKCS#1 v1.5.verify_signature.sh).chmod +x verify_signature.sh.PAYLOAD, SIGNATURE и CERT на ваши данные../verify_signature.sh.✓ Подпись верна и завершится с кодом 0.✗ Подпись неверна и завершится с кодом 1.