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:
GET, POST, PUT, DELETE).POSTFULL_URI:
/api/v1/resource)?id=123&sort=asc)/api/v1/resource?id=123&sort=ascTIMESTAMP:
1700000000000BODY_HASH:
GET запросе), то для вычисления хеша используется пустая строка.e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
```
POST
/api/v1/resource?id=123&sort=asc
1700000000000
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
```
Важно учитывать, что сервер отклоняет запросы с одинаковой комбинацией TIMESTAMP и SIGNATURE, чтобы предотвратить повторное использование одной и той же временной метки.
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 при создании ордера.WebhookPayloadВебхуки отправляются только с этих IP-адресов:
37.252.19.837.252.19.4037.252.19.67UPD. В ближайшем будущем будут использоваться новые IP-адреса:
165.22.22.35104.248.142.564.226.115.100Для обеспечения безопасности необходимо на получающей стороне валидировать IP-адрес отправителя вебхука и проверять, что он соответствует одному из разрешенных. При любом изменении списка IP-адресов клиенты будут заранее проинформированы, а информация об изменениях будет отображена в changelog документации.
🚀 Добавлено
- Новые IP-адреса для отправки вебхуков. В ближайшем будущем хуки будут доставляться исключительно с этих адресов.
🚀 Добавлено
- Добавлены новые флаги для создания ордера pay_in:
selection_settings.require_payment_link
selection_settings.require_qr_code
Эти флаги указывают шлюзу возвращать соответствующие атрибуты вместе с реквизитами.
🚀 Добавлено
- Добавлен новый метод для pay_in: MOBILE - перевод на баланс мобильного оператора
🚀 Добавлено
- Добавлен новый метод для pay_in: NSPK - перевод через платежную систему nspk
🚀 Добавлено
- Добавлен новый метод для pay_in/pay_out: ACCOUNT - перевод по номеру счета
🚀 Добавлено
- В эндпоинт POST /payin добавлено описание ошибки 504 при таймауте запроса к бэкенду
- В эндпоинт POST /payout добавлено описание ошибки 504 при таймауте запроса к бэкенду
🚀 Добавлено
- Во все эндпоинты были добавлены описания успешных ответов
🚀 Добавлено
- Во все эндпоинты были добавлены описания ошибок
🚀 Добавлено
- В эндпоинт POST /payout добавлено описание ошибки 412, 422
- В эндпоинт POST /payin добавлено описание ошибки 404, 412, 422
🚀 Добавлено
- В эндпоинт POST /payout добавлено описание ошибки 409 при конфликте с custom_order_id
- В эндпоинт POST /payin добавлено описание ошибки 409 при конфликте с custom_order_id
🚀 Добавлено
- В эндпоинт GET /payout/{id} добавлено поле `bill_link`, содержащее ссылку на чек. Ссылка активна в тч 24 часов после завершения ордера.
- PayOut вебхук тело запроса теперь содержит поле `bill_link`, содержащее ссылку на чек. Ссылка активна в тч 24 часов после завершения ордера.
🚀 Добавлено
- В эндпоинт 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 выплат.
🚀 Добавлено
- Эндпоинт GET /payout/custom_order_id/{id}
Позволяет получить информацию по выплате, используя ID переданный на этапе формирования заявки.
📌 Важно
- Эндпоинт POST /payout
В объект recipient добавлен аттрибут card_holder, который является обязательным для MTP выплат.
🚀 Добавлено
- Эндпоинт POST /payin
Добавлен объект selection_settings, содержащий поле allow_new_amount.
В значении true позволяет шлюзу изменять сумму исходной заявки в момент подбора реквизита.
🚀 Добавлено
Пример генерации подписи на Python
📌 Важно
- В секции вебхуков добавлены IP-адреса с которых могут отправляться вебхуки: 37.252.19.8, 37.252.19.40, 37.252.19.67.
- Добавлены пояснения для клиентов по обеспечению безопастности в процессе обработки вебхуков.
⚠️ Изменения, требующие обновления клиентов
Валидация IP-адресов отправителей вебхуков
📌 Важно
Временные метки (timestamp) теперь должны быть не старше 10 секунд и не опережать текущее время.
Соответствующая пометка добавлена в описание аргумента в секции расшифровки аргументов строки для подписи
⚠️ Изменения, требующие обновления клиентов
Эндпоинт GET /banks перенесён на GET /list/banks. Старый путь больше не поддерживается.
Эндпоинт GET /balance перенесён на GET /billing/balance. Старый путь больше не поддерживается.
🚀 Добавлено
Пример генерации подписи на Golang
🚀 Добавлено
Первая версия документации API в базовом виде. Описание основных эндпоинтов, параметров и примеров запросов.
Создает новый payin-ордер.
Поддерживается только одна из двух стратегий: либо указание списка banks для подбора среди них, либо использование excluded_banks для исключения.
По умолчанию, если ни одно из полей не передано, применяется стратегия с пустым исключением (excluded_banks) - подбор будет выполняться среди всех доступных банков для указанной валюты
| 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"
|
object (PayInSelectionSettings) | |
| webhook_url | string (Webhook Url) Endpoint for webhook delivery |
{- "amount": 0,
- "banks": [
- "sberbank"
], - "currency": "RUB",
- "custom_order_id": "string",
- "customer": {
- "email": "string",
- "from_merchant_id": "string",
- "id": "string",
- "ip": "string",
- "login": "string",
- "registered_at": "2019-08-24T14:15:22Z",
- "screen_resolution": "string",
- "user_agent": "string"
}, - "excluded_banks": [
- "sberbank"
], - "payment_method": "CARD",
- "selection_settings": {
- "allow_new_amount": false,
- "require_payment_link": false,
- "require_qr_code": false
}, - "webhook_url": "string"
}{- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "created_at": "2019-08-24T14:15:22Z",
- "custom_order_id": "string",
- "disputes": [
- {
- "extra": {
- "message": "string"
}, - "id": "string",
- "status": "PENDING"
}
], - "expires_at": "2019-08-24T14:15:22Z",
- "fee": {
- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "tariff": {
- "percentage": 99,
- "value": 0
}
}, - "id": "string",
- "payment_link": "string",
- "qr_code": "string",
- "requisite": {
- "bank": {
- "currency": "RUB",
- "name": "string"
}, - "holder": "string",
- "payment_method": "CARD",
- "value": "string"
}, - "status": "PENDING",
- "updated_at": "2019-08-24T14:15:22Z",
- "webhook_url": "string"
}Возвращает информацию о payin-ордере.
| id required | string (Id) |
{- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "created_at": "2019-08-24T14:15:22Z",
- "custom_order_id": "string",
- "disputes": [
- {
- "extra": {
- "message": "string"
}, - "id": "string",
- "status": "PENDING"
}
], - "expires_at": "2019-08-24T14:15:22Z",
- "fee": {
- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "tariff": {
- "percentage": 99,
- "value": 0
}
}, - "id": "string",
- "payment_link": "string",
- "qr_code": "string",
- "requisite": {
- "bank": {
- "currency": "RUB",
- "name": "string"
}, - "holder": "string",
- "payment_method": "CARD",
- "value": "string"
}, - "status": "PENDING",
- "updated_at": "2019-08-24T14:15:22Z",
- "webhook_url": "string"
}Оспаривает статус существующего payin-ордера.
| id required | string (Id) |
| amount required | number (Amount) > 0 |
| files required | Array of strings <binary> (Files) [ items <binary > ] |
| message | string (Message) |
{- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "created_at": "2019-08-24T14:15:22Z",
- "custom_order_id": "string",
- "disputes": [
- {
- "extra": {
- "message": "string"
}, - "id": "string",
- "status": "PENDING"
}
], - "expires_at": "2019-08-24T14:15:22Z",
- "fee": {
- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "tariff": {
- "percentage": 99,
- "value": 0
}
}, - "id": "string",
- "payment_link": "string",
- "qr_code": "string",
- "requisite": {
- "bank": {
- "currency": "RUB",
- "name": "string"
}, - "holder": "string",
- "payment_method": "CARD",
- "value": "string"
}, - "status": "PENDING",
- "updated_at": "2019-08-24T14:15:22Z",
- "webhook_url": "string"
}Создает новый payout-ордер.
| 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 |
{- "amount": 0,
- "currency": "RUB",
- "custom_order_id": "string",
- "customer": {
- "email": "string",
- "from_merchant_id": "string",
- "id": "string",
- "ip": "string",
- "login": "string",
- "registered_at": "2019-08-24T14:15:22Z",
- "screen_resolution": "string",
- "user_agent": "string"
}, - "recipient": {
- "bank": {
- "currency": "RUB",
- "name": "string"
}, - "card_holder": "string",
- "payment_method": "CARD",
- "value": "string"
}, - "webhook_url": "string"
}{- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "bill_link": "string",
- "currency": "RUB",
- "custom_order_id": "string",
- "fee": {
- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "tariff": {
- "percentage": 99,
- "value": 0
}
}, - "id": "string",
- "recipient": {
- "bank": {
- "currency": "RUB",
- "name": "string"
}, - "card_holder": "string",
- "payment_method": "CARD",
- "value": "string"
}, - "status": "PENDING",
- "webhook_url": "string"
}Возвращает информацию о payout-ордере по custom_order_id
| id required | string (Id) |
{- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "bill_link": "string",
- "currency": "RUB",
- "custom_order_id": "string",
- "fee": {
- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "tariff": {
- "percentage": 99,
- "value": 0
}
}, - "id": "string",
- "recipient": {
- "bank": {
- "currency": "RUB",
- "name": "string"
}, - "card_holder": "string",
- "payment_method": "CARD",
- "value": "string"
}, - "status": "PENDING",
- "webhook_url": "string"
}Возвращает информацию о payout-ордере.
| id required | string (Id) |
{- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "bill_link": "string",
- "currency": "RUB",
- "custom_order_id": "string",
- "fee": {
- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "tariff": {
- "percentage": 99,
- "value": 0
}
}, - "id": "string",
- "recipient": {
- "bank": {
- "currency": "RUB",
- "name": "string"
}, - "card_holder": "string",
- "payment_method": "CARD",
- "value": "string"
}, - "status": "PENDING",
- "webhook_url": "string"
}Пример тела запроса на предоставленный webhook_url
required | PayInWebhookPayload (object) or PayOutWebhookPayload (object) (Data) |
| order_type required | string (OrderType) Enum: "PAYIN" "PAYOUT" order type |
{- "data": {
- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "created_at": "2019-08-24T14:15:22Z",
- "custom_order_id": "string",
- "disputes": [
- {
- "extra": {
- "message": "string"
}, - "id": "string",
- "status": "PENDING"
}
], - "expires_at": "2019-08-24T14:15:22Z",
- "fee": {
- "amount": {
- "fiat_value": 0,
- "usdt_exchange_rate": 0,
- "usdt_value": 0
}, - "tariff": {
- "percentage": 99,
- "value": 0
}
}, - "id": "string",
- "payment_link": "string",
- "qr_code": "string",
- "requisite": {
- "bank": {
- "currency": "RUB",
- "name": "string"
}, - "holder": "string",
- "payment_method": "CARD",
- "value": "string"
}, - "status": "PENDING",
- "updated_at": "2019-08-24T14:15:22Z",
- "webhook_url": "string"
}, - "order_type": "PAYIN"
}null