Référence API Vio eSIM
Deux interfaces REST sur le même backend : l'API destinée aux clients qui alimente l'application web et nos applications iOS/Android, et une API Partenaire distincte, authentifiée par clé API, pour revendre Vio eSIM de manière programmatique.
https://vioesim.com/api/v1https://vioesim.com/api/public/v1Authentification de l'application mobile
L'application web et les applications natives partagent un seul système de session — une application native transporte simplement le jeton lui-même au lieu de dépendre d'un cookie.
Inscrivez-vous ou connectez-vous. Les deux points de terminaison renvoient un champ token accompagnant l'objet utilisateur (ainsi qu'un en-tête Set-Cookie utilisé par l'application web). Stockez token dans le Trousseau (iOS) ou le stockage sécurisé par Keystore (Android).
Renvoyez-le à chaque requête :
Authorization: Bearer <token>Durée de vie du jeton : 30 jours à partir de l'émission, ou jusqu'à l'appel de /api/v1/auth/logout. Il n'y a pas d'étape de jeton de rafraîchissement — un jeton bientôt expiré est simplement remplacé en redemandant à l'utilisateur de se connecter.
Authentification de l'API Partenaire
Pour les entreprises externes qui revendent Vio eSIM via leur propre site ou application. Un partenaire est un compte Vio eSIM normal : générez une clé depuis Tableau de bord → Clés API (affichage unique — conservez-la, elle ne pourra plus être réaffichée), puis envoyez-la à chaque requête :
Authorization: Bearer vio_live_sk_...
# or
X-API-Key: vio_live_sk_...Générer une nouvelle clé invalide immédiatement la précédente.
Démarrage rapide — API Partenaire
Parcourez le catalogue et achetez une eSIM en deux appels :
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 }'Erreurs et limites de débit
L'API Mobile/Web renvoie { "error": "message" } (messages actuellement en turc). L'API Partenaire renvoie une forme structurée pour que vous puissiez brancher sur code :
{ "error": { "code": "INSUFFICIENT_BALANCE", "message": "Insufficient wallet balance." } }| Statut | Signification |
|---|---|
| 401 | Jeton ou clé API manquant/invalide/expiré |
| 402 | API Partenaire uniquement — solde du portefeuille trop bas |
| 404 | Ressource introuvable ou non détenue par l'appelant |
| 409 | État conflictuel (ex. suppression d'un compte avec un solde non nul) |
| 429 | Limite de débit atteinte — voir l'en-tête Retry-After (secondes) |
| 502 | Paiement capturé mais provisionnement de l'eSIM échoué — ne relancez pas le paiement |
Limites de débit (API Partenaire) : 120 req/min par clé en lecture, 30 req/min sur POST /orders.
API Mobile / Web
Authentification
Inscription
Crée un compte et une session active.
{
"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": "..."
}Connexion
Corps : { email, password }. Même forme de réponse que l'inscription. 401 en cas d'identifiants incorrects, 403 si le compte est suspendu.
Déconnexion
Pas de corps. Supprime la session côté serveur — appelez ceci lors d'une vraie déconnexion, pas seulement en "oubliant le jeton localement", afin qu'un jeton volé ne puisse pas continuer à fonctionner.
Utilisateur actuel
Renvoie { "user": null } (jamais une erreur) en cas de déconnexion — utilisez ceci au lancement de l'app pour décider d'afficher l'écran de connexion.
Mot de passe oublié
Corps : { email, locale }. Renvoie toujours { success: true } que l'adresse existe ou non, afin de ne pas permettre l'énumération des comptes. Envoie un e-mail avec un lien/jeton de réinitialisation (expire dans 1 heure).
Réinitialiser le mot de passe
Corps : { token, newPassword }. Un GET avec ?token= vérifie la validité avant d'afficher le formulaire ({ "valid": true|false }).
Changer le mot de passe
Corps : { currentPassword, newPassword }. currentPassword est requis sauf si le compte n'a pas encore de mot de passe (ex. connexion sociale).
Compte
Mettre à jour le profil
Envoyez uniquement les champs que vous souhaitez modifier.
| Field | Notes |
|---|---|
| firstName, lastName | facultatif · texte |
| preferredCurrency | facultatif · l'un de USD EUR GBP TRY |
| locale | facultatif · code à 2 lettres, ex. fr |
{ "success": true, "user": { ...same shape as /auth/me } }Mettre à jour l'avatar
Corps : { "avatarUrl": "data:image/..." } — un URI de données base64, max ~1,5 Mo.
Générer une clé API
Émet une nouvelle clé API Partenaire pour ce compte, remplaçant toute clé précédente. La clé brute n'est affichée qu'une fois, dans cette réponse — seul son préfixe reste ensuite récupérable.
{
"success": true,
"key": "vio_live_sk_...",
"apiKeyPrefix": "vio_live_sk_ab12…9f8e",
"apiKeyGeneratedAt": "2026-08-22T17:00:00.781Z"
}Supprimer le compte
Requis pour la revue App Store (les applications avec création de compte doivent proposer la suppression dans l'app). Anonymise le compte (e-mail brouillé et libéré pour une nouvelle inscription, nom/avatar/mot de passe effacés) plutôt que de supprimer définitivement les lignes, afin que les commandes passées restent sur les registres pour la comptabilité/fiscalité. Détruit toutes les sessions et tous les appareils push enregistrés de l'utilisateur.
Catalogue
Lister les destinations
Pays et régions avec forfaits actifs, tarifés et formatés pour l'UI (c'est ce que la boutique elle-même appelle). Optionnel ?filter=popular|regional|global|<texte de recherche>.
Détail d'une destination
Détail complet (description, forfaits) pour un pays par code ISO, ex. /api/v1/destinations/jp.
Achats
Paiement
Achète un forfait directement (par opposition à un dépôt préalable dans le portefeuille).
| Field | Notes |
|---|---|
| planId* | |
| quantity | facultatif · 1–10, défaut 1 |
| paymentMethod* | wallet | stripe | crypto |
| successUrl, cancelUrl | facultatif · pour les redirections stripe/crypto. Utilisez un lien universel/app, pas une simple URL web, afin que la redirection rouvre l'application. |
{ "success": true, "orderId": "..." }{ "success": true, "orderId": "...", "url": "https://checkout.stripe.com/..." }Rechargement du portefeuille via Stripe
Recharge le portefeuille par carte — un flux distinct du paiement. Corps : { amount (centimes, min 200), currency, successUrl, cancelUrl }. Renvoie { sessionId, url }.
Rechargement du portefeuille en crypto
Corps : { amount (chaîne décimale, min $2), currency, url_return }. Renvoie l'objet facture Cryptomus, y compris url.
Lister les commandes
Toutes les commandes de l'appelant, les plus récentes en premier.
Détail d'une commande
Une commande, incluant esimIds — récupérez le détail complet de l'eSIM (QR, code d'activation) via GET /api/v1/user/esims et faites correspondre par id.
Mes eSIM
Chaque eSIM possédée par l'appelant : iccid, activationCode, qrCodeUrl, smdpAddress, status, dataUsage/totalVolume (Mo), activatedAt, expiresAt. C'est ce qui alimente l'écran "Mes eSIM" et l'affichage du QR.
Historique du portefeuille
Historique des dépôts/retraits/achats/remboursements pour le solde du portefeuille affiché dans /auth/me.
Support
Lister les tickets
Les tickets de l'appelant avec leurs fils de messages complets, les plus récents en premier.
Nouveau ticket
Corps : { subject, category, message } (category facultatif).
Répondre à un ticket
Corps : { message }. Répondre à un ticket RESOLVED/CLOSED le rouvre automatiquement.
Appareils pour notifications push
Enregistre uniquement les jetons d'appareil — l'envoi effectif nécessite des identifiants APNs/FCM, voir l'encadré ci-dessous.
Enregistrer un appareil
À appeler après obtention d'un jeton APNs ou FCM. Corps : { platform: "IOS"|"ANDROID", pushToken, appVersion }. Fait un upsert par jeton, donc rappeler à chaque lancement de l'app est sûr et recommandé (les jetons peuvent changer).
Désenregistrer un appareil
Corps : { pushToken }. À appeler lors de la déconnexion afin qu'un appareil partagé/réinitialisé cesse de recevoir les notifications d'un autre utilisateur.
API Partenaire
Tout ce qui suit nécessite l'en-tête de clé API décrit ci-dessus — aucun cookie de session ne s'applique ici.
Catalogue
Lister les destinations
Catalogue complet, sous une forme orientée partenaire (pas la forme UI de la boutique).
{
"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": [...] } ]
}Détail d'une destination
Un pays par code ISO (ex. /api/public/v1/destinations/JP), même forme de forfaits que ci-dessus.
Commandes
Créer une commande
Achète un forfait sur le solde du portefeuille de l'appelant et provisionne l'eSIM de manière synchrone — la réponse contient déjà les données QR/activation, prêtes à remettre à votre client final. Aucun sondage nécessaire dans le cas nominal.
{ "planId": "cus...", "quantity": 1 }{
"id": "...", "orderNumber": "VIO-API-...", "status": "COMPLETED", "amountUsd": 4.25,
"esims": [
{ "id": "...", "iccid": "...", "activationCode": "...",
"qrCodeUrl": "https://...", "smdpAddress": "...", "status": "PENDING" }
]
}Lister les commandes
Optionnel ?limit= (défaut 25, max 100). Forme résumée — utilisez le point de terminaison de détail pour les données eSIM.
Détail d'une commande
Détail complet de la commande incluant les données QR/activation et l'usage en direct (dataUsageMb / totalVolumeMb) de chaque eSIM — sondez ceci pour montrer à votre client ses données restantes.
Portefeuille
Solde du portefeuille
Sondez avant de passer un gros lot de commandes, ou alertez-vous quand le solde est bas.
{ "balanceUsd": 128.40, "currency": "USD" }Ce qui n'est pas encore construit
Pour que rien ici ne soit présumé fonctionnel alors qu'il ne l'est pas.
Envoi des notifications push
L'enregistrement du jeton fonctionne ; l'envoi effectif nécessite des identifiants APNs/FCM.
Tarification spécifique au partenaire
L'API Partenaire facture actuellement le même prix de détail que la boutique. Une tarification de gros/négociée nécessiterait un changement de schéma et une décision commerciale.
Jetons de rafraîchissement
Les sessions sont des jetons plats à longue durée de vie (30 jours), pas des paires jeton d'accès court + jeton de rafraîchissement. Suffisant pour l'instant ; à revoir plus tard pour une posture de sécurité plus stricte.
Écran de paiement Stripe natif
L'intégration Stripe utilise le Checkout hébergé (redirection/webview). Une saisie de carte native utiliserait plutôt PaymentIntents + le SDK Stripe.
Webhooks pour les partenaires
Les partenaires doivent sonder GET /orders/:id pour le statut ; il n'y a pas encore de webhook sortant (ex. "eSIM activée").
