Host-to-host
Host-to-host (H2H): your page or app shows the payer where to transfer, and the payer never leaves you. You take on what the hosted page does — showing the account, the countdown, the outcome.
1. Name the method and the payer’s bank
Section titled “1. Name the method and the payer’s bank”When you know how the payer pays, say so in payment_method. The account is then given without asking the
payer anything:
#!/usr/bin/env bash# Create a payment whose method and payer's bank you know: the account comes without the payment page.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", "payment_method": { "type": "bank_transfer", "payer_institution": "${PAYER_BANK:-boc}" }}JSON)mka_request POST "/v1/payments" "$body" "$(mka_new_key)"// Create a payment whose method and payer's bank you know: the account comes without the payment page.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", payment_method: { type: "bank_transfer", payer_institution: process.env.PAYER_BANK ?? "boc", }, }, idempotencyKey: newKey(),});print(answer);<?php// Create a payment whose method and payer's bank you know: the account comes without the payment page.
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', 'payment_method' => [ 'type' => 'bank_transfer', 'payer_institution' => getenv('PAYER_BANK') ?: 'boc', ], ], mka_new_key(),));"""Create a payment whose method and payer's bank you know: the account comes without the payment page."""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", "payment_method": { "type": "bank_transfer", "payer_institution": os.environ.get("PAYER_BANK", "boc"), }, }, idempotency_key=new_key(),))//go:build ignore
// Create a payment whose method and payer's bank you know: the account comes without the payment page.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", "payment_method": map[string]any{ "type": "bank_transfer", "payer_institution": signedrequest.Env("PAYER_BANK", "boc"), }, }, signedrequest.NewKey()))}type— the method. Today:bank_transfer, a transfer to an account. Methods are data: new ones may appear without a new API version.payer_institution— optional, the payer’s bank:boc(Bank of Ceylon),peoples(People’s Bank),combank(Commercial Bank of Ceylon),hnb(Hatton National Bank),ndb(NDB Bank),sampath(Sampath Bank), orother. It is a preference: an account in that bank while one has room, any other after it — then the transfer goes between banks through CEFTS.
A method or a bank the catalog does not list is 422 method_unavailable.
2. Show the account
Section titled “2. Show the account”Read the payment until it is requires_action with customer_action.kind: bank_transfer — usually a few
seconds after creation — and show exactly what it says:
"customer_action": { "kind": "bank_transfer", "bank_transfer": { "bank_name": "Bank of Ceylon", "account_name": "K. A. Perera", "account_number": "0081234567" }},"expires_at": "2026-10-22T18:49:01Z"#!/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, ""))}- Show the exact amount: a different amount is not matched to the payment.
- Show
payment_referencewhen it is present; the payer puts it in the transfer’s description. - Count down to
expires_at. After it, hide the account: a transfer then is credited only by support. - Never cache the account. Each
GETanswers it fresh and stops answering it once it may no longer be used.
3. Follow the status
Section titled “3. Follow the status”The same statuses and webhooks as any payment (lifecycle). On succeeded,
tell the payer; on failed with expired, offer to try again with a new payment.
When the payer should choose
Section titled “When the payer should choose”Without payment_method, a project that lets payers choose answers requires_action with
customer_action.kind: method_selection: the methods and banks on offer, and selection_expires_at. The choice
is made on checkout_url — send the payer there. Unchosen within 30 minutes, the payment fails expired.
A kind you do not know: also send the payer to checkout_url.