API Documentation
API документация — это ваш быстрый вход в интеграцию с нашим платёжным шлюзом. Ниже вы найдёте правила формирования ссылок на платёжную страницу, подписи запросов, формат вебхуков и готовые примеры кода для Node.js и Python, чтобы запустить приём платежей за считанные минуты.
Редирект пользователя на платёжное окно
Сформируйте подпись и соберите URL
- Создайте проект, и получите ключи
- Посчитайте подпись (sha256 → base64)
- Сделайте редирект на https://payment.twizzygate.tech/
Базовый URL и параметры
Базовый URL:
Copied!
https://payment.twizzygate.tech/
| Параметр | Тип | Обязат. | Пример | Описание |
|---|---|---|---|---|
| orderNum | string | Да | 456 | ID заказа на стороне мерчанта |
| amount | number | Да | 100.00 | Сумма (с двумя знаками или целое) |
| currency | string | Да | RUB | Валюта |
| client | string | Да | pub_123 | Публичный ключ клиента |
| sign | string | Да | Base64 | Подпись (см. ниже) |
Важно! Из набора для подписи исключите client и sign. Сортируйте ключи, склейте key=value через & и добавьте в конец secret без имени.
Подпись запроса
- Исключите client и sign из запроса.
- Отсортируйте ключи по алфавиту (ASCII).
- Соберите строку: k1=v1&k2=v2&...&secret .
- Вычислите sha256 → base64.
Copied!
// ⚠️ Считайте подпись на сервере. Секрет не уходит на фронт.
import crypto from "node:crypto";
type Params = Record<string, string | number | undefined>;
function makeSign(params: Params, secret: string): string {
const entries = Object.entries(params)
.filter(([k, v]) => k !== 'client' && k !== 'sign' && v !== undefined)
.sort(([a], [b]) => a.localeCompare(b));
const base = entries.map(([k, v]) => `${k}=${v}`).join('&') + `&${secret}`;
const digest = crypto.createHash('sha256').update(base, 'utf8').digest();
return Buffer.from(digest).toString("base64");
}
const params = { orderNum: "456", amount: "100.00", currency: "RUB", client: "pub_123" };
const secret = "my_secret";
const sign = makeSign(params, secret);
console.log(sign);Тест-векторы
params: {amount: "100.00", currency: "RUB", orderNum: "456"}, secret:
my_secretbase:
amount=100.00¤cy=RUB&orderNum=456&my_secretsign:
KhizMnxNLB/XuSSoLhLZJz/+oq4nwLr3UVTeOYNOWlo=params: { amount: "1200.50", currency: "RUB", orderNum: "ORD-1001" }, secret:
sec_abcbase:
amount=1200.50¤cy=RUB&orderNum=ORD-1001&sec_abcsign:
xrgISoNmltwflMXLOvLIgqK6omiLIY9F2I6aXASo0MI=Советы: используйте стабильный формат суммы (например 100.00), не включайте пустые поля в подпись, храните секрет только на бекенде.
Примеры
Готовый URL
Copied!
https://payment.twizzygate.tech/?orderNum=456&amount=100.00¤cy=RUB&client=pub_123&sign=KhizMnxNLB%2FXuSSoLhLZJz%2F%2Boq4nwLr3UVTeOYNOWlo%3DcURL
Copied!
curl -L
"https://payment.twizzygate.tech/?orderNum=456&amount=100.00¤cy=RUB&client=pub_123&sign=KhizMnxNLB%2FXuSSoLhLZJz%2F%2Boq4nwLr3UVTeOYNOWlo%3D"Ошибки
При некорректной подписи пользователь увидит ошибку.
Коллбек с результатом операции (Webhook)
После обработки платежа мы отправим POST-запрос на ваш бекенд с результатом операции. URL для коллбека вы настраиваете в панели управления проекта.
Метод
POST
URL
Указывается вами в настройках проекта (например: https://merchant.com/payment/callback).
Заголовки
| Название | Описание |
|---|---|
| X-Client-Key | Публичный ключ клиента |
| X-Signature | Подпись запроса (см. раздел ниже). Используется для проверки, что запрос исходит от нас. |
Тело запроса (application/json)
{
"orderNum": "456",
"status": "success",
"details": {}
}- orderNum — ID заказа на вашей стороне.
- status — статус операции: "success", "fail" или "cancel".
- details — объект с дополнительной информацией (зарезервировано, может быть пустым).
Подпись коллбека (X-Signature)
Для защиты от подмены запросов каждый коллбек подписывается. Вам необходимо на своей стороне пересчитать подпись и сравнить с заголовком X-Signature.
- Используйте поля orderNum и status из тела запроса.
- Отсортируйте их по алфавиту ключей.
- Соберите строку в формате key=value через & и добавьте в конец ваш секретный ключ (без имени).
- Посчитайте SHA-256 от строки и закодируйте результат в Base64.
- Сравните полученное значение с заголовком X-Signature .
Пример строки для подписи (если orderNum=456 , status=success , секрет sec_abc ):
orderNum=456&status=success&sec_abc
Node.js пример проверки
import crypto from "node:crypto";
function makeSignature(body, secret) {
const params = {
orderNum: body.orderNum,
status: body.status,
};
const entries = Object.entries(params)
.filter(([, v]) => v !== undefined && v !== null)
.sort(([a], [b]) => a.localeCompare(b));
const base = entries.map(([k, v]) => `${k}=${v}`).join("&") + `&${secret}`;
const digest = crypto.createHash("sha256").update(base, "utf8").digest();
return Buffer.from(digest).toString("base64");
}
function isValidCallback(reqBody, headers, secret) {
const expected = makeSignature(reqBody, secret);
const received = String(headers["x-signature"] || "");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}Python пример проверки
import hmac, hashlib, base64
def make_signature(body: dict, secret: str) -> str:
params = {
"orderNum": body.get("orderNum"),
"status": body.get("status"),
}
items = sorted((k, v) for k, v in params.items() if v is not None)
base = "&".join(f"{k}={v}" for k, v in items) + f"&{secret}"
digest = hashlib.sha256(base.encode("utf-8")).digest()
return base64.b64encode(digest).decode("ascii")
def is_valid_callback(body: dict, headers: dict, secret: str) -> bool:
expected = make_signature(body, secret)
received = headers.get("X-Signature", "")
return hmac.compare_digest(expected, received)Важно:
- Секретный ключ храните только на сервере.
- Проверяйте X-Client-Key и соответствие вашему проекту.
- Используйте timing safe сравнение строк при проверке подписи.