Жизненный цикл и статусы платежа
Платёж — это перевод, который вы ждёте от плательщика. Вы создаёте платёж, плательщик платит, деньги
поступают на баланс проекта. POST /v1/payments отвечает сразу; остальное происходит асинхронно и приходит
к вам вебхуками.
#!/usr/bin/env bash# Create a payment and send the payer to its checkout_url.set -euo pipefail. "$(dirname "$0")/../signed-request.sh"
body=$(cat <<JSON{ "merchant_order_id": "${ORDER_ID:-order-$(mka_new_key)}", "amount": "${AMOUNT:-2500.00}", "currency": "LKR", "return_url": "https://shop.example.lk/orders/return"}JSON)mka_request POST "/v1/payments" "$body" "$(mka_new_key)"// Create a payment and send the payer to its checkout_url.import { newKey, print, request } from "../signed-request.mjs";
const answer = await request("POST", "/v1/payments", { body: { merchant_order_id: process.env.ORDER_ID ?? `order-${newKey()}`, amount: process.env.AMOUNT ?? "2500.00", currency: "LKR", return_url: "https://shop.example.lk/orders/return", }, idempotencyKey: newKey(),});print(answer);<?php// Create a payment and send the payer to its checkout_url.
declare(strict_types=1);
require __DIR__ . '/../signed_request.php';
mka_show(mka_request( 'POST', '/v1/payments', [ 'merchant_order_id' => getenv('ORDER_ID') ?: 'order-' . mka_new_key(), 'amount' => getenv('AMOUNT') ?: '2500.00', 'currency' => 'LKR', 'return_url' => 'https://shop.example.lk/orders/return', ], mka_new_key(),));"""Create a payment and send the payer to its checkout_url."""import os
from signed_request import new_key, request, show
show(request( "POST", "/v1/payments", body={ "merchant_order_id": os.environ.get("ORDER_ID") or f"order-{new_key()}", "amount": os.environ.get("AMOUNT", "2500.00"), "currency": "LKR", "return_url": "https://shop.example.lk/orders/return", }, idempotency_key=new_key(),))//go:build ignore
// Create a payment and send the payer to its checkout_url.package main
import ( "docs.processing.yolotech.cc/examples/signedrequest")
func main() { signedrequest.Show(signedrequest.Request("POST", "/v1/payments", map[string]any{ "merchant_order_id": signedrequest.Env("ORDER_ID", "order-"+signedrequest.NewKey()), "amount": signedrequest.Env("AMOUNT", "2500.00"), "currency": "LKR", "return_url": "https://shop.example.lk/orders/return", }, signedrequest.NewKey()))}Статусы
Заголовок раздела «Статусы»| Статус | Значение | Вебхук |
|---|---|---|
pending |
Принят. Подбираются реквизиты; обычно это секунды. | нет — об этом говорит ответ на создание |
requires_action |
Плательщику нужно действовать: перевести деньги на реквизиты из customer_action или выбрать способ оплаты на checkout_url. |
да |
processing |
Деньги пришли и зачисляются; или идёт отмена. | да |
succeeded |
Зачислен на ваш баланс. Финальный. Отгружайте заказ. | да |
failed |
Никто не заплатил (failure_code: expired) или ни один провайдер не принял платёж (declined). Финальный. |
да |
cancelled |
Отменён до прихода денег. Финальный. | да |
pending → requires_action → processing → succeeded │ ├→ processing (cancelling) → cancelled └→ failed (expired)pending → failed (declined)Финальный статус никогда не меняется. Оплаченным считайте только succeeded: processing значит, что
деньги подтверждены, но ещё не зачислены.
Что должен сделать плательщик
Заголовок раздела «Что должен сделать плательщик»Пока платёж ждёт плательщика, в нём есть customer_action и expires_at:
bank_transfer— реквизиты, на которые нужно перевести точную сумму:bank_name,account_name,account_numberи, если есть,payment_reference. Показывайте их доexpires_atили отправьте плательщика наcheckout_url— там их покажут за вас.method_selection— ваш проект разрешает плательщикам выбирать банк на странице. Отправьте плательщика наcheckout_url.- Незнакомый вам вид — отправьте плательщика на
checkout_url. Новые виды добавляются без новой версии API.
Окно оплаты и поздние переводы
Заголовок раздела «Окно оплаты и поздние переводы»Реквизиты действуют в течение окна (в песочнице — 3 минуты). Если окно закрылось без оплаты, платёж остаётся
requires_action, но без customer_action: опоздавший перевод ещё может зачислить поддержка провайдера,
и тогда платёж становится succeeded, а amount_received показывает, сколько пришло. Через 24 часа после
создания платёж становится failed с failure_code: expired и уже никогда не станет succeeded.
version растёт с каждым изменением. Вебхуки несут payment_version: применяйте событие, только если его
версия выше сохранённой у вас (порядок событий).
Источник истины — GET
Заголовок раздела «Источник истины — GET»Вебхук — это сигнал. Если сомневаетесь — пропущено событие, истёк таймаут, пришёл 503, — прочитайте платёж:
#!/usr/bin/env bash# Read a payment: the truth after a webhook, a timeout or a 503.set -euo pipefail. "$(dirname "$0")/../signed-request.sh"
payment_id=$(mka_required PAYMENT_ID)mka_request GET "/v1/payments/$payment_id"// Read a payment: the truth after a webhook, a timeout or a 503.import { print, request, required } from "../signed-request.mjs";
const paymentId = required("PAYMENT_ID");const answer = await request("GET", `/v1/payments/${paymentId}`);print(answer);<?php// Read a payment: the truth after a webhook, a timeout or a 503.
declare(strict_types=1);
require __DIR__ . '/../signed_request.php';
$paymentId = mka_required('PAYMENT_ID');mka_show(mka_request('GET', "/v1/payments/{$paymentId}"));"""Read a payment: the truth after a webhook, a timeout or a 503."""from signed_request import request, required, show
payment_id = required("PAYMENT_ID")show(request("GET", f"/v1/payments/{payment_id}"))//go:build ignore
// Read a payment: the truth after a webhook, a timeout or a 503.package main
import ( "docs.processing.yolotech.cc/examples/signedrequest")
func main() { paymentID := signedrequest.Required("PAYMENT_ID") signedrequest.Show(signedrequest.Request("GET", "/v1/payments/"+paymentID, nil, ""))}stage показывает, на каком этапе обработка (awaiting_payment, crediting, …), — это для экранов вашей
поддержки. Значений может стать больше; стройте логику на status.