Connexion email
Le client s'inscrit ou demande un OTP avec email. Aucune sélection de
canal téléphone n'est nécessaire.
Cette page sert de guide rapide pour les intégrateurs backend, mobile et web. Elle liste les étapes métier dans le bon ordre, les endpoints à appeler, le payload minimal et une réponse minimale représentative pour chaque endpoint clé.
Cette vue regroupe les repères rapides utiles avant d'entrer dans les étapes du flow. Les OTP téléphone peuvent partir par SMS ou par WhatsApp selon le canal choisi par le client. Le backend applique le parcours demandé sans fallback implicite.
Le client s'inscrit ou demande un OTP avec email. Aucune sélection de
canal téléphone n'est nécessaire.
Le client envoie phone avec phone_channel = sms. Le
backend utilise le provider SMS configuré.
Le client envoie phone avec phone_channel = whatsapp.
Pour l'inscription ou l'OTP initial, le backend envoie d'abord le message
d'accueil puis l'OTP approuvé.
Provider principal déjà intégré avec deux modes d'appel distincts selon le besoin opérationnel ou les tests d'intégration.
easysendrest ou httpProvider alternatif déjà intégré pour permettre un fallback applicatif côté mobile, desktop ou backend quand EasySend n'est pas retenu.
topmessageObtenir le bearer token qui servira à préparer toute l'offre transport.
Ce token devra être envoyé dans l'en-tête Authorization: Bearer ... sur tous les endpoints d'administration suivants.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
identifier |
string | body | oui | Email ou telephone du superadmin. |
password |
string | body | oui | Mot de passe du superadmin. |
{
"identifier": "superadmin@ticketnet.ci",
"password": "SuperAdmin123!"
}
{
"success": true,
"message": "Connexion reussie",
"data": {
"access_token": "...",
"refresh_token": "...",
"user": {
"id": "user-id",
"photo_url": "https://cdn.ticketnet.ci/users/superadmin.jpg"
},
"roles": ["superadmin"],
"permissions": ["companies.create"]
}
}
Créer ou vérifier les destinations métier normalisées.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
name |
string | body | oui | Nom de la localisation. |
type |
string | body | oui | Type de localisation, par exemple city. |
country |
string | body | non | Pays de rattachement. |
{
"name": "Abidjan",
"type": "city",
"country": "Cote d'Ivoire"
}
{
"success": true,
"message": "Localisation creee",
"data": {
"id": "location-id-abidjan",
"name": "Abidjan",
"type": "city"
}
}
Enregistrer le transporteur qui proposera les trajets.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
name |
string | body | oui | Nom de la compagnie. |
phone |
string | body | non | Telephone principal de la compagnie. |
email |
string | body | non | Email principal de la compagnie. |
city |
string | body | non | Ville descriptive de la compagnie. |
country |
string | body | non | Pays de la compagnie. |
{
"name": "UTB",
"phone": "0701020304",
"email": "contact@utb.ci",
"city": "Abidjan",
"country": "Cote d'Ivoire"
}
{
"success": true,
"message": "Compagnie creee",
"data": {
"id": "company-id-utb",
"name": "UTB",
"status": "active"
}
}
Représenter le lieu physique réel, partagé ou dédié.
Une gare physique peut être partagée par plusieurs compagnies ou n'être utilisée que par une seule.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
location_id |
uuid | body | oui | ID de la ville ou localisation parente. |
name |
string | body | oui | Nom de la gare physique. |
address |
string | body | non | Adresse textuelle de la gare. |
photo_url |
string | body | non | Image illustrative de la gare. |
lat |
number | body | oui | Latitude de la gare. |
lng |
number | body | oui | Longitude de la gare. |
status |
string | body | non | Statut de la gare. |
{
"location_id": "location-id-abidjan",
"name": "Gare d'Adjame",
"address": "Adjame, face a la mairie",
"photo_url": "https://cdn.ticketnet.ci/hubs/adjame.jpg",
"lat": 5.3599517,
"lng": -4.0082563,
"status": "active"
}
{
"success": true,
"message": "Gare transport creee",
"data": {
"id": "transport-hub-id-adjame",
"name": "Gare d'Adjame",
"location": {
"id": "location-id-abidjan",
"name": "Abidjan"
}
}
}
Créer la présence opérationnelle de la compagnie dans la gare.
C'est ce niveau qui permet de dire quelle compagnie opère dans quelle gare, avec son point d'embarquement, son contact local ou son libellé d'affichage.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
company_id |
uuid | body | oui | ID de la compagnie. |
transport_hub_id |
uuid | body | oui | ID de la gare physique. |
display_name |
string | body | oui | Nom affiché côté client. |
internal_location |
string | body | non | Quai, zone ou point d'embarquement interne. |
phone |
string | body | non | Telephone local. |
email |
string | body | non | Email local. |
status |
string | body | non | Statut de la presence compagnie. |
{
"company_id": "company-id-utb",
"transport_hub_id": "transport-hub-id-adjame",
"display_name": "UTB - Adjame",
"internal_location": "Quai 2 - Zone nord",
"phone": "0102030405",
"email": "adjame@utb.ci",
"status": "active"
}
{
"success": true,
"message": "Presence compagnie creee",
"data": {
"id": "company-hub-id-utb-adjame",
"display_name": "UTB - Adjame",
"company": {
"id": "company-id-utb",
"name": "UTB"
}
}
}
Définir la liaison théorique entre ville de départ et destination.
Le trajet décrit la relation commerciale entre deux villes. Il ne correspond pas encore à un départ daté.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
company_id |
uuid | body | oui | ID de la compagnie. |
origin_location_id |
uuid | body | oui | ID de la ville de depart. |
destination_location_id |
uuid | body | oui | ID de la ville d'arrivee. |
name |
string | body | non | Libelle du trajet. |
code |
string | body | non | Code interne du trajet. |
{
"company_id": "company-id-utb",
"origin_location_id": "location-id-abidjan",
"destination_location_id": "location-id-bouake",
"name": "Abidjan - Bouake",
"code": "ABJ-BKE",
"status": "active"
}
{
"success": true,
"message": "Trajet cree",
"data": {
"id": "trip-id-abj-bke",
"name": "Abidjan - Bouake",
"status": "active"
}
}
Rendre une offre visible et vendable pour la recherche client.
Un départ ne pourra remonter dans la recherche que s'il est actif, cohérent avec le trajet et rattaché à des gares compagnie valides.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
trip_id |
uuid | body | oui | ID du trajet. |
origin_company_hub_id |
uuid | body | oui | ID du point de depart exploite par la compagnie. |
destination_company_hub_id |
uuid | body | oui | ID du point d'arrivee exploite par la compagnie. |
departure_at |
datetime ISO 8601 | body | oui | Date et heure de depart. |
arrival_estimated_at |
datetime ISO 8601 | body | non | Date et heure d'arrivee estimee. |
price |
int | body | oui | Prix du ticket en entier. |
capacity_total |
int | body | non | Capacite totale. |
capacity_remaining |
int | body | non | Places restantes. |
vehicle_label |
string | body | non | Libelle du vehicule. |
{
"trip_id": "trip-id-abj-bke",
"origin_company_hub_id": "company-hub-id-utb-adjame",
"destination_company_hub_id": "company-hub-id-utb-bouake-centre",
"departure_at": "2026-03-20T14:30:00.000Z",
"arrival_estimated_at": "2026-03-20T18:45:00.000Z",
"vehicle_label": "Bus VVIP",
"price": 4000,
"capacity_total": 70,
"capacity_remaining": 22,
"stopovers_label": "Direct (sans escale)",
"status": "active"
}
{
"success": true,
"message": "Depart cree",
"data": {
"id": "departure-id-abj-bke-1430",
"price": 4000,
"capacity_remaining": 22,
"status": "active"
}
}
Créer un compte client avec email ou téléphone puis passer à la vérification OTP.
Pour un téléphone, le client choisit explicitement le canal avec phone_channel : sms ou whatsapp.
Si phone_channel = whatsapp, le backend envoie d'abord le message d'accueil puis l'OTP approuvé.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
email |
string | body | conditionnel | Email du client. Requis si phone est absent. |
phone |
string | body | conditionnel | Telephone du client. Requis si email est absent. |
phone_channel |
string | body | conditionnel | Canal OTP pour un telephone : sms ou whatsapp. Requis en pratique si phone est envoye. |
sms_provider |
string | body | conditionnel | Provider SMS a utiliser si phone_channel vaut sms et qu un telephone est envoye. |
sms_mode |
string | body | conditionnel | Mode rest ou http pour EasySend si phone_channel vaut sms et sms_provider vaut easysend. |
{
"phone": "0701020304",
"phone_channel": "sms",
"sms_provider": "topmessage"
}
{
"success": true,
"message": "Inscription reussie",
"data": {
"userId": "client-id",
"next_step": "verify_otp"
}
}
Renvoyer un OTP pour un identifiant déjà connu dans le système.
Utiliser ce flow quand le compte existe déjà et qu'il faut renvoyer un code sans recréer l'utilisateur.
Pour un téléphone, le client choisit explicitement le canal avec phone_channel : sms ou whatsapp.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
identifier |
string | body | oui | Email ou telephone existant. |
phone_channel |
string | body | conditionnel | Canal OTP pour un telephone : sms ou whatsapp. Requis en pratique si identifier est un numero. |
sms_provider |
string | body | conditionnel | Provider SMS a utiliser si phone_channel vaut sms et identifier est un numero de telephone. |
sms_mode |
string | body | conditionnel | Mode rest ou http pour EasySend si phone_channel vaut sms et sms_provider vaut easysend. |
{
"identifier": "0701020304",
"phone_channel": "sms",
"sms_provider": "topmessage"
}
{
"success": true,
"message": "OTP envoye",
"data": {
"otp_expires_in": 300
}
}
Valider l'OTP et connecter immédiatement le client.
La réponse retourne directement la session complète : access token, refresh token, user, rôles et permissions.
Quand l'OTP telephone vient de WhatsApp, il suit le canal explicitement choisi par le client.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
identifier |
string | body | oui | Email ou telephone a verifier. |
otp |
string | body | oui | Code OTP a 6 chiffres. |
{
"identifier": "0701020304",
"otp": "123456"
}
{
"success": true,
"message": "OTP verifie",
"data": {
"access_token": "...",
"refresh_token": "...",
"user": {
"id": "client-id",
"photo_url": "https://cdn.ticketnet.ci/users/client-01.jpg"
},
"roles": ["client"],
"permissions": [],
"password_changed": false
}
}
Déclencher un OTP de réinitialisation par email ou téléphone.
Utiliser ce flow quand l'utilisateur a oublié son mot de passe et doit être reconnecté après validation du code.
Pour un téléphone, le client choisit explicitement le canal avec phone_channel : sms ou whatsapp.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
identifier |
string | body | oui | Email ou telephone du compte a reinitialiser. |
phone_channel |
string | body | conditionnel | Canal OTP pour un telephone : sms ou whatsapp. Requis en pratique si identifier est un numero. |
sms_provider |
string | body | conditionnel | Provider SMS a utiliser si phone_channel vaut sms et identifier est un numero de telephone. |
sms_mode |
string | body | conditionnel | Mode rest ou http pour EasySend si phone_channel vaut sms et sms_provider vaut easysend. |
{
"identifier": "client@ticketnet.com"
}
{
"success": true,
"message": "OTP de reinitialisation envoye",
"data": {
"otp_expires_in": 300
}
}
Valider l'OTP de réinitialisation et reconnecter l'utilisateur.
La réponse retourne immédiatement une nouvelle session utilisable côté mobile, web ou desktop.
Le mot de passe temporaire reste l'OTP validé tant qu'il n'a pas été remplacé.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
identifier |
string | body | oui | Email ou telephone a verifier. |
otp |
string | body | oui | Code OTP a 6 chiffres. |
{
"identifier": "client@ticketnet.com",
"otp": "123456"
}
{
"success": true,
"message": "OTP de reinitialisation verifie",
"data": {
"access_token": "...",
"refresh_token": "...",
"user": {
"id": "client-id",
"photo_url": "https://cdn.ticketnet.ci/users/client-01.jpg"
},
"roles": ["client"],
"permissions": [],
"password_changed": false
}
}
Le client se connecte avant toute recherche ou consultation détaillée.
À partir de cette étape, toutes les requêtes métier côté client doivent envoyer un bearer token valide.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
identifier |
string | body | oui | Email ou telephone du client. |
password |
string | body | oui | Mot de passe actuel du client. |
{
"identifier": "0701020304",
"password": "123456"
}
{
"success": true,
"message": "Connexion reussie",
"data": {
"access_token": "...",
"refresh_token": "...",
"user": {
"id": "client-id",
"photo_url": "https://cdn.ticketnet.ci/users/client-01.jpg"
},
"roles": ["client"],
"permissions": [],
"password_changed": true
}
}
Échanger un refresh token valide contre une nouvelle session.
Utiliser ce flow quand l'access token a expiré mais que la session utilisateur doit rester ouverte.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
refresh_token |
string | body | oui | Refresh token valide retourne lors du login ou de la verification OTP. |
{
"refresh_token": "REFRESH_TOKEN"
}
{
"success": true,
"message": "Token rafraichi",
"data": {
"access_token": "...",
"refresh_token": "...",
"user": {
"id": "client-id"
},
"roles": ["client"],
"permissions": [],
"password_changed": true
}
}
Invalider le refresh token courant pour fermer proprement la session.
Après cette étape, le refresh token ne doit plus être réutilisé par l'application cliente.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
Authorization |
string | header | oui | Bearer token du client connecte. |
refresh_token |
string | body | oui | Refresh token a invalider. |
{
"refresh_token": "REFRESH_TOKEN"
}
{
"success": true,
"message": "Deconnexion reussie",
"data": {
"success": true
}
}
Récupérer les informations du compte actuellement connecté.
Utiliser cet endpoint au démarrage de l'application cliente pour hydrater le profil et l'état de session.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
Authorization |
string | header | oui | Bearer token du client connecte. |
Aucun body requis. Utiliser les query params ou l'identifiant dans l'URL.
{
"success": true,
"message": "Profil recupere",
"data": {
"id": "client-id",
"email": "client@ticketnet.com",
"phone": "0701020304",
"photo_url": "https://cdn.ticketnet.ci/users/client-01.jpg",
"status": "active",
"roles": ["client"]
}
}
Mettre à jour les informations personnelles après connexion.
Si email ou phone change, le backend lance une verification OTP avant validation du nouveau contact. Le canal d'inscription d'origine n'est pas modifiable.
Pour un nouveau numéro, le client peut verifier par sms ou whatsapp.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
Authorization |
string | header | oui | Bearer token du client connecte. |
first_name |
string | body | non | Prenom du client. |
last_name |
string | body | non | Nom du client. |
date_of_birth |
date | body | non | Date de naissance. |
gender |
string | body | non | Sexe du client. |
residence |
string | body | non | Lieu d'habitation. |
city |
string | body | non | Ville de residence. |
country |
string | body | non | Pays de residence. |
photo_url |
string | body | non | URL de la photo de profil du client. |
email |
string | body | non | Email secondaire a ajouter ou modifier. Verification OTP requise si la valeur change. |
phone |
string | body | non | Telephone secondaire a ajouter ou modifier. Verification OTP requise si la valeur change. |
phone_channel |
string | body | conditionnel | Canal OTP a utiliser pour verifier un nouveau numero : sms ou whatsapp. |
sms_provider |
string | body | conditionnel | Provider SMS a utiliser si phone_channel vaut sms pour verifier un nouveau numero. |
sms_mode |
string | body | conditionnel | Mode rest ou http pour EasySend si sms_provider vaut easysend. |
{
"first_name": "Awa",
"last_name": "Traore",
"date_of_birth": "1998-05-12",
"gender": "female",
"residence": "Cocody Riviera",
"city": "Abidjan",
"country": "Cote d'Ivoire",
"photo_url": "https://cdn.ticketnet.ci/users/awa-traore.jpg"
}
{
"success": true,
"message": "Profil mis a jour",
"data": {
"id": "client-id",
"first_name": "Awa",
"last_name": "Traore",
"photo_url": "https://cdn.ticketnet.ci/users/awa-traore.jpg",
"city": "Abidjan",
"country": "Cote d'Ivoire"
}
}
Confirmer par OTP l'ajout ou la modification d'un canal secondaire.
Cet endpoint finalise l'ecriture du nouvel email ou du nouveau telephone seulement apres verification.
Si le nouveau contact telephone a été demandé par WhatsApp, le code suit le canal choisi par le client.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
Authorization |
string | header | oui | Bearer token du client connecte. |
otp |
string | body | oui | Code OTP envoye sur le nouveau contact. |
{
"otp": "123456"
}
{
"success": true,
"message": "Contact verifie et mis a jour",
"data": {
"user": {
"id": "client-id",
"email": "client@ticketnet.com",
"phone": "0701020304"
},
"roles": ["client"],
"permissions": [],
"password_changed": true
}
}
Permettre au client de remplacer son mot de passe actuel ou l'OTP utilisé comme mot de passe par défaut.
À utiliser après connexion, notamment quand l'application invite l'utilisateur à personnaliser son mot de passe.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
Authorization |
string | header | oui | Bearer token du client connecte. |
current_password |
string | body | oui | Mot de passe actuel du client. |
new_password |
string | body | oui | Nouveau mot de passe souhaite. |
{
"current_password": "123456",
"new_password": "MonNouveauMotDePasse123!"
}
{
"success": true,
"message": "Mot de passe modifie",
"data": {
"success": true
}
}
Alimenter une recherche assistée et forcer la sélection d'une ville normalisée.
Sans le query parameter search, l'endpoint retourne la liste paginée de toutes les villes actives.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
Authorization |
string | header | oui | Bearer token du client connecte. |
search |
string | query | non | Texte saisi par le client pour filtrer les villes. |
page |
int | query | non | Numero de page. |
limit |
int | query | non | Nombre maximum de villes a retourner. |
Aucun body requis. Utiliser les query params ou l'identifiant dans l'URL.
{
"success": true,
"message": "Villes disponibles recuperees",
"data": {
"data": [
{
"id": "location-id-bouake",
"name": "Bouake",
"type": "city"
}
],
"meta": {
"total": 1,
"per_page": 10,
"last_page": 1
}
}
}
Récupérer les valeurs backend officielles pour horaires, prix, tri et paliers de rayon.
Ces données servent à alimenter les filtres de recherche de départ afin de garantir que les valeurs envoyées au backend soient conformes.
Le front doit utiliser uniquement les rayons autorisés renvoyés par le backend : 10, 20, 30, 40, 50 et 60 km.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
Authorization |
string | header | oui | Bearer token du client connecte. |
Aucun body requis. Utiliser les query params ou l'identifiant dans l'URL.
{
"success": true,
"message": "Filtres de recherche recuperes",
"data": {
"time_slots": ["morning", "afternoon", "evening"],
"price_ranges": ["economic", "medium", "premium"],
"sort_options": ["nearest", "earliest", "cheapest", "fastest"],
"radius_steps_km": [10, 20, 30, 40, 50, 60]
}
}
Chercher les départs dans un rayon autorisé autour du client pour une destination donnée.
La recherche doit commencer à 10 km. Si aucun résultat n'est trouvé, le front doit demander confirmation au client avant de relancer la recherche avec le palier suivant : 20, puis 30, jusqu'à 60 km maximum.
Les champs comme time_slots, price_ranges, company_ids et sort ne sont pas obligatoires pour une recherche simple.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
Authorization |
string | header | oui | Bearer token du client connecte. |
destination_location_id |
uuid | body | oui | ID de la destination choisie. |
lat |
number | body | oui | Latitude actuelle du client. |
lng |
number | body | oui | Longitude actuelle du client. |
travel_date |
date | body | oui | Date de voyage souhaitee. |
radius_km |
int | body | non | Rayon maximal autorise en kilometres. Valeurs permises : 10, 20, 30, 40, 50, 60. |
time_slots |
string[] | body | non | Tranches horaires officielles du backend. |
price_ranges |
string[] | body | non | Gammes de prix officielles du backend. |
company_ids |
uuid[] | body | non | Liste des compagnies a filtrer. |
sort |
string | body | non | Critere de tri officiel du backend. |
page |
int | body | non | Numero de page. |
limit |
int | body | non | Nombre maximum de departs a retourner. |
{
"destination_location_id": "location-id-bouake",
"lat": 5.348,
"lng": -4.027,
"travel_date": "2026-03-20",
"radius_km": 10,
"time_slots": ["morning"],
"price_ranges": ["economic", "medium"],
"company_ids": ["company-id-utb"],
"sort": "nearest",
"page": 1,
"limit": 10
}
{
"success": true,
"message": "Departs trouves",
"data": {
"data": [
{
"id": "departure-id-abj-bke-1430",
"price": 4000,
"distance_km": 1.8,
"capacity_remaining": 22,
"company": {
"id": "company-id-utb",
"name": "UTB"
}
}
],
"meta": {
"total": 1,
"per_page": 10,
"last_page": 1
},
"search_expansion": {
"current_radius_km": 10,
"next_allowed_radius_km": 20,
"can_expand": true,
"max_radius_km": 60
}
}
}
Afficher la gare physique, la présence compagnie, les contacts, les horaires, le véhicule, les places et le prix.
| Champ | Type | Source | Obligatoire | Description |
|---|---|---|---|---|
Authorization |
string | header | oui | Bearer token du client connecte. |
id |
uuid | path | oui | ID du depart a consulter. |
Aucun body requis. Utiliser les query params ou l'identifiant dans l'URL.
{
"success": true,
"message": "Detail depart recupere",
"data": {
"id": "departure-id-abj-bke-1430",
"price": 4000,
"vehicle_label": "Bus VVIP",
"transport_hub": {
"name": "Gare d'Adjame",
"photo_url": "https://cdn.ticketnet.ci/hubs/adjame.jpg"
},
"company_hub": {
"display_name": "UTB - Adjame",
"phone": "0102030405"
}
}
}