Руководство интегратора

API Платежей

Введение в Payments API v2

Для приёма через Payments v2 (кроме A-GATE) у мерчанта один эндпоинт созданияPOST /api/v2/payments/create — и один набор полей по Swagger: обязательны merchant_site_id, operation_id, amount (копейки RUB); остальное опционально по сценарию. Код метода в теле запроса не передаётся — платформа подставляет параметры приёма по настройке торговой точки. Опрос: GET /api/v2/payments/{payment_id}/status.

В текстах руководства сценарии без проверки ФИО по выписке называются «СБП без авторизации» и «PayIN_OOP»; для интеграции это один и тот же контракт API, без отдельных URL и без дополнительных полей для «типа приёма».

A-GATE (A_GATE): приём платежей через API платформы V-DAR по инструкции A-GATE v2.0 — отдельные эндпоинты /api/v2/a-gate/... и при необходимости POST /api/v2/altyn/payments/create (витрина). Это не POST /api/v2/payments/create. Подробности — вкладка «A-GATE».

Источник правды по полям и схемам: Swagger UI — группа payments_v2.
Сумма amount: для RUB — целое число копеек (минимум 100 = 1 ₽). Пример: 11 ₽ → 1100.
  • СБП с авторизацией (код в ответе GET /payments/methods — справочно): нужны payer_name и payer_token, ФИО сверяется с токеном.
  • СБП без авторизации и PayIN_OOP: те же POST /create и поля; payer_name и payer_token не обязательны; в ответе — payment_url для плательщика, qr_code может быть null.
  • A-GATE (A_GATE): создание платежа — POST /api/v2/altyn/payments/create (витрина) и/или POST /api/v2/a-gate/gate/payment/bank/…, POST /api/v2/a-gate/payment/sbp/; статус — GET /api/v2/a-gate/payment/{payment_id}/ или GET /api/v2/payments/{payment_id}/status. Swagger: a-gate, altyn-payments.

Какой метод у торговой точки

GET /api/v2/payments/methods?merchant_site_id=<UUID>

Требуется X-API-Key (readonly или full_access). В ответе — code, is_enabled, комиссии и лимиты точки.

curl -sS "https://api.v-dar.ru/api/v2/payments/methods?merchant_site_id=YOUR_SITE_UUID" \
  -H "X-API-Key: YOUR_KEY"

Поток СБП с авторизацией плательщика и проверкой ФИО

  1. POST /payments/auth-url — получить auth_url, открыть пользователю.
  2. После прохождения авторизации: получить токен — GET /payments/user/{user_id} или ваш callback_url.
  3. POST /payments/create с payer_name (как в токене) и payer_token.
  4. Отдать пользователю payment_url / QR.
  5. GET /payments/{payment_id}/status — опрос до финального статуса.
Тело create (пример)
{
  "merchant_site_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "operation_id": "ORDER-998877",
  "amount": 150000,
  "description": "Оплата заказа #998877",
  "payer_name": "Иванов Иван Иванович",
  "payer_token": "gAAAAABl...",
  "sbp_redirectURL": "https://yoursite.com/payment-success"
}

СБП без авторизации и PayIN_OOP — один запрос создания

Для обоих сценариев используется тот же POST /api/v2/payments/create и тот же перечень полей, что в Swagger. Дополнительных параметров «типа приёма» нет: достаточно суммы и идентификаторов; условные поля авторизации не обязательны. Редирект после оплаты при необходимости укажите в sbp_redirectURL (если поддерживается для вашей точки).

{
  "merchant_site_id": "YOUR_SITE_UUID",
  "operation_id": "ORDER-unique-123",
  "amount": 1100,
  "description": "Оплата 11 RUB",
  "sbp_redirectURL": "https://yoursite.com/thanks"
}
Ответ create (актуальная форма)
{
  "payment_id": "uuid",
  "payment_url": "https://merchant.example/acq/...",
  "qr_code": null,
  "created_at": "2026-03-28T12:00:00.000000Z",
  "expires_at": "2026-03-28T12:45:00.000000Z",
  "operation_id": "ORDER-unique-123",
  "description": "Оплата 11 RUB",
  "amount": 1100,
  "method_code": "<код_из_GET_/payments/methods>"
}

Поле status в ответе на create не возвращается — статус смотрите через GET /payments/{id}/status.

METHOD_NOT_CONFIGURED: для точки не настроен активный приём — обратитесь в поддержку V-DAR. QR_CREATION_FAILED: сбой этапа создания платежа; форма POST /create у мерчанта не меняется по типу точки — при повторяющейся ошибке обратитесь в поддержку.

A-GATE — приём платежей через платформу V-DAR

Согласовано с официальной инструкцией A-GATE для мерчанта (версия 2.0, 2026-03-20). Текст веб-руководства: 6.0. Базовый URL API: https://api.v-dar.ru. Поля и схемы — Swagger a-gate, altyn-payments, API v1.

Не использовать POST /api/v2/payments/create для торговой точки с методом A_GATE: для такой точки приём оформлен отдельными эндпоинтами ниже (ожидается подсказка об этом в ответе API).
1. Общая схема

Аутентификация мерчанта: заголовок X-API-Key с типом full_access (для операций создания и опроса в группе a-gate). Префикс пути: /api/v2/a-gate/ либо /api/v2/altyn/payments/ для витрины.

  • GET /api/v2/a-gate/client/{phone} — проверка клиента (уровень идентификации, счёт).
  • POST /api/v2/a-gate/gate/upload/ + PUT на выданный URL — загрузка паспорта/селфи (получаете file_key).
  • POST /api/v2/a-gate/client/ — регистрация клиента с identity (file_key документов).
  • POST /api/v2/a-gate/gate/payment/bank/{sber|vtb|tbank}/ — оплата deeplink выбранного банка (account_number, сумма строкой в рублях, external_id ≤ 40 символов).
  • GET /api/v2/a-gate/sbp_banks — справочник банков СБП.
  • POST /api/v2/a-gate/payment/sbp/ — создание платежа СБП (bank_id из справочника).
  • GET /api/v2/a-gate/payment/{payment_id}/ — детальный статус платежа A-GATE.
  • GET /api/v2/a-gate/rate — котировка курса (опционально).
  • POST /api/v2/altyn/payments/create — сценарий витрины: только payment_method_type: "showcase"; сумма amount в копейках RUB; нужен клиент с идентификацией в A-GATE по payer_phone.
2. Витрина (showcase) — краткий поток
  1. Убедиться, что плательщик прошёл KYC (иначе API вернёт требование POST /api/v2/a-gate/client/).
  2. POST /api/v2/altyn/payments/create с телом: merchant_site_id, operation_id, amount (копейки), payer_phone, payment_method_type: "showcase", при необходимости callback_url.
  3. Открыть пользователю showcase_url / payment_url из ответа.
  4. Опрос: GET /api/v2/payments/{payment_id}/status или GET /api/v2/a-gate/payment/{payment_id}/ (один и тот же UUID payment_id из ответа создания).
3. СБП / банк — краткий поток
  1. Подготовка документов и POST /api/v2/a-gate/client/ (см. Swagger).
  2. Создание платежа: POST .../payment/sbp/ или POST .../gate/payment/bank/sber/ (и т.д.).
  3. Опционально callbackURL в теле — POST на URL мерчанта при смене статуса (формат как у ответа статуса).
  4. Опрос статуса — как в п.2. Эндпоинт POST /api/v2/a-gate/payments/callback — служебный приём на V-DAR (HMAC), не вызывается мерчантом.
Примеры (витрина + статус)

Замените YOUR_KEY, UUID торговой точки и телефон.

# 1) Витрина (amount — копейки, 10000 = 100 ₽)
curl -sS -X POST "https://api.v-dar.ru/api/v2/altyn/payments/create" \
  -H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"merchant_site_id":"YOUR_SITE_UUID","operation_id":"ord-'"$(date +%s)"'","amount":10000,"payer_phone":"+79991234567","payment_method_type":"showcase"}'

# 2) Статус (тот же payment_id из JSON ответа)
curl -sS "https://api.v-dar.ru/api/v2/payments/PAYMENT_UUID/status" \
  -H "X-API-Key: YOUR_KEY"

# (опционально) детальный статус A-GATE
curl -sS "https://api.v-dar.ru/api/v2/a-gate/payment/PAYMENT_UUID/" \
  -H "X-API-Key: YOUR_KEY"
import requests

BASE = "https://api.v-dar.ru/api/v2"
KEY = "YOUR_KEY"
site = "YOUR_SITE_UUID"

r = requests.post(
    f"{BASE}/altyn/payments/create",
    headers={"X-API-Key": KEY, "Content-Type": "application/json"},
    json={
        "merchant_site_id": site,
        "operation_id": "ord-001",
        "amount": 10000,
        "payer_phone": "+79991234567",
        "payment_method_type": "showcase",
    },
    timeout=60,
)
r.raise_for_status()
data = r.json()
pid = data["payment_id"]
print("Open:", data.get("showcase_url") or data.get("payment_url"))

st = requests.get(f"{BASE}/payments/{pid}/status", headers={"X-API-Key": KEY}, timeout=60)
print("V-DAR status:", st.json())

ag = requests.get(f"{BASE}/a-gate/payment/{pid}/", headers={"X-API-Key": KEY}, timeout=60)
print("A-GATE detail:", ag.json())
$key = getenv("VDAR_API_KEY");
$site = "YOUR_SITE_UUID";
$payload = json_encode([
  "merchant_site_id" => $site,
  "operation_id" => "ord-" . bin2hex(random_bytes(4)),
  "amount" => 10000,
  "payer_phone" => "+79991234567",
  "payment_method_type" => "showcase",
]);
$ch = curl_init("https://api.v-dar.ru/api/v2/altyn/payments/create");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => ["X-API-Key: $key", "Content-Type: application/json"],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);
$create = json_decode(curl_exec($ch), true);
curl_close($ch);
$pid = $create["payment_id"];
$stCh = curl_init("https://api.v-dar.ru/api/v2/payments/" . urlencode($pid) . "/status");
curl_setopt_array($stCh, [
  CURLOPT_HTTPHEADER => ["X-API-Key: $key"],
  CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($stCh);
curl_close($stCh);
const key = process.env.VDAR_API_KEY;
const site = "YOUR_SITE_UUID";
const create = await fetch("https://api.v-dar.ru/api/v2/altyn/payments/create", {
  method: "POST",
  headers: { "X-API-Key": key, "Content-Type": "application/json" },
  body: JSON.stringify({
    merchant_site_id: site,
    operation_id: "ord-" + crypto.randomUUID(),
    amount: 10000,
    payer_phone: "+79991234567",
    payment_method_type: "showcase",
  }),
});
const created = await create.json();
const pid = created.payment_id;
const st = await fetch(`https://api.v-dar.ru/api/v2/payments/${pid}/status`, {
  headers: { "X-API-Key": key },
});
console.log(await st.json());
using System.Net.Http.Json;
using System.Text.Json;

var key = Environment.GetEnvironmentVariable("VDAR_API_KEY");
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", key!);
var body = new {
    merchant_site_id = "YOUR_SITE_UUID",
    operation_id = "ord-" + Guid.NewGuid().ToString("N")[..12],
    amount = 10000,
    payer_phone = "+79991234567",
    payment_method_type = "showcase"
};
var res = await client.PostAsJsonAsync(
    "https://api.v-dar.ru/api/v2/altyn/payments/create", body);
res.EnsureSuccessStatusCode();
var created = await res.Content.ReadFromJsonAsync<JsonElement>();
var pid = created.GetProperty("payment_id").GetString()!;
var st = await client.GetAsync(
    $"https://api.v-dar.ru/api/v2/payments/{Uri.EscapeDataString(pid)}/status");
Console.WriteLine(await st.Content.ReadAsStringAsync());

MCP: два инструмента для сценария витрины на хосте V-DAR (секреты только на сервере прокси).

{
  "tools": [
    {
      "name": "agate_showcase_create",
      "description": "Создать платёж A-GATE витрина: POST https://api.v-dar.ru/api/v2/altyn/payments/create (amount в копейках, payment_method_type showcase).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "merchant_site_id": { "type": "string" },
          "operation_id": { "type": "string" },
          "amount_kopeks": { "type": "integer" },
          "payer_phone": { "type": "string" },
          "callback_url": { "type": "string" }
        },
        "required": ["merchant_site_id", "operation_id", "amount_kopeks", "payer_phone"]
      }
    },
    {
      "name": "agate_payment_status",
      "description": "Статус платежа V-DAR: GET /api/v2/payments/{payment_id}/status или GET /api/v2/a-gate/payment/{payment_id}/",
      "inputSchema": {
        "type": "object",
        "properties": {
          "payment_id": { "type": "string" },
          "detail": { "type": "boolean", "description": "true = a-gate детальный ответ" }
        },
        "required": ["payment_id"]
      }
    }
  ]
}

Handler: все запросы с заголовком X-API-Key; не вызывать /api/v2/payments/create для точки A_GATE.

Примеры: create + status (СБП без авторизации)

Замените YOUR_KEY, YOUR_SITE_UUID, PAYMENT_ID.

# create
curl -sS -X POST "https://api.v-dar.ru/api/v2/payments/create" \
  -H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"merchant_site_id":"YOUR_SITE_UUID","operation_id":"order-'"$(date +%s)"'","amount":1100,"description":"11 RUB","sbp_redirectURL":"https://example.com/ok"}'

# status
curl -sS "https://api.v-dar.ru/api/v2/payments/PAYMENT_ID/status" \
  -H "X-API-Key: YOUR_KEY"
import requests, uuid
B = "https://api.v-dar.ru/api/v2/payments"
H = {"X-API-Key": "YOUR_KEY", "Content-Type": "application/json"}
r = requests.post(f"{B}/create", headers=H, json={
    "merchant_site_id": "YOUR_SITE_UUID",
    "operation_id": f"ord-{uuid.uuid4().hex[:12]}",
    "amount": 1100,
    "description": "11 RUB",
    "sbp_redirectURL": "https://example.com/ok",
}, timeout=60)
r.raise_for_status()
data = r.json()
s = requests.get(f"{B}/{data['payment_id']}/status", headers={"X-API-Key": "YOUR_KEY"}, timeout=60)
print(s.json())
const base = "https://api.v-dar.ru/api/v2/payments";
const headers = { "X-API-Key": "YOUR_KEY", "Content-Type": "application/json" };
const create = await fetch(`${base}/create`, {
  method: "POST", headers,
  body: JSON.stringify({
    merchant_site_id: "YOUR_SITE_UUID",
    operation_id: "ord-" + crypto.randomUUID(),
    amount: 1100,
    description: "11 RUB",
    sbp_redirectURL: "https://example.com/ok"
  })
});
const { payment_id, payment_url } = await create.json();
const st = await fetch(`${base}/${payment_id}/status`, { headers: { "X-API-Key": "YOUR_KEY" } });
console.log(await st.json());
using System.Net.Http.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_KEY");
var body = new {
    merchant_site_id = "YOUR_SITE_UUID",
    operation_id = "ord-" + Guid.NewGuid().ToString("N")[..12],
    amount = 1100,
    description = "11 RUB",
    sbp_redirectURL = "https://example.com/ok"
};
var res = await client.PostAsJsonAsync("https://api.v-dar.ru/api/v2/payments/create", body);
res.EnsureSuccessStatusCode();
var created = await res.Content.ReadFromJsonAsync<System.Text.Json.JsonElement>();
var pid = created.GetProperty("payment_id").GetString();
var st = await client.GetAsync($"https://api.v-dar.ru/api/v2/payments/{pid}/status");
Console.WriteLine(await st.Content.ReadAsStringAsync());
$key = "YOUR_KEY";
$payload = json_encode([
  "merchant_site_id" => "YOUR_SITE_UUID",
  "operation_id" => "ord-" . bin2hex(random_bytes(6)),
  "amount" => 1100,
  "description" => "11 RUB",
  "sbp_redirectURL" => "https://example.com/ok",
]);
$ch = curl_init("https://api.v-dar.ru/api/v2/payments/create");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => ["X-API-Key: $key", "Content-Type: application/json"],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
]);
$out = curl_exec($ch);
curl_close($ch);
$data = json_decode($out, true);
$ch2 = curl_init("https://api.v-dar.ru/api/v2/payments/{$data['payment_id']}/status");
curl_setopt_array($ch2, [
  CURLOPT_HTTPHEADER => ["X-API-Key: $key"],
  CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($ch2);

Для СБП с авторизацией добавьте в JSON поля payer_name и payer_token и предварительно выполните шаги из вкладки «СБП с авторизацией».

Идемпотентность: необязательное поле idempotency_key (до 128 символов) — повторный POST с тем же ключом возвращает тот же платёж без повторного создания.

Проверка статуса

GET /api/v2/payments/{payment_id}/status

Опрос каждые 3–5 с до финального статуса: PAID_VERIFIED, FAILED_REJECTED, FAILED_VERIFICATION, REFUNDED, PARTIALLY_REFUNDED, EXPIRED (неоплачен), либо устаревшие PAID / FAILED.

Запрос актуализирует статус для Payments v2. Для платежей A-GATE (созданных через /api/v2/a-gate/... или /api/v2/altyn/payments/create) используйте тот же payment_id здесь или GET /api/v2/a-gate/payment/{payment_id}/ — см. вкладку «A-GATE».

Пример ответа (успех)
{
  "payment_id": "789e4567-e89b-12d3-a456-426614174000",
  "status": "PAID_VERIFIED",
  "operation_id": "ORDER-998877",
  "amount": 150000,
  "created_at": "2025-01-25T12:30:00Z",
  "paid_at": "2025-01-25T12:32:15Z",
  "name_verification_status": "VERIFIED",
  "payment_url": "...",
  "qrc_id": "..."
}

Поступление на баланс торговой точки

После PAID_VERIFIED проверьте баланс через API v1 (тот же X-API-Key):

curl -sS "https://api.v-dar.ru/api/v1/merchants/balance/YOUR_SITE_UUID" \
  -H "X-API-Key: YOUR_KEY"

История операций: GET /api/v1/operations/ — см. руководство по кодам и операциям.

Исходящие выплаты на карту (KHM_PAY)

Для торговой точки с подключённым и включённым методом выплат KHM_PAY доступны эндпоинты группы khm-payouts в Swagger. Аутентификация: заголовок X-API-Key с правом full_access.

Создание выплаты

POST https://api.v-dar.ru/api/v2/payouts/khm (на стенде замените хост).

ПолеОбяз.Описание
merchant_site_idдаUUID торговой точки (метод KHM_PAY должен быть включён для точки).
operation_idдаУникальный идентификатор операции у мерчанта (в рамках мерчанта).
amountдаСумма выплаты получателю в рублях (десятичное, например 100.00).
currency_codeнетПо умолчанию RUB; иначе поддерживается только RUB.
card_noдаНомер карты получателя (PAN).
first_nameдаИмя держателя карты.
last_nameдаФамилия держателя карты.
channelнетКанал провайдера; если не передан — значение по умолчанию на стороне платформы.
idempotency_keyнетДо 128 символов; повтор с тем же ключом возвращает ту же выплату без повторного создания у провайдера.
Проверка баланса до создания: перед резервом средств платформа проверяет, что на балансе торговой точки достаточно средств на сумму выплаты + комиссии. Комиссия считается по процентам, заданным для метода KHM_PAY на этой торговой точке (в т.ч. доля платформы и агентов). Если средств недостаточно — ответ 400, текст «Недостаточно средств на балансе торговой точки», в details — код INSUFFICIENT_BALANCE и поля payout_amount, fee_amount, required_total, available_balance, currency_code.
Статус выплаты

GET https://api.v-dar.ru/api/v2/payouts/khm/{payout_id}

СтатусСмысл
createdСоздана запись (кратковременно до резерва).
awaiting_providerЗарезервировано на Hold, ожидается/выполняется создание у провайдера.
processingПлатёж у провайдера в обработке (ожидает опроса статуса).
succeededВыплата успешно завершена, проводки зафиксированы.
failedВыплата отклонена или ошибка провайдера; резерв возвращён на точку (если применимо).
refundedВозврат по выплате (служебный конечный статус при возврате).

Фоновый опрос нефинальных выплат у провайдера выполняет процесс payment-status-checker на стороне платформы (периодичность задаётся конфигурацией окружения, по умолчанию порядка минут). Для ручной проверки в тесте можно вызывать GET …/payouts/khm/{id} периодически.

Режим demo провайдера (тестовые PAN)

При включённом demo у провайдера выплат поведение по тестовым номерам карт (последовательности известны из документации провайдера):

Номер карты (PAN)Ожидаемое поведение
4111111111100031Успешная выплата сразу.
4111111111100023Успех после ожидания порядка 2 минут (нужен опрос статуса / воркер).
4111111111100072Неуспех сразу.
4111111111100056Неуспех после ожидания порядка 2 минут.
другие допустимые в demoИсход успех/неуспех через случайное время 0–10 минут.

Сумму amount согласуйте с лимитами demo; для регресса фиксируйте одну сумму (например 100.00 ₽) на все кейсы, если провайдер не требует иного.

План регрессионного тестирования через API V-DAR

Перед прогоном подготовьте: тестового мерчанта, merchant_site_id с включённым KHM_PAY, X-API-Key с full_access, достаточный баланс точки (с запасом под комиссию), уникальные operation_id на каждый кейс. База API: https://api.v-dar.ru (или стенд).

  1. Предусловия: GET /api/v2/payments/methods?merchant_site_id=… — в ответе есть активный метод с кодом KHM_PAY. GET /api/v1/merchants/balance/{merchant_site_id} — зафиксировать баланс до тестов.
  2. TC-INSUFFICIENT: Запрос POST /api/v2/payouts/khm с суммой amount, заведомо большей, чем баланс с учётом комиссии. Ожидание: HTTP 400, сообщение о недостатке средств, details.code = INSUFFICIENT_BALANCE, числовые поля в details согласованы с ручным расчётом (выплата + комиссия).
  3. TC-CARD-OK-IMMEDIATE: PAN 4111111111100031, уникальный operation_id. Ожидание: HTTP 200, status в ответе стремится к финальному успеху; GET …/payouts/khm/{payout_id}succeeded (возможен краткий awaiting_provider/processing). Проверить проводки: повторный GET …/balance/…, при необходимости GET /api/v1/operations/ — суммы резерва/списания согласованы с total_reserved из ответа.
  4. TC-CARD-OK-DELAYED: PAN 4111111111100023. После создания опрашивать GET …/payouts/khm/{id} каждые 15–30 с до 4 мин; ожидание перехода в succeeded около 2 мин ± допуск. Убедиться, что воркер/checker не оставляет выплату вечно в processing.
  5. TC-CARD-FAIL-IMMEDIATE: PAN 4111111111100072. Ожидание: failed, резерв возвращён, last_error присутствует при необходимости; баланс точки восстановлен относительно резерва.
  6. TC-CARD-FAIL-DELAYED: PAN 4111111111100056. Опрос до 4 мин; ожидание failed после задержки ~2 мин.
  7. TC-CARD-RANDOM: Любой другой допустимый PAN в demo. Опрос до 12 мин; зафиксировать фактический финальный статус и время. Повторный прогон может отличаться — норма для random.
  8. TC-DUPLICATE-OP: Повторить POST …/payouts/khm с тем же operation_id. Ожидание: отказ (дубликат операции).
  9. TC-IDEMPOTENCY: Дважды одинаковый запрос с одним idempotency_key и одинаковым телом. Ожидание: второй ответ с duplicate: true, одна выплата в системе.
  10. TC-STATUS-POLL: Для одной «долгой» выплаты сравнить поля external_payment_id, смену статусов и отсутствие расхождения с логами payment-status-checker на стороне платформы (по согласованию с администратором).
  11. Постусловия: сверка баланса точки и выборочно цепочки операций; убедиться, что нет «зависших» сумм на Hold для финальных succeeded/failed.

После того как вы передадите агенту тестовые merchant_site_id и ключ API (только в защищённом канале, не в публичных логах), можно автоматизировать шаги через скрипт или CI; до этого план выполняется вручную по чеклисту выше.

Автоматический черновик прогона: scripts/khmpay_vdar_api_regression.py (--smoke или --full, переменные VDAR_API_BASE, VDAR_X_API_KEY, VDAR_MERCHANT_SITE_ID).

Пример создания (curl)
curl -sS -X POST "https://api.v-dar.ru/api/v2/payouts/khm" \
  -H "X-API-Key: YOUR_FULL_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_site_id": "YOUR_SITE_UUID",
    "operation_id": "TEST-PAYOUT-001",
    "amount": "100.00",
    "currency_code": "RUB",
    "card_no": "4111111111100031",
    "first_name": "TEST",
    "last_name": "USER"
  }'

Статусы платежей

СтатусОписание
CREATEDПлатёж создан, ожидает оплаты
PAID_PENDING_VERIFICATIONОплачен, проверяется ФИО
PAID_VERIFIEDОплачен и проверен, средства зачислены
PAID_MANUAL_REVIEWОплачен, требует ручной проверки (не найден в выписке за 45 минут)
FAILED_REJECTEDОтклонён при обработке платежа (RJCT)
FAILED_VERIFICATIONНе прошёл проверку ФИО (MISMATCH)
REFUNDINGВозврат в процессе
REFUNDEDПолностью возвращён
PARTIALLY_REFUNDEDЧастично возвращён
EXPIREDИстёк срок (45 минут), только для неоплаченных платежей
Старые статусы (для обратной совместимости):
PENDINGЭквивалент PAID_PENDING_VERIFICATION
PAIDЭквивалент PAID_VERIFIED или PAID_MANUAL_REVIEW
FAILEDЭквивалент FAILED_REJECTED или FAILED_VERIFICATION

Коды ошибок API (400 Bad Request)

Код ошибкиОписание
PAYER_NAME_MISMATCH Имя payer_name, переданное в запросе, не совпадает с именем, зашифрованным в payer_token. Возможна попытка подмены данных.
DUPLICATE_OPERATION_ID Платеж с таким operation_id уже существует. Используйте уникальные ID заказов.
AMOUNT_TOO_SMALL Сумма платежа меньше минимально допустимой (минимум 100 копеек = 1.00 RUB).
AMOUNT_TOO_LARGE Сумма платежа больше максимально допустимой (максимум 100000000 копеек = 1,000,000.00 RUB).
PAYMENT_CREATION_ERROR Общая ошибка создания платежа (внутренняя ошибка системы).
INVALID_TOKEN Не удалось расшифровать payer_token. Возможно, он поврежден или устарел.
SITE_NOT_FOUND Указанный merchant_site_id не существует или не принадлежит мерчанту ключа.
METHOD_NOT_CONFIGURED Для торговой точки не настроен активный способ приёма на стороне платформы. Тело POST /create менять не нужно — обратитесь в поддержку V-DAR.
QR_CREATION_FAILED Ошибка на этапе создания платежа; детали — в тексте ответа API. Тело POST /create для мерчанта едино для всех точек Payments v2 (кроме A-GATE); при устойчивой ошибке обратитесь в поддержку V-DAR.
HTTP 422 Ошибка валидации тела запроса (например, отсутствуют обязательные поля для выбранного метода).