Skip to content

Card Bind Webhook ​

Webhook, который Paylov отправляет в систему партнёра после успешной привязки карты.

Требуется настройка

Адрес webhook (endpoint) и логин/пароль Basic Auth для него заранее настраиваются совместно с Paylov (сохраняются в профиле merchant'а). Если это ещё не настроено, сообщите технической команде Paylov, на какой адрес и с каким логином/паролем отправлять запросы.

Детали запроса ​

Method: POST
URL: webhook URL, указанный партнёром
Header:

http
Authorization: Basic base64(login:password)
Content-Type: application/json

Пример запроса

json
{
  "token": "pR3x...kLq9",
  "userId": "partner-user-10234",
  "status": "confirmed",
  "card": {
    "cardId": "b1e2f3a4-...-uuid",
    "userId": "partner-user-10234",
    "owner": "ТЕСТОВЫЙ ПОЛЬЗОВАТЕЛЬ",
    "cardName": null,
    "number": "860012******9012",
    "balance": 1500000,
    "expireDate": "2612",
    "bankId": "7",
    "bankName": "Ipoteka Bank",
    "vendor": "uzcard",
    "processing": "Uzcard",
    "status": {
      "is_active": true,
      "status_message": "active",
      "sms_info": true
    }
  }
}

Params

FieldTypeDescription
tokenstringtoken, полученный при создании ссылки — для идентификации запроса у партнёра
userIdstringuserId, который партнёр сам передал при создании ссылки
statusstringПока всегда confirmed
card.cardIdstringОсновной ID, используемый во всех последующих операциях
card.numberstringЗамаскированный номер карты — полный PAN не передаётся
card.balanceintegerВ тийинах (100 = 1 сум)

Пример приёмника — Python/FastAPI ​

python
import base64
from fastapi import FastAPI, Header, HTTPException, Request

EXPECTED_LOGIN = "partner_webhook"
EXPECTED_PASSWORD = "..."  # согласовано с Paylov

app = FastAPI()


@app.post("/paylov/card-bind/webhook")
async def card_bind_webhook(request: Request, authorization: str = Header(None)):
    if not authorization or not authorization.startswith("Basic "):
        raise HTTPException(401)
    decoded = base64.b64decode(authorization[6:]).decode()
    login, password = decoded.split(":", 1)
    if login != EXPECTED_LOGIN or password != EXPECTED_PASSWORD:
        raise HTTPException(401)

    payload = await request.json()
    user_id = payload["userId"]
    card = payload["card"]
    # сохраните card["cardId"] для этого userId
    return {"ok": True}

Примечание

Ответ на webhook должен быть 2xx. Если сторона партнёра не отвечает или возвращает ошибку, Paylov лишь фиксирует это в логах — автоматических повторных попыток пока нет. Поэтому запрос проверки статуса служит резервным вариантом.