API интеграции мерчанта (0.0.20)

Download OpenAPI specification:

Документация по интеграции клиента с нашим API.

Аутентификация

API использует аутентификацию с применением API-ключа и цифровой подписи. Для каждого запроса требуется аутентификация.

Каждый запрос должен содержать заголовки аутентификации

  • X-Api-Key: Уникальный ID ключа, генерируемый мерчантом в личном кабинете
  • X-Timestamp: Временная метка в миллисекундах (UTC)
  • X-Signature: Подпись строки запроса

Пример строки для подписи:

HTTP_METHOD + "\n" +
FULL_URI + "\n" +
TIMESTAMP + "\n" +
BODY_HASH

Расшифровка аргументов:

  • HTTP_METHOD:

    • HTTP метод запроса (GET, POST, PUT, DELETE).
    • Обеспечивает уникальность подписи для разных методов с одинаковым URL.
    • Пример: POST
  • FULL_URI:

    • Полный URI запроса, включая путь и отсортированные параметры запроса.
    • Как формируется:
      • Путь запроса (например, /api/v1/resource)
      • Параметры запроса в алфавитном порядке (например, ?id=123&sort=asc)
    • Пример: /api/v1/resource?id=123&sort=asc
  • TIMESTAMP:

    • Временная метка в миллисекундах (UTC) на момент создания запроса.
    • Защищает от повторных атак (Replay Attacks).
    • В production среде сервер отклоняет запросы, если их временная метка (TIMESTAMP) устарела более чем на 10 секунд или опережает текущее время.
    • Пример: 1700000000000
  • BODY_HASH:

    • Хеш тела запроса, вычисленный с использованием SHA-256.
    • Гарантирует целостность данных в теле запроса.
    • Если тело запроса пустое (например, в GET запросе), то для вычисления хеша используется пустая строка.
    • Пример:
      e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
      

Полный пример строки для подписи:

```
POST
/api/v1/resource?id=123&sort=asc
1700000000000
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
```

Важно учитывать, что сервер отклоняет запросы с одинаковой комбинацией TIMESTAMP и SIGNATURE, чтобы предотвратить повторное использование одной и той же временной метки.

Code snippets:

Golang:

package main

import (
    "bytes"
    "crypto/ed25519"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "io"
    "net/http"
)

const (
    BASE_ENDPOINT = "https://api.payup.ws"
    HTTP_METHOD   = "POST"
    FULL_URI      = "/v1/payin"

    // TODO: Setup your keys
    API_KEY       = "7e360b4e-65ab-4fef-9f02-394b2721eac1"
    PRIVATE_KEY   = "f6c27d638a9a07cd11cce44ed41c82aeedcaef2fd82eaa8370e3f9733adb83f9"
)

type generateSignatureArgs struct {
    Method     string
    URI        string
    BodyHash   []byte
    PrivateKey string
}

func generateSignature(args generateSignatureArgs) (string, string) {
    timestamp := fmt.Sprintf("%d", time.Now().UnixMilli())
    signString := fmt.Sprintf("%s\n%s\n%s\n%x", args.Method, args.URI, timestamp, args.BodyHash)

    privateKeyBytes, err := hex.DecodeString(args.PrivateKey)
    if err != nil {
        panic(err)
    }

    privateKey := ed25519.NewKeyFromSeed(privateKeyBytes)
    signature := ed25519.Sign(privateKey, []byte(signString))

    return hex.EncodeToString(signature), timestamp
}

func makeRequest() {
    payload := map[string]any{
        "amount":   1000,
        "currency": "RUB",
        "customer": map[string]any{
            "id": "string",
        },
        "payment_method": "CARD",
        "webhook_url":    "https://webhook.site/SomeID",
    }

    payloadB, err := json.Marshal(payload)
    if err != nil {
        panic(err)
    }

    bodyHash := sha256.Sum256(payloadB)
    signature, timestamp := generateSignature(generateSignatureArgs{
        Method:     HTTP_METHOD,
        URI:        FULL_URI,
        BodyHash:   bodyHash[:],
        PrivateKey: PRIVATE_KEY,
    })

    request, err := http.NewRequest(HTTP_METHOD, BASE_ENDPOINT+FULL_URI, bytes.NewBuffer(payloadB))
    if err != nil {
        panic(err)
    }

    request.Header.Set("X-Api-Key", API_KEY)
    request.Header.Set("X-Timestamp", timestamp)
    request.Header.Set("X-Signature", signature)
    request.Header.Set("Content-Type", "application/json")

    client := http.Client{}
    response, err := client.Do(request)
    if err != nil {
        panic(err)
    }
    defer response.Body.Close()

    responseData, err := io.ReadAll(response.Body)
    if err != nil {
        panic(err)
    }

    fmt.Println(response.Status)
    fmt.Println(string(responseData))
    fmt.Println("X-Request-Id:", response.Header.Get("X-Request-Id"))
}

func main() {
    makeRequest()
}

Python:

import binascii
import time
import json
import hashlib
import requests
from nacl.signing import SigningKey

BASE_ENDPOINT = "https://api.payup.ws"
HTTP_METHOD = "POST"
FULL_URI = "/v1/payin"

# TODO: Setup your keys
API_KEY = "7e360b4e-65ab-4fef-9f02-394b2721eac1"
PRIVATE_KEY = "f6c27d638a9a07cd11cce44ed41c82aeedcaef2fd82eaa8370e3f9733adb83f9"


def generate_signature(method: str, uri: str, payload: dict, private_key: str) -> (str, str):
    timestamp = str(int(time.time() * 1000))
    body_hash = hashlib.sha256(json.dumps(payload).encode("utf-8")).hexdigest()
    sign_string = f"{method}\n{uri}\n{timestamp}\n{body_hash}"

    private_key_bytes = binascii.unhexlify(private_key)
    signing_key = SigningKey(private_key_bytes)
    signature = signing_key.sign(sign_string.encode())

    return signature.signature.hex(), timestamp


def make_request():
    payload = {
        "amount": 1000,
        "banks": [],
        "currency": "RUB",
        "customer": {
            "id": "string",
        },
        "payment_method": "CARD",
        "webhook_url": "https://webhook.site/SomeID"
    }

    signature, timestamp = generate_signature(HTTP_METHOD, FULL_URI, payload, PRIVATE_KEY)

    headers = {
        "X-Api-Key": API_KEY,
        "X-Timestamp": timestamp,
        "X-Signature": signature,
        "Content-Type": "application/json",
    }

    response = requests.request(HTTP_METHOD, BASE_ENDPOINT + FULL_URI, headers=headers, json=payload)

    print(response.status_code)
    print(response.text)
    print('X-Request-Id:', response.headers.get('X-Request-Id'))


if __name__ == "__main__":
    make_request()

Вебхуки

API поддерживает механизм вебхуков для уведомления клиента об изменении статуса ордера.

  • Клиент может передать webhook_url при создании ордера.
  • При изменении статуса ордера API отправит HTTP POST-запрос на этот URL.
  • Формат payload вебхука определён в компоненте WebhookPayload

Вебхуки отправляются только с этих IP-адресов:

  • 37.252.19.8
  • 37.252.19.40
  • 37.252.19.67

UPD. В ближайшем будущем будут использоваться новые IP-адреса:

  • 165.22.22.35
  • 104.248.142.5
  • 64.226.115.100

Для обеспечения безопасности необходимо на получающей стороне валидировать IP-адрес отправителя вебхука и проверять, что он соответствует одному из разрешенных. При любом изменении списка IP-адресов клиенты будут заранее проинформированы, а информация об изменениях будет отображена в changelog документации.

Changelog

v0.0.20 (2026-02-01)

🚀 Добавлено

-   Эндпоинт POST /payin/{id}/cancel
    Позволяет отменить заявку на депозит.

-   Эндпоинт POST /payin/custom/{id}/cancel
    Позволяет отменить заявку на депозит, используя ID переданный на этапе формирования заявки.

v0.0.19 (2025-11-13)

🚀 Добавлено

- Новые IP-адреса для отправки вебхуков. В ближайшем будущем хуки будут доставляться исключительно с этих адресов.

v0.0.18 (2025-10-31)

🚀 Добавлено

- Добавлены новые флаги для создания ордера pay_in:

    selection_settings.require_payment_link
    selection_settings.require_qr_code

  Эти флаги указывают шлюзу возвращать соответствующие атрибуты вместе с реквизитами.

v0.0.17 (2025-10-13)

🚀 Добавлено

- Добавлен новый метод для pay_in: MOBILE - перевод на баланс мобильного оператора

v0.0.16 (2025-09-30)

🚀 Добавлено

- Добавлен новый метод для pay_in: NSPK - перевод через платежную систему nspk

v0.0.15 (2025-08-08)

🚀 Добавлено

- Добавлен новый метод для pay_in/pay_out: ACCOUNT - перевод по номеру счета

v0.0.14 (2025-06-19)

🚀 Добавлено

- В эндпоинт POST /payin добавлено описание ошибки 504 при таймауте запроса к бэкенду
- В эндпоинт POST /payout добавлено описание ошибки 504 при таймауте запроса к бэкенду

v0.0.13 (2025-05-19)

🚀 Добавлено

- Во все эндпоинты были добавлены описания успешных ответов

v0.0.12 (2025-05-19)

🚀 Добавлено

- Во все эндпоинты были добавлены описания ошибок

v0.0.11 (2025-05-19)

🚀 Добавлено

-  В эндпоинт POST /payout добавлено описание ошибки 412, 422
-  В эндпоинт POST /payin добавлено описание ошибки 404, 412, 422

v0.0.10 (2025-05-14)

🚀 Добавлено

-  В эндпоинт POST /payout добавлено описание ошибки 409 при конфликте с custom_order_id
-  В эндпоинт POST /payin добавлено описание ошибки 409 при конфликте с custom_order_id

v0.0.9 (2025-05-12)

🚀 Добавлено

-   В эндпоинт GET /payout/{id} добавлено поле `bill_link`, содержащее ссылку на чек. Ссылка активна в тч 24 часов после завершения ордера.
-   PayOut вебхук тело запроса теперь содержит поле `bill_link`, содержащее ссылку на чек. Ссылка активна в тч 24 часов после завершения ордера.

v0.0.8 (2025-04-07)

🚀 Добавлено

-   В эндпоинт POST /payin
    Добавлен новый тип платежа MTP_INTERNATIONAL, который позволяет проводить международные переводы, как рублевые
-   В эндпоинт POST /payin
    Добавлены новые опциональные аттрибуты для объекта customer:
        [`registered_at`, `ip`, `user_agent`, `login`, `email`,
        `screen_resolution`, `from_merchant_id`]
        `registered_at`- Дата регистрации клиента в системе.
        `ip` - IP-адрес клиента.
        `user_agent`- User-Agent клиента.
        `login`- Логин клиента.
        `email` - Email клиента.
        `screen_resolution`- Разрешение экрана клиента.
        `from_merchant_id` - ID мерчанта, с которого был создан ордер.
-   В эндпоинт POST /payout
    Добавлены новые опциональные аттрибуты для объекта customer:
        [`registered_at`, `ip`, `user_agent`, `login`, `email`,
        `screen_resolution`, `from_merchant_id`]
        `registered_at`- Дата регистрации клиента в системе.
        `ip` - IP-адрес клиента.
        `user_agent`- User-Agent клиента.
        `login`- Логин клиента.
        `email` - Email клиента.
        `screen_resolution`- Разрешение экрана клиента.
        `from_merchant_id` - ID мерчанта, с которого был создан ордер.
-   В эндпоинт POST /payout
    Аттрибут card_holder в объекте recipient теперь не является обязательным для MTP выплат.

v0.0.7 (2025-04-04)

🚀 Добавлено

-   Эндпоинт GET /payout/custom/{id}
    Позволяет получить информацию по выплате, используя ID переданный на этапе формирования заявки.

v0.0.6 (2025-03-27)

📌 Важно

-   Эндпоинт POST /payout
    В объект recipient добавлен аттрибут card_holder, который является обязательным для MTP выплат.

v0.0.5 (2025-03-18)

🚀 Добавлено

-   Эндпоинт POST /payin
    Добавлен объект selection_settings, содержащий поле allow_new_amount.
    В значении true позволяет шлюзу изменять сумму исходной заявки в момент подбора реквизита.

v0.0.4 (2025-03-13)

🚀 Добавлено

Пример генерации подписи на Python

v0.0.3 (2025-03-07)

📌 Важно

- В секции вебхуков добавлены IP-адреса с которых могут отправляться вебхуки: 37.252.19.8, 37.252.19.40, 37.252.19.67.
- Добавлены пояснения для клиентов по обеспечению безопастности в процессе обработки вебхуков.

⚠️ Изменения, требующие обновления клиентов

Валидация IP-адресов отправителей вебхуков

v0.0.2 (2025-02-28)

📌 Важно

Временные метки (timestamp) теперь должны быть не старше 10 секунд и не опережать текущее время.
Соответствующая пометка добавлена в описание аргумента в секции расшифровки аргументов строки для подписи

⚠️ Изменения, требующие обновления клиентов

Эндпоинт GET /banks перенесён на GET /list/banks. Старый путь больше не поддерживается.

Эндпоинт GET /balance перенесён на GET /billing/balance. Старый путь больше не поддерживается.

🚀 Добавлено

Пример генерации подписи на Golang

v0.0.1 (2025-02-15)

🚀 Добавлено

Первая версия документации API в базовом виде. Описание основных эндпоинтов, параметров и примеров запросов.

billing

Получить баланс

Возвращает информацию о балансе клиента.

Responses

Response samples

Content type
application/json
{
  • "property1": {
    },
  • "property2": {
    }
}

list

Информация по доступным банкам с разбивкой по валютам

query Parameters
currency
required
string (Currency)
Enum: "RUB" "UZS" "AZN"

Responses

Response samples

Content type
application/json
[
  • {
    }
]

payin

Создать платежный ордер

Создает новый payin-ордер. Поддерживается только одна из двух стратегий: либо указание списка banks для подбора среди них, либо использование excluded_banks для исключения. По умолчанию, если ни одно из полей не передано, применяется стратегия с пустым исключением (excluded_banks) - подбор будет выполняться среди всех доступных банков для указанной валюты.

Request Body schema: application/json
required
amount
required
number (Amount) > 0
banks
Array of strings (Banks)

An up-to-date list of banks is available at /list/banks

currency
required
string (Currency)
Enum: "RUB" "UZS" "AZN"

ISO4217

Custom Order Id (string) or Custom Order Id (null) (Custom Order Id)
Customer (object) or null
excluded_banks
Array of strings (Excluded Banks)

An up-to-date list of banks is available at /list/banks

payment_method
required
string (PaymentMethod)
Enum: "CARD" "MTP" "ACCOUNT" "MTP_INTERNATIONAL" "NSPK" "MOBILE"

MTP — Mobile Transfer Protocol (SBP) CARD — Card Number Transfer ACCOUNT — Account Number Transfer NSPK — NSPK Transfer (Available for RUB only.) MOBILE — Mobile Operator Transfer

PayInSelectionSettings (object) or null
Webhook Url (string) or Webhook Url (null) (Webhook Url)

Endpoint for webhook delivery

Responses

Request samples

Content type
application/json
{
  • "amount": 0,
  • "banks": [
    ],
  • "currency": "RUB",
  • "custom_order_id": "string",
  • "customer": {
    },
  • "excluded_banks": [
    ],
  • "payment_method": "CARD",
  • "selection_settings": {
    },
  • "webhook_url": "string"
}

Response samples

Content type
application/json
{
  • "order": {
    }
}

Получить детали платежа по вашему id

Возвращает информацию о payin-ордере.

path Parameters
id
required
string (Id)

Responses

Response samples

Content type
application/json
{
  • "amount": {
    },
  • "created_at": "2019-08-24T14:15:22Z",
  • "custom_order_id": "string",
  • "disputes": [
    ],
  • "expires_at": "2019-08-24T14:15:22Z",
  • "fee": {
    },
  • "id": "string",
  • "payment_link": "string",
  • "qr_code": "string",
  • "requisite": {
    },
  • "status": "PENDING",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "webhook_url": "string"
}

Отменить payin-ордер по пользовательскому id

Отменяет действующий payin-ордер по пользовательскому идентификатору.

path Parameters
id
required
string (Id)

Responses

Response samples

Content type
application/json
{
  • "error": {
    }
}

Получить детали платежа

Возвращает информацию о payin-ордере.

path Parameters
id
required
string (Id)

Responses

Response samples

Content type
application/json
{
  • "amount": {
    },
  • "created_at": "2019-08-24T14:15:22Z",
  • "custom_order_id": "string",
  • "disputes": [
    ],
  • "expires_at": "2019-08-24T14:15:22Z",
  • "fee": {
    },
  • "id": "string",
  • "payment_link": "string",
  • "qr_code": "string",
  • "requisite": {
    },
  • "status": "PENDING",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "webhook_url": "string"
}

Отменить payin-ордер

Отменяет действующий payin-ордер по его внутреннему идентификатору.

path Parameters
id
required
string (Id)

Responses

Response samples

Content type
application/json
{
  • "error": {
    }
}

Оспорить статус ордера

Оспаривает статус существующего payin-ордера.

path Parameters
id
required
string (Id)
Request Body schema: multipart/form-data
required
amount
required
number (Amount)
files
Array of strings <binary> (Files) [ items <binary > ]
Message (string) or Message (null) (Message)

Responses

Response samples

Content type
application/json
{
  • "amount": {
    },
  • "created_at": "2019-08-24T14:15:22Z",
  • "custom_order_id": "string",
  • "disputes": [
    ],
  • "expires_at": "2019-08-24T14:15:22Z",
  • "fee": {
    },
  • "id": "string",
  • "payment_link": "string",
  • "qr_code": "string",
  • "requisite": {
    },
  • "status": "PENDING",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "webhook_url": "string"
}

payout

Создать вывод средств

Создает новый payout-ордер.

Request Body schema: application/json
required
amount
required
number (Amount) > 0
currency
required
string (Currency)
Enum: "RUB" "UZS" "AZN"

ISO4217

Custom Order Id (string) or Custom Order Id (null) (Custom Order Id)
Customer (object) or null
required
object (RecipientPayout)

Payout recipient

Webhook Url (string) or Webhook Url (null) (Webhook Url)

Endpoint for webhook delivery

Responses

Request samples

Content type
application/json
{
  • "amount": 0,
  • "currency": "RUB",
  • "custom_order_id": "string",
  • "customer": {
    },
  • "recipient": {
    },
  • "webhook_url": "string"
}

Response samples

Content type
application/json
{
  • "amount": {
    },
  • "bill_link": "string",
  • "currency": "RUB",
  • "custom_order_id": "string",
  • "fee": {
    },
  • "id": "string",
  • "recipient": {
    },
  • "status": "PENDING",
  • "webhook_url": "string"
}

Получить детали вывода средств по вашему id

Возвращает информацию о payout-ордере по custom_order_id

path Parameters
id
required
string (Id)

Responses

Response samples

Content type
application/json
{
  • "amount": {
    },
  • "bill_link": "string",
  • "currency": "RUB",
  • "custom_order_id": "string",
  • "fee": {
    },
  • "id": "string",
  • "recipient": {
    },
  • "status": "PENDING",
  • "webhook_url": "string"
}

Получить детали вывода средств

Возвращает информацию о payout-ордере.

path Parameters
id
required
string (Id)

Responses

Response samples

Content type
application/json
{
  • "amount": {
    },
  • "bill_link": "string",
  • "currency": "RUB",
  • "custom_order_id": "string",
  • "fee": {
    },
  • "id": "string",
  • "recipient": {
    },
  • "status": "PENDING",
  • "webhook_url": "string"
}

webhook

Пример webhook запроса на ваш backend сервер

Пример тела запроса на предоставленный webhook_url

Request Body schema: application/json
required
required
PayInWebhookPayload (object) or PayOutWebhookPayload (object) (Data)
order_type
required
string (OrderType)
Enum: "PAYIN" "PAYOUT"

order type

Responses

Request samples

Content type
application/json
{
  • "data": {
    },
  • "order_type": "PAYIN"
}

Response samples

Content type
application/json
null