В данном разделе описано как работает подсистема импорта данных из внешних провайдеров через CASHOFF API. Описание содержит следующие составляющие:
- добавление связи CASHOFF с провайдером через профиль
- авторизация профиля в провайдере
- процесс импорта данных
- получение загруженных данных из CASHOFF
Цикл работы с профилями при импорте данных
Глобально цикл состоит из следующих шагов:
- Добавление нового профиля. При добавлении указывается пользователь и провайдер.
- Запуск обновления данных. В рамках обновления данных из ЛК провайдера данные будут импортированы в CASHOFF.
- Авторизация в ЛК провайдера. Это первый, обязательный, этап обновления. На этом шаге либо клиенту нужно будет предоставить данные для авторизации (логин/пароль/смс и т.п.), либо CASHOFF использует сохраненные у него данные авторизации или сессию для восстановления подключения к провайдеру.
- Импорт данных. Выполняется после успешной авторизации
CASHOFF позволяет выполнить шаги 1-3 двумя разными способами: полностью через серверное API или через готовые визуальные модули.
После успешного добавления и первичного импорта данных можно повторно обновлять профиль выполняя шаги 2-4.
Сам процесс авторизации и импорта данных происходит асинхронно: соответствующие API методы только запускают выполнение действия, взаимодействие с провайдером же происходит в фоновом режиме.
Результат выполнения действий отслеживается через статус профиля (поле status), а прогресс через поля update_current_stage и update_progress. Основной способ отслеживания - нотификаций, в частности событие profile.updated, которое описано ниже в разделе "Уведомление о изменении профиля".
Загруженные на шаге 4 данные доступны на постоянной основе и могут в любое время получены через API. К примеру для списка продуктов это запрос GET /accounts, а операций - GET /transactions. Запрашивать можно и в момент импорта, однако данные в таком случае будут только частично обновлены.
Запуск импорта через серверное API
При таком способе визуальные формы для клиента необходимо реализовывать самостоятельно в приложении, а все шаги импорта выполняется через различные API методы. Данный раздел преимущественно посвящен именно этому способу.
Запуск импорта через визуальные модули
CASHOFF предоставляет готовый визуальный модуль profile-update, через который клиент может выбрать провайдера для подключения, авторизоваться и наблюдать процесс импорта данных. Приложению остается только забрать данные (шаг 4). Подробнее о использовании визуальных модулей написано в разделе Встраиваемые UI модули.
Данный модуль последовательно выполняет шаги 1-3, но при этом начать можно с любого шага. Например можно самостоятельно реализовать в приложении выбор провайдера, а визуальный модуль использовать только для процесса обновления и авторизации.
Рисунок 1. Общий цикл импорта данных
Так же его можно использовать исключительно для авторизации: показывать модуль при статусе профиля updating. Такой подход позволяет избавить приложение от необходимости работать с авторизационными данными клиента от провайдеров.
Данный модуль можно использовать как образец реализации интерфейса подключения и обновления профиля.
В итоге приложению остается только отслеживать завершение обновления профиля (серверными нотификациями или с помощью сообщений на клиенте) и получить данные из CASHOFF. Повторные обновления можно производить так же при помощью этого модуля.
Добавление нового профиля
Добавление профиля происходит запросом POST /profiles/add, в котором нужно указать идентификатор провайдера:
{
"provider_key": "sber"
}
Запрос в таком виде только создаст новый профиль, но не выполнит шаги 2 и 3.
Эти действия выполняются отдельными запросами, POST /profiles/{profile_id}/update и POST /profiles/{profile_id}/session/auth соответственно, но их можно выполнить и разом при создании:
{
"provider_key": "sber",
"start_update": true,
"auth_data": {
"login": "VApTr56Ui9",
"password": "8Apq0Ohy1"
}
}
В данном запросе атрибут start_update запустит обновление (шаг 2), а auth_data предоставит данные для первого шага авторизации (шаг 3).
Пример ответа:
{
"profile": {
"id": 1291399,
"user_id": 1330891,
"provider": {
"id": 72,
"key": "sber",
"name": "Сбербанк",
"type": "bank",
"logo": "https://cashoff.ru/static/build/cashoff/v-7c7f6a8a477c1b3e3d20a0ca10147158/img/logo/fi/sber_36.svg"
},
"session": {
"key": "ac1db988825748b595526852e02c2712",
"status": "ok"
},
"status": "updating",
"created": "2019-03-28T08:52:23Z",
"changed": "2019-03-28T08:52:23Z"
},
"update_status": "ok"
}
Переданные при создании профиля данные авторизации (auth_data) используются только если одновременно запускается обновление (start_update). Если обновление не запускается, то будет сохранен только логин (для контроля уникальности профиля у пользователя), а пароль не перенесется к моменту следующего запуска обновления.
Если на первом шаге нет данных для ввода (например "пустой" шаг, который будет описан далее), то для выполнения авторизации нужно указать пустой auth_data, а не пропускать его совсем: без него запрос будет считаться просто запуском обновления, без выполнения шага авторизации.
CASHOFF не позволяет одному и тому же пользователю добавлять несколько одинаковых профилей (профили с одинаковым провайдером и логином). При повторном добавлении будет возвращена ошибка profile_exists, а в атрибуте extra.existing_profile_id можно будет найти идентификатор существующего дублирующего профиля. Подобная же ошибка будет при запросе POST /profiles/{profile_id}/session/auth, если изначально запрос создания профиля не включал логин, а тут он пришел и нашелся дублирующий профиль.
Запуск обновления профиля
Обновление запускается с помощью запроса POST /profiles/{profile_id}/update. Ответ придет с полем status, в котором будет указано что обновление либо успешно запущено (ok), либо код причины невозможности запуска.
Обновление состоит из двух ключевых фаз:
- Авторизация. Сначала идет попытка подключения по сохраненным данным (есть еще активная сессия). Если это не получается, то запускается сам процесс авторизации
- Импорт данных. Данная фаза возможна только после успешной авторизации.
Авторизация в ЛК провайдера
В процессе авторизации CASHOFF с помощью предоставляемых клиентом данных пытается авторизоваться в ЛК провайдера. В авторизации есть ряд ключевых моментов, которые нужно учитывать:
- Последовательность шагов авторизации не фиксирована: многие ЛК поддерживают вход как с смс, так и без, могут запрашивать проверочные вопросы, а так же выдавать дополнительные шаги в зависимости от введенных данных. Как результат набор шагов и их количество могут меняться в зависимости от пользователя, даже в рамках одного профиля.
- Пользователь может ошибаться при вводе данных авторизации, по этому каждый шаг может завершиться ошибкой введенных данных (например не правильный пароль). Такую ошибку необходимо показать пользователю и для продолжения обновления он должен будет повторить ввод данных текущего шага.
С учетом этих моментов общая схема авторизации выглядит следующим образом:
- CASHOFF проверяет статус сохраненной у него сессии в ЛК провайдера.
- Сессия "жива" (по ней можно получить данные): авторизация завершена, переход к шагу 6.
- Сессия не "жива": начинается непосредственно процесс авторизации.
- CASHOFF определяет текущий шаг авторизации и указывает в профиле какой шаг нужно выполнить сейчас (session.auth_step).
- Приложение показывает пользователю форму из session.auth_step.
- Пользователь вводит данные в форму, приложение отправляет форму в CASHOFF.
- CASHOFF применяет данные для авторизации в ЛК. Далее может быть один из следующих исходов:
- Шаг выполнен успешно, больше шагов нет: авторизация завершена, переход к шагу 6.
- Шаг выполнен успешно, но есть следующий: профиль получает новую форму (session.auth_step) и с ней повторяет шаги 3-5.
- Шаг выполнен неуспешно: форма (session.auth_step) остается та же, приложение показывает пользователю ошибку и он повторяет ввод данных (шаг 4).
- Авторизация завершена, начинается импорт данных.
Рисунок 2. Проверка сессии и запуск авторизации
Таким образом авторизация представляет собой цикл из шагов 2-5, который предваряется проверкой статуса имеющейся сессии и завершается переходом в импорт данных.
Данные на шаге 5 передаются в CASHOFF с помощью запроса POST /profiles/{profile_id}/session/auth и должны соответствовать текущему шагу (session.auth_step):
{
"auth_data": {
"sms": "1234"
}
}
Т.к. авторизация является частью процесса обновления, то каждый раз при отправке данных профиль будет переходить в статус updating, взаимодействовать фоново с провайдером и по результату переходить в какой-то из статусов: auth, error, ok.
Завершение фазы авторизации можно отследить по тому, что update_current_stage <> auth.
В CASHOFF есть ограничение в 15 минут на выполнение шага 4: если с момента установки текущего шага авторизации не придет в течении 15 минут запрос с данным для него, то процесс авторизации (вместе с обновлением) будет сброшен и обновление нужно будет начинать заново. Любая отправка данных, даже не позволившая пройти шаг, приведет к обновлению таймера. По этому суммарно время авторизации не ограничено этими 15 минутами - это ограничение только на попытку (на стороне CASHOFF, провайдеры всё равно могут накладывать свои ограничения).
Описания шагов авторизации
Каждый шаг авторизации провайдера представляет собой форму с набором полей. Типовая форма первого шага выглядит следующим образом:
{
"key": "initial",
"fields": [
{
"key": "login",
"type": "text",
"label": "Логин"
},
{
"key": "password",
"type": "password",
"label": "Пароль"
}
]
}
У данной формы ключ initial, и в ней содержится поля: login и password. По ней необходимо вывести пользователю форму с двумя полями, "Логин" и "Пароль". Поля формы с type=password должны маскировать вводимые в них данные.
Если в форме указан атрибут help, то его содержимое нужно вывести пользователю над полями - это вспомогательный текст содержащий 1-2 предложения, который поясняет особенности ввода данных на данной форме.
Если заполнен атрибут session.status_message, то его текст нужно вывести в качестве ошибки формы.
Результат ввода по этой форме, будучи отправленным в cashoff, выглядит следующим образом:
{
"auth_data": {
"login": "1234",
"password": "qwerty"
}
}
Шаг авторизации с выбором формы
В качестве шага авторизации session.auth_step может быть указана не одна форма, а несколько: это означает что пользователь может выбрать с помощью каких данных авторизоваться. При этом разные формы могут привести к разным последующим шагам. Вот пример шага из двух форм на выбор:
[
{
"key": "credentials",
"fields": [
{
"key": "login",
"type": "text",
"label": "Логин"
},
{
"key": "password",
"type": "password",
"label": "Пароль"
}
]
},
{
"key": "phone",
"fields": [
{
"key": "phone",
"type": "text",
"label": "Телефон"
}
]
}
]
В примере пользователь может либо ввести логин и пароль, либо ввести номер телефона. Нужно предоставить пользователю выбор из этих двух форм, дать ему заполнить одну из них и отправить POST /profiles/{profile_id}/session/auth с обязательным указанием в атрибуте form_key какая форма выбрана:
{
"form_key": "phone",
"auth_data": {
"phone": "+79991234567"
}
}
Выбор потенциально может прийти на любом шаге, но обычно это первый, который определяет весь сценарий авторизации.
Рисунок 3. Login & Password Authorization Flow — общий сценарий
Авторизация с помощью QR-кода
В CASHOFF у ряда провайдеров есть возможность авторизации с помощью сканирования QR-кода приложением провайдера и подтверждения авторизации в нём. В таком случае на этапе сканирования придёт следующая форма:
{
"key": "check_qr_code",
"help": "Отсканируйте QR-код в Вашем приложении банка.",
"qr_code": "gpbapp://auth/qr?code=AQICGySDjnmLpaiVQnADiWPO1D1B7e4g5sPzRRDg7F8OPERZy5Rbtd1H5dW2elmvz4aoUd6U5GhmskyiIIx2QQFBKmoNj3nCokDMFvyOuZf+vSZU0xo91slLmoY604oJ7Oi78aNO0TAUGLYyykZcEcNfc&info=aSzAr0WCcr7Ftzl2quVSY9mF",
"qr_code_usage_hint": "inapp_scan_image",
"qr_expiration_time": "2026-05-27T16:58:14Z",
"fields": []
}
В ней пустой список полей (т.к. вводить ничего не нужно), но указан атрибут qr_code - по нему нужно показать пользователю QR-код. В данном случае нужно показать пользователю форму с текстом "Отсканируйте QR-код в Вашем приложении банка.", под ней QR-код и далее кнопка перехода на следующий шаг авторизации.
Система не проверяет в фоне факт подтверждения авторизации в приложении провайдера: пользователю нужно самостоятельно нажать кнопку перехода на следующий шаг (а приложению отправить POST /profiles/{profile_id}/session/auth) после того, как он авторизацию подтвердил. Т.к. на форме нет полей для ввода, то данные авторизации в запросе будут пустым объектом:
{
"auth_data": {}
}
После этого CASHOFF проверит прошла ли авторизация и пойдёт дальше если это так. Если авторизация не прошла и текущий QR-код истёк, то вернётся форма с новым QR-кодом - она должна заменить старую.
Опционально с QR-кодом может прийти так же срок его действия (qr_expiration_time) и подсказка об способе сканирования (qr_code_usage_hint). Последняя поможет если авторизация происходит уже на телефоне и QR-код просканировать напрямую не получится.
QR-код на первом шаге
Первый шаг авторизации всегда статичен, по этому на нём не может прийти персонального QR-кода. Если авторизация начинается со сканирования, то в начале будет промежуточный "пустой" шаг с пояснением что будет дальше, например:
{
"key": "qr_code",
"name": "Вход по QR-коду",
"help": "Для входа потребуется отсканировать QR-код внутри приложения банка.",
"qr_code_usage_hint": "open_url",
"fields": []
}
На нем так же нет полей, по этому пользователь ознакомившись с сообщением аналогично переходит на следующий этап. Обычно такой шаг появляется в рамках выбора из нескольких форм авторизации.
Важно отметить что это выбор единоразовый в рамках данной авторизации т.к. нет возможности перейти на шаг назад - пользователь далее сможет продолжить только с QR-кодом. Пользователю нужно заново начать авторизацию что бы иметь возможность выбрать другой сценарий авторизации. Что бы начать заново нужно сделать сброс запросом POST /profiles/{profile_id}/reset.
В данном примере пользователь может зайти с помощью номера телефона или по QR-коду:
[
{
"key": "phone",
"name": "Вход по номеру телефона",
"help": "Введите номер телефона в формате +79999999999.",
"fields": [
{
"key": "login",
"type": "text",
"label": "Номер Телефона",
}
]
},
{
"key": "qr_code",
"name": "Вход по QR-коду",
"help": "Для входа потребуется отсканировать QR-код внутри приложения банка.",
"qr_code_usage_hint": "open_url",
"fields": []
}
]
Если пользователь выберет форму qr_code, то на следующем шаге он получит QR-код для сканирования.
В такие формы так же добавляется qr_code_usage_hint: он сигнализирует какой qr_code_usage_hint будет на следующем шаге. Если текущий вариант не подходит, то форму для пользователя можно скрыть и оставить только подходящую (в данном случае ввод номера телефона).
Включение авторизации по QR-коду
Для обратной совместимости данный способ авторизации сделан опциональным. Что бы включить его нужно сделать запрос POST /settings/profiles/optional-features и указать там qr_auth: true. Без данного флага формы авторизации по qr будут исключаться из выдачи там, где они опциональны.
Рисунок 4. Пример возможного варианта авторизации через QR-код
Импорт данных
После успешной авторизации обновление переходит к импорту данных. Сигналом окончания обновления будет переход профиля в статус ok (успешное завершение) или fatal (обновление прервалось ошибкой). Во втором случае текст ошибки будет доступен в поле session.status_message - это готовое сообщение для пользователя.
Набор данных зависит от типа провайдера, подробнее о списке загружаемых данных в зависимости от типа провайдера написано в разделе Провайдеры.
В CASHOFF обновление данных выполняется где возможно инкрементно: при каждом обновлении запрашиваются только данные за те даты, за которые они еще не загружены.
Указание выполняемых при импорте данных действий
При запуске обновления можно указать, какие данные нужно импортировать - за это отвечает атрибут update_stages (есть как в методе запуска обновления, так и в методе создания профиля). В нём перечисляются шаги, которые нужно выполнить в рамках обновления, а так же можно на некоторых шагах затребовать выполнение дополнительных действий. Атрибут может заполняться в двух форматах: сокращенном (список идентификаторов шагов) и развернутом (для каждого шага можно указать доп. действия). Пример сокращенного:
["auth", "accounts"]
(запрошена авторизация и загрузка списка продуктов). Пример развернутого:
{
"auth": {},
"accounts": {
"payment_rub": true
}
}
(то же самое, только для продуктов запрошено определение того, с какого продукта можно совершать рублевые платежи через CASHOFF).
При указании списка шагов шаг auth можно опустить, т.к. он выполняется автоматически при необходимости. Однако его необходимо указать, если цель обновления - только обновить авторизацию:
["auth"]
Такое обновление используется в тех случаях, когда данные импортировать не нужно, а работа с профилем будет выполняться напрямую (например вызовы методов, создающие платежи), а не через импорт данных в рамках обновления..
Если атрибут не заполнен, то шаги по умолчанию проставляются согласно типу провайдера.
На каком конкретно этапе обновления сейчас находится профиль можно узнать через поле update_current_stage. К примеру в случае авторизации там будет auth, а в случае загрузки списка продуктов - accounts.
Ошибки в процессе обновления данных
Импорт данных может завершиться ошибкой, вызванной как парсером, так и провайдером. В таких случаях профиль получает статус status=error, а текст ошибки будет в поле session.status_message; код причины ошибки можно найти в атрибуте last_attempt_error.
При ошибке обновление прерывается. Далее можно либо сбросить текущий статус (POST /profiles/{profile_id}/reset), либо запустить обновление заново (POST /profiles/{profile_id}/update) (по сути это сброс + запуск).
Сброс очистит текст ошибки и переведет авторизацию на первый шаг. При сбросе уже загруженные данные останутся не тронутыми, он касается только непосредственно состояния профиля.
Уведомления об изменении профиля
В CASHOFF предусмотрено событие profile.updated, уведомления по которому отправляется при изменении профиля. Изменение включают в себя изменение профиля (статуса и текущего этапа обновления), состояния сессии
Уведомления не отправляются при изменении загруженных по профилю данных, в частности продуктов, операций и чеков. Данное событие является основным способом отслеживания процесса импорта данных.
В теле уведомления profile.updated приходит полная информация по профилю, аналогичная выдаче запроса GET /profiles/{profile_id}.
Ниже представлены примеры уведомлений по различным этапам импорта данных
Требуется ввод данных авторизации (смс)
|
Обновление успешно завершено
|
Неверные данные авторизации
|
Ошибка обновления профиля
|



