API Services
Architecture modulaire des services API de l'application mobile YaniPay. Chaque service encapsule un domaine métier spécifique.
Overview
L'application mobile utilise une architecture de services modulaire où chaque domaine métier est encapsulé dans un service dédié. Tous les services utilisent un client API commun avec gestion automatique des tokens, retry et logging.
UserService
WalletService
CardService
PaymentService
TransactionService
KYCService
LoyaltyService
NotificationService
API Client
Le client API centralisé gère l'authentification, le retry automatique et le logging. Il est basé sur Axios avec des intercepteurs personnalisés.
import axios, { AxiosInstance } from 'axios';
import * as SecureStore from 'expo-secure-store';
const BASE_URL = 'https://api.yanipay.com/v1/mobile';
class ApiClient {
private client: AxiosInstance;
constructor() {
this.client = axios.create({
baseURL: BASE_URL,
timeout: 30000,
headers: {
'Content-Type': 'application/json',
},
});
// Request interceptor - Add auth token
this.client.interceptors.request.use(async (config) => {
const token = await SecureStore.getItemAsync('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Response interceptor - Handle 401, retry logic
this.client.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401) {
// Token expired - attempt refresh
await this.refreshToken();
return this.client.request(error.config);
}
throw error;
}
);
}
// Retry with exponential backoff
async requestWithRetry<T>(fn: () => Promise<T>, retries = 3): Promise<T> {
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
}
}
throw new Error('Max retries reached');
}
get = <T>(url: string) => this.client.get<T>(url);
post = <T>(url: string, data?: unknown) => this.client.post<T>(url, data);
put = <T>(url: string, data?: unknown) => this.client.put<T>(url, data);
delete = <T>(url: string) => this.client.delete<T>(url);
}
export const api = new ApiClient();User Service
Gestion du profil utilisateur, authentification à deux facteurs et gestion des appareils.
import { api } from './api';
import { User, UserProfile, Device } from '@/types/models';
class UserService {
// Profile
async getProfile(): Promise<UserProfile> {
const { data } = await api.get<UserProfile>('/user/profile');
return data;
}
async updateProfile(updates: Partial<UserProfile>): Promise<UserProfile> {
const { data } = await api.put<UserProfile>('/user/profile', updates);
return data;
}
async uploadAvatar(imageUri: string): Promise<{ avatarUrl: string }> {
const formData = new FormData();
formData.append('avatar', {
uri: imageUri,
type: 'image/jpeg',
name: 'avatar.jpg',
} as any);
const { data } = await api.post('/user/avatar', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
return data;
}
// 2FA
async enable2FA(): Promise<{ secret: string; qrCode: string }> {
const { data } = await api.post('/user/2fa/enable');
return data;
}
async verify2FA(code: string): Promise<{ success: boolean }> {
const { data } = await api.post('/user/2fa/verify', { code });
return data;
}
// Devices
async getDevices(): Promise<Device[]> {
const { data } = await api.get<Device[]>('/user/devices');
return data;
}
async removeDevice(deviceId: string): Promise<void> {
await api.delete(`/user/devices/${deviceId}`);
}
}
export const userService = new UserService();Wallet Service
Gestion du portefeuille, balance, top-up et transferts bancaires.
import { api } from './api';
import { Wallet, BankAccount, TopUpRequest } from '@/types/models';
class WalletService {
// Balance
async getWallet(): Promise<Wallet> {
const { data } = await api.get<Wallet>('/wallet');
return data;
}
async getBalance(): Promise<{ balance: number; currency: string }> {
const { data } = await api.get('/wallet/balance');
return data;
}
// Top-up
async createTopUp(request: TopUpRequest): Promise<{
clientSecret: string;
paymentIntentId: string;
}> {
const { data } = await api.post('/wallet/topup', request);
return data;
}
async confirmTopUp(paymentIntentId: string): Promise<{ success: boolean }> {
const { data } = await api.post('/wallet/topup/confirm', { paymentIntentId });
return data;
}
// Bank accounts
async getBankAccounts(): Promise<BankAccount[]> {
const { data } = await api.get<BankAccount[]>('/wallet/bank-accounts');
return data;
}
async addBankAccount(iban: string, bic: string): Promise<BankAccount> {
const { data } = await api.post<BankAccount>('/wallet/bank-accounts', { iban, bic });
return data;
}
async withdraw(amount: number, bankAccountId: string): Promise<{ transactionId: string }> {
const { data } = await api.post('/wallet/withdraw', { amount, bankAccountId });
return data;
}
// Auto top-up
async getAutoTopUpSettings(): Promise<{
enabled: boolean;
threshold: number;
amount: number;
}> {
const { data } = await api.get('/wallet/auto-topup');
return data;
}
async updateAutoTopUp(settings: {
enabled: boolean;
threshold: number;
amount: number;
}): Promise<void> {
await api.put('/wallet/auto-topup', settings);
}
}
export const walletService = new WalletService();Card Service
Gestion des cartes virtuelles et physiques, limites et intégration Apple/Google Pay.
import { api } from './api';
import { Card, CardSettings, CardTransaction } from '@/types/models';
class CardService {
// Cards CRUD
async getCards(): Promise<Card[]> {
const { data } = await api.get<Card[]>('/cards');
return data;
}
async getCard(cardId: string): Promise<Card> {
const { data } = await api.get<Card>(`/cards/${cardId}`);
return data;
}
async createVirtualCard(): Promise<Card> {
const { data } = await api.post<Card>('/cards/virtual');
return data;
}
async orderPhysicalCard(address: {
street: string;
city: string;
postalCode: string;
country: string;
}): Promise<Card> {
const { data } = await api.post<Card>('/cards/physical', address);
return data;
}
// Card controls
async freezeCard(cardId: string): Promise<void> {
await api.post(`/cards/${cardId}/freeze`);
}
async unfreezeCard(cardId: string): Promise<void> {
await api.post(`/cards/${cardId}/unfreeze`);
}
async updateLimits(cardId: string, limits: {
daily?: number;
monthly?: number;
perTransaction?: number;
}): Promise<CardSettings> {
const { data } = await api.put<CardSettings>(`/cards/${cardId}/limits`, limits);
return data;
}
// PIN (requires biometric)
async getPin(cardId: string): Promise<{ pin: string }> {
const { data } = await api.get(`/cards/${cardId}/pin`);
return data;
}
// Apple/Google Wallet
async addToAppleWallet(cardId: string): Promise<{ passUrl: string }> {
const { data } = await api.post(`/cards/${cardId}/apple-wallet`);
return data;
}
async addToGooglePay(cardId: string): Promise<{ token: string }> {
const { data } = await api.post(`/cards/${cardId}/google-pay`);
return data;
}
// Transactions
async getCardTransactions(cardId: string, params?: {
limit?: number;
offset?: number;
}): Promise<CardTransaction[]> {
const { data } = await api.get<CardTransaction[]>(
`/cards/${cardId}/transactions`,
{ params }
);
return data;
}
}
export const cardService = new CardService();Payment Service
Paiements QR, demandes de paiement et paiements programmés.
import { api } from './api';
import { PaymentRequest, ScheduledPayment } from '@/types/models';
class PaymentService {
// P2P Transfers
async sendMoney(recipientId: string, amount: number, note?: string): Promise<{
transactionId: string;
status: string;
}> {
const { data } = await api.post('/payments/send', {
recipientId,
amount,
note,
});
return data;
}
// QR Payments
async generateQRCode(amount?: number): Promise<{ qrData: string; expiresAt: string }> {
const { data } = await api.post('/payments/qr/generate', { amount });
return data;
}
async processQRPayment(qrData: string): Promise<{
transactionId: string;
amount: number;
merchant: string;
}> {
const { data } = await api.post('/payments/qr/process', { qrData });
return data;
}
// Payment Requests
async createPaymentRequest(request: {
amount: number;
recipientId: string;
description?: string;
expiresAt?: string;
}): Promise<PaymentRequest> {
const { data } = await api.post<PaymentRequest>('/payments/requests', request);
return data;
}
async getPaymentRequests(): Promise<PaymentRequest[]> {
const { data } = await api.get<PaymentRequest[]>('/payments/requests');
return data;
}
async respondToRequest(requestId: string, accept: boolean): Promise<void> {
await api.post(`/payments/requests/${requestId}/respond`, { accept });
}
// Scheduled Payments
async createScheduledPayment(payment: {
recipientId: string;
amount: number;
frequency: 'daily' | 'weekly' | 'monthly';
startDate: string;
endDate?: string;
}): Promise<ScheduledPayment> {
const { data } = await api.post<ScheduledPayment>('/payments/scheduled', payment);
return data;
}
async getScheduledPayments(): Promise<ScheduledPayment[]> {
const { data } = await api.get<ScheduledPayment[]>('/payments/scheduled');
return data;
}
async cancelScheduledPayment(paymentId: string): Promise<void> {
await api.delete(`/payments/scheduled/${paymentId}`);
}
}
export const paymentService = new PaymentService();KYC Service
Vérification d'identité avec upload de documents et intégration Onfido.
import { api } from './api';
import { KycStatus, KycDocument } from '@/types/models';
class KycService {
// Status
async getKycStatus(): Promise<KycStatus> {
const { data } = await api.get<KycStatus>('/kyc/status');
return data;
}
// Documents
async uploadDocument(
type: 'passport' | 'id_card' | 'driving_license' | 'address_proof',
imageUri: string
): Promise<KycDocument> {
const formData = new FormData();
formData.append('type', type);
formData.append('document', {
uri: imageUri,
type: 'image/jpeg',
name: `${type}.jpg`,
} as any);
const { data } = await api.post<KycDocument>('/kyc/documents', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
return data;
}
async getDocuments(): Promise<KycDocument[]> {
const { data } = await api.get<KycDocument[]>('/kyc/documents');
return data;
}
// Onfido Integration
async startOnfidoVerification(): Promise<{ sdkToken: string; workflowRunId: string }> {
const { data } = await api.post('/kyc/onfido/start');
return data;
}
async completeOnfidoVerification(workflowRunId: string): Promise<KycStatus> {
const { data } = await api.post<KycStatus>('/kyc/onfido/complete', { workflowRunId });
return data;
}
// Selfie
async uploadSelfie(imageUri: string): Promise<{ verified: boolean }> {
const formData = new FormData();
formData.append('selfie', {
uri: imageUri,
type: 'image/jpeg',
name: 'selfie.jpg',
} as any);
const { data } = await api.post('/kyc/selfie', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
return data;
}
}
export const kycService = new KycService();Loyalty Service
Programme de fidélité, points, cashback et récompenses.
import { api } from './api';
import { LoyaltyProgram, Reward, CashbackTransaction } from '@/types/models';
class LoyaltyService {
// Program status
async getLoyaltyStatus(): Promise<LoyaltyProgram> {
const { data } = await api.get<LoyaltyProgram>('/loyalty/status');
return data;
}
async getPoints(): Promise<{ points: number; tier: string; nextTierPoints: number }> {
const { data } = await api.get('/loyalty/points');
return data;
}
// Cashback
async getCashbackHistory(params?: {
limit?: number;
offset?: number;
}): Promise<CashbackTransaction[]> {
const { data } = await api.get<CashbackTransaction[]>('/loyalty/cashback', { params });
return data;
}
async getCashbackRate(): Promise<{
rate: number;
bonusCategories: { category: string; rate: number }[];
}> {
const { data } = await api.get('/loyalty/cashback/rate');
return data;
}
// Rewards
async getAvailableRewards(): Promise<Reward[]> {
const { data } = await api.get<Reward[]>('/loyalty/rewards');
return data;
}
async redeemReward(rewardId: string): Promise<{ success: boolean; code?: string }> {
const { data } = await api.post(`/loyalty/rewards/${rewardId}/redeem`);
return data;
}
// Challenges
async getChallenges(): Promise<{
id: string;
title: string;
description: string;
progress: number;
target: number;
reward: number;
expiresAt: string;
}[]> {
const { data } = await api.get('/loyalty/challenges');
return data;
}
}
export const loyaltyService = new LoyaltyService();