Vio eSIM API 레퍼런스
동일한 백엔드 위의 두 가지 REST 인터페이스: 웹 앱과 iOS/Android 앱을 구동하는 고객용 API, 그리고 Vio eSIM을 프로그래밍 방식으로 재판매하기 위한 별도의 API 키 인증 파트너 API입니다.
https://vioesim.com/api/v1https://vioesim.com/api/public/v1모바일 앱 인증
웹 앱과 네이티브 앱은 동일한 세션 시스템을 공유합니다 — 네이티브 앱은 쿠키 저장소에 의존하는 대신 토큰 자체를 보관합니다.
가입 또는 로그인. 두 엔드포인트 모두 사용자 객체와 함께 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 | 상태 충돌(예: 잔액이 0이 아닌 계정 삭제) |
| 429 | 속도 제한 도달 — Retry-After 헤더(초) 참조 |
| 502 | 결제는 완료되었으나 eSIM 프로비저닝 실패 — 재청구하지 마세요 |
속도 제한(파트너 API): 읽기는 키당 분당 120회, POST /orders는 분당 30회.
모바일 / 웹 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 }. ?token=으로 GET 요청하면 폼을 표시하기 전에 유효성을 확인할 수 있습니다({ "valid": true|false }).
비밀번호 변경
본문: { currentPassword, newPassword }. 계정에 아직 비밀번호가 설정되지 않은 경우(예: 소셜 로그인)를 제외하고 currentPassword는 필수입니다.
계정
프로필 업데이트
변경하려는 필드만 전송하세요.
| Field | Notes |
|---|---|
| firstName, lastName | 선택 · 문자열 |
| preferredCurrency | 선택 · USD, EUR, GBP, TRY 중 하나 |
| locale | 선택 · 2자리 코드, 예: ko |
{ "success": true, "user": { ...same shape as /auth/me } }아바타 업데이트
본문: { "avatarUrl": "data:image/..." } — base64 data URI, 최대 약 1.5MB.
API 키 생성
이 계정에 대한 새 파트너 API 키를 발급하여 이전 키를 대체합니다. 원본 키는 이 응답에서만 한 번 표시됩니다 — 이후에는 접두사만 조회할 수 있습니다.
{
"success": true,
"key": "vio_live_sk_...",
"apiKeyPrefix": "vio_live_sk_ab12…9f8e",
"apiKeyGeneratedAt": "2026-08-22T17:00:00.781Z"
}계정 삭제
App Store 심사에 필요합니다(계정 생성 기능이 있는 앱은 앱 내 삭제를 제공해야 함). 과거 주문이 세무/회계 기록으로 남도록 행을 완전히 삭제하는 대신 계정을 익명화합니다(이메일은 뒤섞여 재가입에 사용 가능해지고, 이름/아바터/비밀번호는 지워집니다). 해당 사용자의 모든 세션과 등록된 푸시 기기를 삭제합니다.
카탈로그
목적지 목록 조회
유효한 요금제가 있는 국가 및 지역을 가격이 매겨지고 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 리디렉션용. 리디렉션이 앱을 다시 열도록 일반 웹 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 }. url을 포함한 Cryptomus 인보이스 객체를 반환합니다.
주문 목록
호출자의 모든 주문을 최신순으로 반환합니다.
주문 상세 정보
esimIds를 포함한 단일 주문 — GET /api/v1/user/esims로 전체 eSIM 상세 정보(QR, 활성화 코드)를 가져와 id로 매칭하세요.
내 eSIM
호출자가 소유한 각 eSIM: iccid, activationCode, qrCodeUrl, smdpAddress, status, dataUsage/totalVolume(MB), activatedAt, expiresAt. "내 eSIM" 화면과 QR 표시를 구동하는 데이터입니다.
지갑 내역
/auth/me에 표시되는 지갑 잔액에 대한 충전/출금/구매/환불 내역.
고객 지원
티켓 목록
호출자의 티켓과 전체 메시지 스레드를 최신순으로 반환합니다.
새 티켓
본문: { subject, category, message }(category는 선택 사항).
티켓 답변
본문: { message }. RESOLVED/CLOSED 상태의 티켓에 답변하면 자동으로 다시 열립니다.
푸시 알림 기기
기기 토큰 등록만 처리합니다 — 실제 전송에는 APNs/FCM 자격 증명이 필요합니다. 아래 참고 사항을 확인하세요.
기기 등록
APNs 또는 FCM 토큰을 받은 후 호출하세요. 본문: { platform: "IOS"|"ANDROID", pushToken, appVersion }. 토큰 기준으로 upsert되므로 앱 시작 시마다 다시 호출해도 안전하며 권장됩니다(토큰은 순환될 수 있음).
기기 등록 해제
본문: { pushToken }. 공유되거나 초기화된 기기가 다른 사용자의 알림을 계속 받지 않도록 로그아웃 시 호출하세요.
파트너 API
아래 항목들은 모두 위에서 설명한 API 키 헤더가 필요합니다 — 여기서는 세션 쿠키가 적용되지 않습니다.
카탈로그
목적지 목록 조회
스토어프론트 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 데이터는 상세 엔드포인트를 사용하세요.
주문 상세 정보
각 eSIM의 QR/활성화 데이터와 실시간 사용량(dataUsageMb / totalVolumeMb)을 포함한 전체 주문 상세 정보 — 고객에게 남은 데이터를 표시하려면 이를 폴링하세요.
지갑
지갑 잔액
대량 주문 전에 확인하거나 잔액이 부족할 때 알림을 설정하세요.
{ "balanceUsd": 128.40, "currency": "USD" }아직 구축되지 않은 기능
여기에 없는 것이 작동하는 것처럼 오인되지 않도록 하기 위함입니다.
푸시 알림 전송
토큰 등록은 작동하지만 실제 전송에는 APNs/FCM 자격 증명이 필요합니다.
파트너별 가격 책정
파트너 API는 현재 스토어프론트와 동일한 소매 가격을 청구합니다. 도매/협상 가격에는 스키마 변경과 비즈니스 결정이 필요합니다.
리프레시 토큰
세션은 단기 액세스 토큰과 리프레시 토큰 쌍이 아닌 장기(30일) 단일 토큰입니다. 현재로서는 충분하며, 더 엄격한 보안 체계가 필요해지면 추후 재검토합니다.
네이티브 Stripe 결제 화면
Stripe 연동은 현재 호스팅형 Checkout(리디렉션/웹뷰)을 사용합니다. 네이티브 카드 입력 UI에는 PaymentIntents와 Stripe SDK가 필요합니다.
파트너용 Webhook
파트너는 현재 상태 확인을 위해 GET /orders/:id를 폴링해야 합니다. 아직 발신 Webhook(예: "eSIM이 활성화됨")은 제공되지 않습니다.
