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

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.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_order_id/{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)
Items Value: "sberbank"

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 (Custom Order Id)
object (Customer)
excluded_banks
Array of strings (Excluded Banks)
Items Value: "sberbank"

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

object (PayInSelectionSettings)
webhook_url
string (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
{
  • "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-ордере.

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-ордера.

path Parameters
id
required
string (Id)
Request Body schema: multipart/form-data
required
amount
required
number (Amount) > 0
files
required
Array of strings <binary> (Files) [ items <binary > ]
message
string (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 (Custom Order Id)
object (Customer)
required
object (Recipient-Input)

Payout recipient

webhook_url
string (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