Справочник API Vio eSIM
Два REST-интерфейса на одном бэкенде: клиентский API, на котором работает веб-приложение и наши приложения для iOS/Android, и отдельный Партнёрский API с аутентификацией по API-ключу для программной перепродажи Vio eSIM.
https://vioesim.com/api/v1https://vioesim.com/api/public/v1Аутентификация мобильного приложения
Веб-приложение и нативные приложения используют одну систему сессий — нативное приложение просто хранит сам токен вместо использования cookie.
Регистрация или вход. Оба эндпоинта возвращают поле token вместе с объектом пользователя (а также заголовок Set-Cookie, который вместо этого использует веб-приложение). Храните token в Keychain (iOS) или в хранилище на основе Keystore (Android).
Отправляйте его обратно в каждом запросе:
Authorization: Bearer <token>Срок действия токена: 30 дней с момента выдачи или до вызова /api/v1/auth/logout. Шага обновления токена нет — токен с истекающим сроком просто заменяется повторным входом пользователя.
Аутентификация Партнёрского API
Для внешних компаний, перепродающих Vio eSIM через собственный сайт или приложение. Партнёр — это обычная учётная запись Vio eSIM: создайте ключ в разделе Панель управления → API-ключи (показывается один раз — сохраните его, повторно он показан не будет), затем отправляйте его в каждом запросе:
Authorization: Bearer vio_live_sk_...
# or
X-API-Key: vio_live_sk_...Создание нового ключа немедленно делает предыдущий недействительным.
Быстрый старт — Партнёрский API
Просмотрите каталог и купите eSIM за два вызова:
curl https://vioesim.com/api/public/v1/destinations \
-H "Authorization: Bearer vio_live_sk_..."
curl -X POST https://vioesim.com/api/public/v1/orders \
-H "Authorization: Bearer vio_live_sk_..." \
-H "Content-Type: application/json" \
-d '{ "planId": "cus...", "quantity": 1 }'Ошибки и ограничения частоты запросов
Мобильный/веб API возвращает { "error": "сообщение" } (сообщения сейчас на турецком). Партнёрский API возвращает структурированный формат, чтобы вы могли обрабатывать по code:
{ "error": { "code": "INSUFFICIENT_BALANCE", "message": "Insufficient wallet balance." } }| Статус | Значение |
|---|---|
| 401 | Отсутствующий/неверный/истёкший токен или API-ключ |
| 402 | Только Партнёрский API — недостаточно средств на балансе |
| 404 | Ресурс не найден или не принадлежит вызывающей стороне |
| 409 | Конфликтующее состояние (напр. удаление аккаунта с ненулевым балансом) |
| 429 | Достигнут лимит частоты запросов — см. заголовок Retry-After (в секундах) |
| 502 | Платёж списан, но выпуск eSIM не удался — не повторяйте списание |
Ограничения частоты (Партнёрский API): 120 запросов/мин на ключ для чтения, 30 запросов/мин на POST /orders.
Мобильный / веб API
Аутентификация
Регистрация
Создаёт учётную запись и активную сессию.
{
"firstName": "Ada",
"lastName": "Lovelace",
"email": "[email protected]",
"password": "min 8 chars"
}{
"success": true,
"user": {
"id", "firstName", "lastName", "fullName", "email",
"emailVerified", "walletBalance", "currency", "locale", "createdAt"
},
"token": "..."
}Вход
Тело: { email, password }. Тот же формат ответа, что и у регистрации. 401 при неверных данных, 403 если аккаунт заблокирован.
Выход
Без тела запроса. Удаляет сессию на сервере — вызывайте при реальном выходе, а не просто «забыв токен локально», чтобы украденный токен не мог продолжать работать.
Текущий пользователь
Возвращает { "user": null } (никогда не ошибку) при выходе из системы — используйте при запуске приложения, чтобы решить, показывать ли экран входа.
Забыли пароль
Тело: { email, locale }. Всегда возвращает { success: true } независимо от существования адреса, чтобы нельзя было перебирать аккаунты. Отправляет письмо со ссылкой/токеном сброса (действует 1 час).
Сброс пароля
Тело: { token, newPassword }. GET с ?token= проверяет действительность перед показом формы ({ "valid": true|false }).
Смена пароля
Тело: { currentPassword, newPassword }. currentPassword обязателен, если у аккаунта ещё нет пароля (напр. вход через соцсеть).
Аккаунт
Обновить профиль
Отправляйте только те поля, которые хотите изменить.
| Field | Notes |
|---|---|
| firstName, lastName | необязательно · строка |
| preferredCurrency | необязательно · одно из USD EUR GBP TRY |
| locale | необязательно · 2-буквенный код, напр. ru |
{ "success": true, "user": { ...same shape as /auth/me } }Обновить аватар
Тело: { "avatarUrl": "data:image/..." } — base64 data URI, макс. ~1,5 МБ.
Создать API-ключ
Выдаёт новый Партнёрский API-ключ для этого аккаунта, заменяя предыдущий. Сырой ключ показывается только один раз, в этом ответе — впоследствии доступен только его префикс.
{
"success": true,
"key": "vio_live_sk_...",
"apiKeyPrefix": "vio_live_sk_ab12…9f8e",
"apiKeyGeneratedAt": "2026-08-22T17:00:00.781Z"
}Удалить аккаунт
Требуется для проверки App Store (приложения с созданием аккаунта должны предлагать удаление внутри приложения). Обезличивает аккаунт (email заменяется и освобождается для повторной регистрации, имя/аватар/пароль удаляются) вместо окончательного удаления строк, чтобы прошлые заказы оставались в бухгалтерских/налоговых записях. Удаляет все сессии и зарегистрированные push-устройства пользователя.
Каталог
Список направлений
Страны и регионы с активными тарифами, с ценами и в формате для UI (это то, что вызывает сама витрина). Необязательно ?filter=popular|regional|global|<текст поиска>.
Детали направления
Полная информация (описание, тарифы) для одной страны по коду ISO, напр. /api/v1/destinations/jp.
Покупки
Оформление заказа
Покупает тариф напрямую (в отличие от предварительного пополнения кошелька).
| Field | Notes |
|---|---|
| planId* | |
| quantity | необязательно · 1–10, по умолчанию 1 |
| paymentMethod* | wallet | stripe | crypto |
| successUrl, cancelUrl | необязательно · для перенаправлений stripe/crypto. Используйте универсальную/app-ссылку, а не обычный веб-URL, чтобы перенаправление снова открывало приложение. |
{ "success": true, "orderId": "..." }{ "success": true, "orderId": "...", "url": "https://checkout.stripe.com/..." }Пополнение кошелька через Stripe
Пополняет кошелёк картой — отдельный от оформления заказа процесс. Тело: { amount (в центах, мин. 200), currency, successUrl, cancelUrl }. Возвращает { sessionId, url }.
Пополнение кошелька криптовалютой
Тело: { amount (строка с десятичным числом, мин. $2), currency, url_return }. Возвращает объект счёта Cryptomus, включая url.
Список заказов
Все заказы вызывающей стороны, сначала новые.
Детали заказа
Один заказ, включая esimIds — получите полные данные eSIM (QR, код активации) через GET /api/v1/user/esims и сопоставьте по id.
Мои eSIM
Каждая eSIM, принадлежащая вызывающей стороне: iccid, activationCode, qrCodeUrl, smdpAddress, status, dataUsage/totalVolume (МБ), activatedAt, expiresAt. Это данные для экрана «Мои eSIM» и отображения QR.
История кошелька
История пополнений/выводов/покупок/возвратов для баланса кошелька, показанного в /auth/me.
Поддержка
Список обращений
Обращения вызывающей стороны с полными цепочками сообщений, сначала новые.
Новое обращение
Тело: { subject, category, message } (category необязательно).
Ответить на обращение
Тело: { message }. Ответ на обращение со статусом RESOLVED/CLOSED автоматически переоткрывает его.
Устройства push-уведомлений
Регистрирует только токены устройств — для реальной отправки нужны учётные данные APNs/FCM, см. примечание ниже.
Регистрация устройства
Вызывайте после получения токена APNs или FCM. Тело: { platform: "IOS"|"ANDROID", pushToken, appVersion }. Выполняет upsert по токену, поэтому повторный вызов при каждом запуске приложения безопасен и рекомендуется (токены могут меняться).
Отмена регистрации устройства
Тело: { pushToken }. Вызывайте при выходе из системы, чтобы общее/сброшенное устройство перестало получать уведомления другого пользователя.
Партнёрский API
Для всего перечисленного ниже требуется заголовок с API-ключом, описанный выше — cookie сессии здесь не применяется.
Каталог
Список направлений
Полный каталог в формате, ориентированном на партнёров (не в UI-формате витрины).
{
"countries": [
{
"code": "JP",
"name": { "en": "Japan", "tr": "Japonya", "...": "..." },
"flagEmoji": "🇯🇵",
"continent": "Asia",
"plans": [
{ "id": "cus...", "dataAmountMb": 1024, "durationDays": 7, "priceUsd": 4.25, "isTopUp": false }
]
}
],
"regions": [ { "code": "...", "name": {...}, "countryCount": 15, "plans": [...] } ]
}Детали направления
Одна страна по коду ISO (напр. /api/public/v1/destinations/JP), тот же формат тарифов, что и выше.
Заказы
Создать заказ
Покупает тариф с баланса кошелька вызывающей стороны и синхронно выпускает eSIM — ответ уже содержит данные QR/активации, готовые к передаче конечному клиенту. В штатном случае опрос не требуется.
{ "planId": "cus...", "quantity": 1 }{
"id": "...", "orderNumber": "VIO-API-...", "status": "COMPLETED", "amountUsd": 4.25,
"esims": [
{ "id": "...", "iccid": "...", "activationCode": "...",
"qrCodeUrl": "https://...", "smdpAddress": "...", "status": "PENDING" }
]
}Список заказов
Необязательно ?limit= (по умолчанию 25, макс. 100). Сокращённый формат — используйте эндпоинт деталей для данных eSIM.
Детали заказа
Полные детали заказа, включая данные QR/активации и текущее использование (dataUsageMb / totalVolumeMb) каждой eSIM — опрашивайте это, чтобы показать клиенту оставшийся трафик.
Кошелёк
Баланс кошелька
Проверяйте перед размещением большой партии заказов или настройте оповещение при низком балансе.
{ "balanceUsd": 128.40, "currency": "USD" }Что ещё не реализовано
Чтобы ничего здесь не считалось работающим, если это не так.
Отправка push-уведомлений
Регистрация токенов работает; для реальной отправки нужны учётные данные APNs/FCM.
Индивидуальные цены для партнёров
Партнёрский API сейчас взимает ту же розничную цену, что и витрина. Оптовые/договорные цены потребуют изменения схемы и бизнес-решения.
Refresh-токены
Сессии — это долгоживущие (30 дней) простые токены, а не пары короткоживущий access + refresh токен. Пока достаточно; пересмотреть позже для более строгой модели безопасности.
Нативный экран оплаты Stripe
Интеграция Stripe использует размещённый Checkout (перенаправление/webview). Нативный ввод карты вместо этого использовал бы PaymentIntents + SDK Stripe.
Вебхуки для партнёров
Партнёры должны опрашивать GET /orders/:id для получения статуса; исходящего вебхука (напр. «eSIM активирована») пока нет.
