Assalam Docs

Привязка карты

Наша страница привязки или своя форма — и почему номер карты не должен попадать на ваш сервер

Клиент подтверждает карту кодом из SMS один раз — дальше вы списываете без его участия.

Оба способа начинаются одинаково: вы создаёте сессию привязки своим секретным ключом на сервере. В ответе — ссылка url для первого способа и clientToken для второго.

Токен сессии живёт 15 минут и разрешает только привязку одной карты. Он не позволяет списывать деньги и смотреть другие операции, поэтому его безопасно передать в браузер или приложение — в отличие от секретного ключа.

POST/subscribe/v1/card_sessions
Ваш сервер · Создание сессии
curl -X POST https://api.assalam.uz/subscribe/v1/card_sessions \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "returnUrl": "https://your.app/cards/return",
    "customerRef": "user_1024"
  }'
Ответ
{
  "id": "cmsr9f2c",
  "url": "https://checkout.assalam.uz/s/6a3f...",
  "clientToken": "6a3f...",
  "expiresAt": "2026-08-14T10:15:00.000Z",
  "livemode": false
}
Ваш сервер · Результат сессии
# когда клиент вернулся на returnUrl
curl https://api.assalam.uz/subscribe/v1/card_sessions/cmsr9f2c \
  -H "Authorization: Bearer sk_test_..."

# → {"status":"COMPLETED","paymentMethodId":"cmsr7d1e"}

Способ 1 — наша страница

Откройте url в WebView приложения или редиректом на сайте. Клиент вводит карту и код на нашей странице, после чего возвращается на ваш returnUrl.

Ни ваш бэкенд, ни ваше приложение не видят номер карты. Это самый быстрый способ подключиться и самый простой с точки зрения требований PCI DSS.

Способ 2 — своя форма

Вы рисуете форму ввода карты сами — внутри мобильного приложения или на своём сайте. Наша страница не открывается вовсе.

Ключевое отличие от обычной интеграции: эти два запроса делает не ваш сервер, а само приложение или страница клиента. Номер карты уходит от клиента прямо к нам, минуя ваш бэкенд — поэтому он и не попадает в PCI-scope.

Порядок вызовов:

  1. Ваш сервер создаёт сессию и получает clientToken.
  2. Вы передаёте clientToken в приложение или на страницу.
  3. Клиент вводит карту → POST /checkout/v1/sessions/{token}/card.
  4. Клиент вводит код из SMS → POST /checkout/v1/sessions/{token}/code.
  5. Ваш сервер забирает paymentMethodId по id сессии.
Браузер или приложение клиента · 1. Карта
# 6a3f... — это clientToken из ответа выше.
# Запрос уходит ИЗ приложения или страницы клиента,
# минуя ваш бэкенд. Ключ продукта здесь не нужен.
curl -X POST \
  https://api.assalam.uz/checkout/v1/sessions/6a3f.../card \
  -H "Content-Type: application/json" \
  -d '{
    "pan": "8600000000001234",
    "expiry": "3001",
    "phone": "998901234567"
  }'

# → {"status":"AWAITING_CODE","maskedPan":"860000******1234"}
# клиенту приходит SMS с кодом
Браузер или приложение клиента · 2. Код
# тот же токен, код клиент вводит в вашей форме
curl -X POST \
  https://api.assalam.uz/checkout/v1/sessions/6a3f.../code \
  -H "Content-Type: application/json" \
  -d '{"code": "123456"}'

# → {"status":"COMPLETED", ...} — карта привязана
Ваш сервер · 3. Забрать карту
# снова с вашего сервера, по id сессии
curl https://api.assalam.uz/subscribe/v1/card_sessions/cmsr9f2c \
  -H "Authorization: Bearer sk_test_..."

# → {"status":"COMPLETED","paymentMethodId":"cmsr7d1e"}

Секретный ключ в приложение не передаётся

Обратите внимание: в запросах клиента нет заголовка Authorization. Авторизацией служит clientToken прямо в адресе — он разрешает только эту привязку и живёт 15 минут. Секретный ключ продукта в приложение передавать нельзя.

Обязательные правила

  • Никогда не отправляйте номер карты на свой бэкенд — ни для валидации, ни для логов. Только напрямую в Assalam.
  • Не сохраняйте и не логируйте его: ни в базе, ни в аналитике, ни в crash-репортах.
  • Не спрашивайте CVV — банк его не принимает.
  • Никаких сторонних скриптов на странице с формой: любой из них может прочитать поле ввода.

Для веб-формы укажите домены в настройках продукта — запрос с другого origin будет отклонён. Мобильным приложениям это не нужно: там границей служит сам токен сессии.

Число попыток ограничено: 3 на ввод карты и 5 на код. После этого сессия закрывается — создайте новую.

Получение результата

Когда клиент вернулся, запросите сессию со своего сервера: статус COMPLETED и paymentMethodId — идентификатор карты для списаний. Сохраните его у себя рядом со своим пользователем.

GET/subscribe/v1/card_sessions/{id}

Сохраните paymentMethodId у себя

Это единственное, что нужно для будущих списаний. Положите его в свою базу рядом с пользователем — например в поле user.assalamPaymentMethodId. Полезно сохранить и маску карты, чтобы показывать её клиенту.

Если не сохранили — карты клиента находятся по вашей же метке: GET /subscribe/v1/cards?customerRef=user_1024.

Подробнее о том, кто что хранит и как связаны идентификаторы — в разделе «Как это устроено».

Что известно о карте

При опознании карты банк сообщает нам её маску, банк-эмитент, процессинг и ФИО держателя. Всё это возвращается в объекте карты; полного номера среди этих полей нет и быть не может — он не хранится нигде.

  • maskedPan — маска вида 860012******1234. Показывайте её клиенту, чтобы он понимал, какой картой платит.
  • holderName — ФИО держателя. Банк заполняет его не всегда, поэтому поле может быть пустым.
  • bankName, processingSystem — банк-эмитент и платёжная система (UZCARD, HUMO, PULLY).

ФИО держателя — персональные данные

Показывайте его только самому держателю — например, чтобы он отличил свою карту от чужой в списке. Не передавайте третьим лицам и не показывайте другим пользователям вашего продукта. Банк раскрывает эти сведения нам как агенту, а не для дальнейшего распространения.

Остатка на карте банк не сообщает

Метода запроса баланса в действующем контракте нет. Узнать, хватает ли средств, можно только попыткой списания: при нехватке приходит отказ с кодом INSUFFICIENT_FUNDS. Учитывайте это в сценариях, где хотелось бы предупредить клиента заранее.

Статусы карты

  • REQUIRES_VERIFICATION — карта опознана, ждём код из SMS.
  • ACTIVE — можно списывать.
  • DISABLED — отключена вами или клиентом.
  • FAILED — привязка не удалась.

Отключить карту: POST /subscribe/v1/cards/{id}/disable. После этого списания по ней невозможны.

Дальше по теме

Остаток на карте

Нужно отдельное разрешение

Метод доступен, только если мы включили его вашему продукту. Напишите нам, если он нужен: остаток — персональные финансовые данные клиента, а не справочный атрибут карты вроде маски номера, поэтому доступ выдаётся поимённо и под задачу. Без разрешения ответ — 403 CARD_BALANCE_DISABLED.

GET /subscribe/v1/cards/{card}/balance
{
  "object": "card_balance",
  "card": "cmv93eb6h0005wi01kqvnbhhk",
  "balance": 999500,
  "currency": "UZS"
}

Сумма в тийинах, как и везде в API: 999500 — это 9 995 сум.

Зачем это бывает нужно: перед списанием по подписке проверить, хватит ли денег, и не портить клиенту историю отказом. Чего делать не стоит:

  • опрашивать остаток в цикле. Каждый вызов идёт в банк и делится общим лимитом обращений с вашими платежами — опрос остатка способен затормозить собственные списания;
  • хранить остаток у себя. Он меняется без нашего участия, и сохранённое значение устаревает сразу же;
  • показывать остаток кому-либо, кроме держателя карты.

Метод работает не на всякой рельсе: если банк, через который привязана карта, остаток не отдаёт, ответ — NOT_SUPPORTED. Это не ошибка интеграции.

На этой странице