InOut

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-23456789abcd

The 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

FieldTypeRequiredNotes
merchant_operation_idstringyesIdempotency 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_idstringyesYour end-user identifier. Any non-empty string.
client_ipstringnoClient IP address, used for antifraud.
methodstringyesLogical payment method, e.g. WT_RUB_C2C or WT_RUB_PHONE. See Payment methods.
amountstringyesDecimal string with scale 2, e.g. "1500.00".
currencystringyesISO 4217 code, e.g. "RUB".
numberstringnoDestination identifier — only consulted for payouts and ignored on payments. Card number for WT_RUB_C2C; phone number for WT_RUB_PHONE.
namestringnoHolder/recipient name on the destination. Same scoping as number.
banknamestringnoDestination 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.
  • 401X-API-Key missing or invalid.
  • 412merchant_operation_id collision with a different body.

On this page