Documentation
Documentation complète pour l'intégration Flutter
Toutes les requêtes API doivent inclure un token Bearer dans l'en-tête Authorization :
final response = await http.get(
Uri.parse('${baseUrl}/api/endpoint'),
headers: {
'Authorization': 'Bearer $token',
'Accept': 'application/json',
},
);
Endpoint: /api/register
Corps de la requête:
{
"name": "John Doe",
"email": "john@example.com",
"password": "password123",
"password_confirmation": "password123",
"birth_date": "1990-01-01", // Optionnel
"phone": "+237600000000", // Optionnel
"address": "Yaoundé, Cameroun", // Optionnel
"speciality": "Cardiologie", // Optionnel
"medical_order_number": "12345" // Optionnel
}
Exemple de réponse:
{
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"phone": "+237600000000",
"address": "Yaoundé, Cameroun",
"birth_date": "1990-01-01",
"speciality": "Cardiologie",
"medical_order_number": "12345",
"email_verified_at": null,
"created_at": "2024-02-14T12:00:00.000000Z",
"updated_at": "2024-02-14T12:00:00.000000Z"
},
"token": "votre_token_d_acces"
}
Exemple d'intégration Flutter:
Future register({
required String name,
required String email,
required String password,
required String passwordConfirmation,
String? birthDate,
String? phone,
String? address,
String? speciality,
String? medicalOrderNumber,
}) async {
final response = await http.post(
Uri.parse('${baseUrl}/api/register'),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: jsonEncode({
'name': name,
'email': email,
'password': password,
'password_confirmation': passwordConfirmation,
if (birthDate != null) 'birth_date': birthDate,
if (phone != null) 'phone': phone,
if (address != null) 'address': address,
if (speciality != null) 'speciality': speciality,
if (medicalOrderNumber != null) 'medical_order_number': medicalOrderNumber,
}),
);
if (response.statusCode == 201) {
final data = jsonDecode(response.body);
await storage.write(key: 'token', value: data['token']);
return User.fromJson(data['user']);
}
throw Exception(jsonDecode(response.body)['message']);
}
class User {
final int id;
final String name;
final String email;
final String? phone;
final String? address;
final String? speciality;
final String? medicalOrderNumber;
final DateTime? birthDate;
final DateTime? emailVerifiedAt;
final DateTime createdAt;
final DateTime updatedAt;
User({
required this.id,
required this.name,
required this.email,
this.phone,
this.address,
this.speciality,
this.medicalOrderNumber,
this.birthDate,
this.emailVerifiedAt,
required this.createdAt,
required this.updatedAt,
});
factory User.fromJson(Map json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
phone: json['phone'],
address: json['address'],
speciality: json['speciality'],
medicalOrderNumber: json['medical_order_number'],
birthDate: json['birth_date'] != null
? DateTime.parse(json['birth_date'])
: null,
emailVerifiedAt: json['email_verified_at'] != null
? DateTime.parse(json['email_verified_at'])
: null,
createdAt: DateTime.parse(json['created_at']),
updatedAt: DateTime.parse(json['updated_at']),
);
}
Map toJson() {
return {
'id': id,
'name': name,
'email': email,
'phone': phone,
'address': address,
'speciality': speciality,
'medical_order_number': medicalOrderNumber,
'birth_date': birthDate?.toIso8601String(),
'email_verified_at': emailVerifiedAt?.toIso8601String(),
'created_at': createdAt.toIso8601String(),
'updated_at': updatedAt.toIso8601String(),
};
}
}
class UserProvider extends ChangeNotifier {
User? _user;
final storage = const FlutterSecureStorage();
User? get user => _user;
Future loadUser() async {
final token = await storage.read(key: 'token');
if (token == null) return;
try {
final response = await http.get(
Uri.parse('${baseUrl}/api/user'),
headers: {
'Authorization': 'Bearer $token',
'Accept': 'application/json',
},
);
if (response.statusCode == 200) {
_user = User.fromJson(jsonDecode(response.body));
notifyListeners();
}
} catch (e) {
await storage.delete(key: 'token');
}
}
Future updateProfile({
String? name,
String? phone,
String? address,
String? birthDate,
String? speciality,
String? medicalOrderNumber,
}) async {
final token = await storage.read(key: 'token');
if (token == null) return;
final response = await http.put(
Uri.parse('${baseUrl}/api/user/profile'),
headers: {
'Authorization': 'Bearer $token',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: jsonEncode({
if (name != null) 'name': name,
if (phone != null) 'phone': phone,
if (address != null) 'address': address,
if (birthDate != null) 'birth_date': birthDate,
if (speciality != null) 'speciality': speciality,
if (medicalOrderNumber != null) 'medical_order_number': medicalOrderNumber,
}),
);
if (response.statusCode == 200) {
_user = User.fromJson(jsonDecode(response.body));
notifyListeners();
} else {
throw Exception('Échec de la mise à jour du profil');
}
}
}
Endpoint: /api/login
Corps de la requête:
{
"email": "john@example.com",
"password": "password123"
}
Exemple d'intégration Flutter:
Future login({
required String email,
required String password,
}) async {
final response = await http.post(
Uri.parse('${baseUrl}/api/login'),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: jsonEncode({
'email': email,
'password': password,
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
// Sauvegarder le token
await storage.write(key: 'token', value: data['token']);
return User.fromJson(data['user']);
}
throw Exception(jsonDecode(response.body)['message']);
}
Endpoint: /api/forgot-password
Corps de la requête:
{
"email": "john@example.com"
}
Exemple d'intégration Flutter:
Future forgotPassword({
required String email,
}) async {
final response = await http.post(
Uri.parse('${baseUrl}/api/forgot-password'),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: jsonEncode({
'email': email,
}),
);
if (response.statusCode != 200) {
throw Exception(jsonDecode(response.body)['message']);
}
}
Endpoint: /api/reset-password
Corps de la requête:
{
"token": "token_reçu_par_email",
"email": "john@example.com",
"password": "nouveau_mot_de_passe",
"password_confirmation": "nouveau_mot_de_passe"
}
Exemple d'intégration Flutter:
Future resetPassword({
required String token,
required String email,
required String password,
required String passwordConfirmation,
}) async {
final response = await http.post(
Uri.parse('${baseUrl}/api/reset-password'),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: jsonEncode({
'token': token,
'email': email,
'password': password,
'password_confirmation': passwordConfirmation,
}),
);
if (response.statusCode != 200) {
throw Exception(jsonDecode(response.body)['message']);
}
}
Endpoint: /api/logout
Exemple d'intégration Flutter:
Future logout() async {
final token = await storage.read(key: 'token');
final response = await http.post(
Uri.parse('${baseUrl}/api/logout'),
headers: {
'Authorization': 'Bearer $token',
'Accept': 'application/json',
},
);
if (response.statusCode == 200) {
// Supprimer le token stocké
await storage.delete(key: 'token');
return;
}
throw Exception('Erreur lors de la déconnexion');
}
URL de redirection: /api/auth/google
URL de callback: /api/auth/google/callback
Future signInWithGoogle() async {
final url = Uri.parse('${baseUrl}/api/auth/google');
// Utiliser url_launcher ou webview pour la redirection
if (await canLaunch(url.toString())) {
await launch(url.toString());
} else {
throw Exception('Impossible d\'ouvrir l\'URL d\'authentification');
}
}
URL de redirection: /api/auth/facebook
URL de callback: /api/auth/facebook/callback
Future signInWithFacebook() async {
final url = Uri.parse('${baseUrl}/api/auth/facebook');
if (await canLaunch(url.toString())) {
await launch(url.toString());
} else {
throw Exception('Impossible d\'ouvrir l\'URL d\'authentification');
}
}
URL de redirection: /api/auth/github
URL de callback: /api/auth/github/callback
Future signInWithGithub() async {
final url = Uri.parse('${baseUrl}/api/auth/github');
if (await canLaunch(url.toString())) {
await launch(url.toString());
} else {
throw Exception('Impossible d\'ouvrir l\'URL d\'authentification');
}
}
Endpoint: /api/user/profile
Paramètres: Aucun
Exemple de réponse:
{
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"avatar": "1_1743615420.jpg",
"phone": "+237600000000",
"address": "Yaoundé, Cameroun",
"birth_date": "1990-01-01",
"speciality": "Cardiologie",
"medical_order_number": "12345",
"has_used_trial": true,
"email_verified_at": "2024-02-14T12:00:00.000000Z",
"created_at": "2024-02-14T12:00:00.000000Z",
"updated_at": "2024-02-14T12:00:00.000000Z"
},
"message": "Profil récupéré avec succès"
}
Endpoint: /api/user/profile
Corps de la requête (multipart/form-data):
{
"name": "John Doe", // Optionnel
"birth_date": "1990-01-01", // Optionnel
"phone": "+237600000000", // Optionnel
"address": "Yaoundé, Cameroun", // Optionnel
"speciality": "Cardiologie", // Optionnel
"medical_order_number": "12345", // Optionnel
"avatar": [FICHIER IMAGE] // Optionnel, max 2MB
}
Exemple de réponse:
{
"message": "Profil mis à jour avec succès",
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"avatar": "1_1743615420.jpg",
"phone": "+237600000000",
"address": "Yaoundé, Cameroun",
"birth_date": "1990-01-01",
"speciality": "Cardiologie",
"medical_order_number": "12345",
"has_used_trial": true,
"email_verified_at": "2024-02-14T12:00:00.000000Z",
"created_at": "2024-02-14T12:00:00.000000Z",
"updated_at": "2024-02-14T12:00:00.000000Z"
}
}
Endpoint: /api/user/profile/email
Corps de la requête:
{
"email": "nouveau@example.com",
"current_password": "mot_de_passe_actuel"
}
Exemple de réponse:
{
"message": "Adresse email mise à jour avec succès",
"user": {
"id": 1,
"name": "John Doe",
"email": "nouveau@example.com",
"email_verified_at": null,
// autres attributs...
}
}
Endpoint: /api/user/profile/password
Corps de la requête:
{
"current_password": "mot_de_passe_actuel",
"password": "nouveau_mot_de_passe",
"password_confirmation": "nouveau_mot_de_passe"
}
Exemple de réponse:
{
"message": "Mot de passe mis à jour avec succès"
}
Endpoint: /api/user/profile/avatar
Paramètres: Aucun
Exemple de réponse:
{
"message": "Avatar supprimé avec succès",
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"avatar": null,
// autres attributs...
}
}
Endpoint: /api/subscriptions/current
Paramètres: Aucun
Exemple de réponse (avec abonnement):
{
"message": "Abonnement actif récupéré",
"subscription": {
"id": 3,
"name": "Abonnement Premium",
"plan_id": 2,
"plan_name": "Premium",
"is_trial": false,
"has_used_trial": true,
"starts_at": "2024-04-01T00:00:00.000000Z",
"ends_at": "2024-05-01T00:00:00.000000Z",
"remaining_days": 29,
"plan_price": 10000,
"plan_interval": 30
},
"has_active_subscription": true
}
Exemple de réponse (sans abonnement):
{
"message": "Aucun abonnement actif",
"subscription": null,
"has_active_subscription": false
}
Endpoint: /api/subscriptions/trial
Corps de la requête:
{
"plan_id": 2
}
Notes:
Exemple de réponse (succès):
{
"message": "Période d'essai activée avec succès",
"status": "success",
"data": {
"subscription": {
"id": 5,
"subscriber_type": "App\\Models\\User",
"subscriber_id": 2,
"plan_id": 2,
"name": "Trial Subscription",
"slug": "trial-subscription",
"description": null,
"is_trial": true,
"trial_ends_at": "2024-04-15T00:00:00.000000Z",
"starts_at": "2024-04-02T00:00:00.000000Z",
"ends_at": "2024-04-15T00:00:00.000000Z",
"updated_at": "2024-04-02T17:05:19.000000Z",
"created_at": "2024-04-02T17:05:19.000000Z"
},
"trial_ends_at": "2024-04-15 00:00:00",
"plan": {
"id": 2,
"name": {
"en": "Premium"
},
"description": {
"en": "Plan premium avec toutes les fonctionnalités"
},
"price": 10000,
"interval": 30,
"trial_period": 14,
"created_at": "2024-02-11T09:59:31.000000Z",
"updated_at": "2024-02-11T09:59:31.000000Z"
}
}
}
Exemple de réponse (déjà utilisé un essai):
{
"message": "Vous avez déjà utilisé votre période d'essai gratuit. Vous ne pouvez plus bénéficier d'essai sur aucun forfait.",
"status": "error"
}
Endpoint: /api/subscriptions/subscribe
Corps de la requête:
{
"plan_id": 2
}
Notes:
Exemple de réponse (succès):
{
"authorization_url": "https://pay.notchpay.co/rUZp8lTuQuJQyxpb0QzntE3eRPaV6jjgXqU9HjOeb9Sg7riFPCTZx9wmQuleQEHIVVba8pekz4uMIy0EMY0prJqljdHwmYPRlflXIDdrBMYPeNYpAE2ei34XMKzDoAHwBMYesQXRphAYo6cym5gAT18trWSgpl6N84QZ4jyBKva2aNkdvypUgvFnWr9Qfbl",
"reference": "SUB-2-1743613520",
"message": "Paiement initialisé avec succès"
}
Endpoint: /api/subscriptions/unsubscribe
Corps de la requête: Aucun
Exemple de réponse (succès):
{
"message": "Abonnement résilié avec succès."
}
Endpoint: /api/subscriptions/all
Paramètres: Aucun
Exemple de réponse:
{
"subscriptions": [
{
"id": 2,
"subscriber_type": "App\\Models\\User",
"subscriber_id": 2,
"plan_id": 1,
"name": "Trial Subscription",
"slug": "trial-subscription",
"is_trial": true,
"trial_ends_at": "2024-03-15T00:00:00.000000Z",
"starts_at": "2024-03-01T00:00:00.000000Z",
"ends_at": "2024-03-15T00:00:00.000000Z",
"is_active": false,
"is_in_trial": false,
"plan": {
"id": 1,
"name": {
"en": "Basic"
},
"price": 5000
// autres attributs...
}
},
{
"id": 5,
"subscriber_type": "App\\Models\\User",
"subscriber_id": 2,
"plan_id": 2,
"name": "Abonnement Premium",
"slug": "abonnement-premium",
"is_trial": false,
"trial_ends_at": null,
"starts_at": "2024-04-02T00:00:00.000000Z",
"ends_at": "2024-05-02T00:00:00.000000Z",
"is_active": true,
"is_in_trial": false,
"plan": {
"id": 2,
"name": {
"en": "Premium"
},
"price": 10000
// autres attributs...
}
}
]
}
Endpoint: /api/admin/users
Paramètres:
Future
Exemple de réponse:
{
"data": [
{
"id": "1",
"name": "John Doe",
"email": "john@example.com",
"subscription": {
"plan": "Business",
"isActive": true,
"startDate": "2024-02-01T00:00:00.000Z",
"endDate": "2024-03-01T00:00:00.000Z"
},
"status": "active",
"createdAt": "2024-01-01T00:00:00.000Z",
"phone": "+237600000000",
"address": "Yaoundé, Cameroun",
"speciality": "Cardiologie",
"medical_order_number": "12345"
}
],
"total": 50,
"currentPage": 1,
"perPage": 10,
"lastPage": 5
}
Endpoint: /api/admin/users/{id}
Future
Exemple de réponse:
{
"user": {
"id": "1",
"name": "John Doe",
"email": "john@example.com",
"phone": "+237600000000",
"address": "Yaoundé, Cameroun",
"birth_date": "1990-01-01",
"speciality": "Cardiologie",
"medical_order_number": "12345",
"createdAt": "2024-01-01T00:00:00.000Z",
"status": "active",
"currentSubscription": {
"plan": "Business",
"isActive": true,
"startDate": "2024-02-01T00:00:00.000Z",
"endDate": "2024-03-01T00:00:00.000Z"
},
"subscriptionHistory": [
{
"id": "1",
"plan": "Business",
"startDate": "2024-02-01T00:00:00.000Z",
"endDate": "2024-03-01T00:00:00.000Z",
"isActive": true,
"price": 49.99
}
]
}
}
class AdminUser {
final String id;
final String name;
final String email;
final String? phone;
final String? address;
final String? speciality;
final String? medicalOrderNumber;
final String status;
final DateTime createdAt;
final UserSubscription? currentSubscription;
final List subscriptionHistory;
AdminUser({
required this.id,
required this.name,
required this.email,
this.phone,
this.address,
this.speciality,
this.medicalOrderNumber,
required this.status,
required this.createdAt,
this.currentSubscription,
required this.subscriptionHistory,
});
factory AdminUser.fromJson(Map json) {
return AdminUser(
id: json['id'].toString(),
name: json['name'],
email: json['email'],
phone: json['phone'],
address: json['address'],
speciality: json['speciality'],
medicalOrderNumber: json['medical_order_number'],
status: json['status'],
createdAt: DateTime.parse(json['createdAt']),
currentSubscription: json['currentSubscription'] != null
? UserSubscription.fromJson(json['currentSubscription'])
: null,
subscriptionHistory: (json['subscriptionHistory'] as List)
.map((item) => SubscriptionHistory.fromJson(item))
.toList(),
);
}
}
class UserSubscription {
final String plan;
final bool isActive;
final DateTime startDate;
final DateTime endDate;
UserSubscription({
required this.plan,
required this.isActive,
required this.startDate,
required this.endDate,
});
factory UserSubscription.fromJson(Map json) {
return UserSubscription(
plan: json['plan'],
isActive: json['isActive'],
startDate: DateTime.parse(json['startDate']),
endDate: DateTime.parse(json['endDate']),
);
}
}
class SubscriptionHistory {
final String id;
final String plan;
final DateTime startDate;
final DateTime endDate;
final bool isActive;
final double price;
SubscriptionHistory({
required this.id,
required this.plan,
required this.startDate,
required this.endDate,
required this.isActive,
required this.price,
});
factory SubscriptionHistory.fromJson(Map json) {
return SubscriptionHistory(
id: json['id'].toString(),
plan: json['plan'],
startDate: DateTime.parse(json['startDate']),
endDate: DateTime.parse(json['endDate']),
isActive: json['isActive'],
price: double.parse(json['price'].toString()),
);
}
}