Create payment
POST /v1/payment
Create an inbound payment. The merchant collects funds; InOut routes the operation to a configured provider and returns the current state.
Endpoint
POST /v1/payment
Content-Type: application/json
X-API-Key: 01234567-89ab-4cde-8f01-23456789abcdThe X-API-Key header is required — see
Authentication. The key fixes
the merchant and shop scope; do not send merchant_id or shop_id in
the body.
Request
| Field | Type | Required | Notes |
|---|---|---|---|
merchant_operation_id | string | yes | Idempotency key. Any non-empty string (UUID, hex, integer-as-string, …). Re-sending the same key with the same body returns the original operation; with a different body it returns 412 Precondition Failed. |
client_id | string | yes | Your end-user identifier. Any non-empty string. |
client_ip | string | no | Client IP address, used for antifraud. |
method | string | yes | Logical payment method, e.g. WT_RUB_C2C or WT_RUB_PHONE. See Payment methods. |
amount | string | yes | Decimal string with scale 2, e.g. "1500.00". |
currency | string | yes | ISO 4217 code, e.g. "RUB". |
number | string | no | Destination identifier — only consulted for payouts and ignored on payments. Card number for WT_RUB_C2C; phone number for WT_RUB_PHONE. |
name | string | no | Holder/recipient name on the destination. Same scoping as number. |
bankname | string | no | Destination bank — required for WT_RUB_PHONE payouts (sber, tcs); ignored for the card rail. |
The destination fields (number, name, bankname) form a unified
shape shared with POST /v1/payout. For payments
they are accepted but unused on the request — the inbound destination
the end user must transfer to is allocated by InOut and returned on
the response.
Example
curl -X POST https://api.alva.co.nl/v1/payment \
-H "Content-Type: application/json" \
-H "X-API-Key: 01234567-89ab-4cde-8f01-23456789abcd" \
-d '{
"merchant_operation_id": "8a26f5cf-1f56-4cda-8d8a-2a915b5e4b58",
"client_id": "57b8a4ca-3a4b-4f01-9a5e-1f29c1cefb9b",
"client_ip": "203.0.113.10",
"method": "WT_RUB_PHONE",
"amount": "1500.00",
"currency": "RUB"
}'Response
200 OK with the operation object. The gateway waits up to
15 seconds for a provider to accept the payment and produce usable requisites
or a confirmation requirement. It does not return a synthetic pending response
when no provider accepted the operation; that path rejects. An accepted payment
may remain non-terminal and its final state then arrives by
webhook.
When the chosen route requires a receipt confirmation, the create response
status is awaiting_confirmation (instead of pending). This means the
end user must upload a receipt via POST /v1/confirm_payment before the
payment can proceed. A webhook fires immediately on entry to
awaiting_confirmation so you can prompt the user; the terminal callback
fires once the receipt is reviewed and the payment reaches a terminal
status.
Operation object
{
"operation_id": "f6c2e7d4-3e5b-4f1f-8a02-9d6c7e8a1b22",
"type": "payment",
"status": "pending",
"method": "WT_RUB_PHONE",
"expected_amount": "1500.00",
"actual_amount": "0.00",
"currency": "RUB",
"fx_source": "rapira",
"fx_rate": "0.013000",
"settlement_amount": "19.11",
"settlement_currency": "USDT",
"commission_amount": "0.39",
"external_confirmation": {
"required": true,
"methods": ["receipt"]
},
"number": "+79991234567",
"name": "Ivan Ivanov",
"bankname": "sber"
}expected_amount mirrors what you sent. actual_amount is the physical fact
known for the operation; do not infer it from status or replace zero with the
requested amount. It is normally non-zero after money is processed; internal
operator surfaces may additionally show attempt-level physical facts that are
not fields of this public payment response.
When a route uses auto-conversion, fx_source and fx_rate are present as
soon as the route is chosen — this is a quote (expected amount × rate),
available well before the operation resolves. recorded_currency and
recorded_amount are the ledger fact (actual amount × rate) and appear
only once actual_amount is non-zero, i.e. once the operation has actually
processed money (completed, or a self-matching partial). A pending
response therefore carries only the fx_rate/fx_source quote — never
recorded_amount/recorded_currency. Example of a completed response on the
same operation:
{
"operation_id": "f6c2e7d4-3e5b-4f1f-8a02-9d6c7e8a1b22",
"type": "payment",
"status": "completed",
"method": "WT_RUB_PHONE",
"expected_amount": "1500.00",
"actual_amount": "1500.00",
"currency": "RUB",
"recorded_currency": "USDT",
"recorded_amount": "19.50",
"fx_source": "rapira",
"fx_rate": "0.013000",
"number": "+79991234567",
"name": "Ivan Ivanov",
"bankname": "sber"
}settlement_amount is the amount that moves on your balance net of the InOut
commission, in settlement_currency (the ledger currency, equal to currency
without conversion): for a payment it is what is credited to you after
commission, for a payout the total charged to you including commission.
commission_amount is the InOut commission. Before a terminal status these are
the expected figures for the routed amount and settle to the captured amount at
terminal.
The destination fields (number, name, bankname) are populated
once InOut has allocated an inbound destination — until then they are
absent from the response. See
Destinations for which fields each
method uses.
A provider field may also appear on responses; it is an opaque
internal routing label and merchants should not depend on its value.
Errors
See Errors. The most common ones for this endpoint:
400— invalid JSON or a required field is missing/malformed.401—X-API-Keymissing or invalid.412—merchant_operation_idcollision with a different body.