Payments API Reference
Reference complete de l'API de paiements YaniPay. Endpoints, schemas, exemples de code et gestion des webhooks Stripe.
Vue d'ensemble
L'API Payments est construite sur Next.js 16 App Router avec des Route Handlers. Tous les endpoints sont proteges par authentification NextAuth.js et valides par des schemas Zod.
Base URL : https://app.yanipay.com/api (production) ou http://localhost:3000/api (developpement).
9 Endpoints
Paiements, cartes, marchands
Webhooks
HMAC-SHA256 verification
Stripe Checkout
Sessions, PaymentIntents
Authentification
Tous les endpoints (sauf le webhook Stripe) necessitent un token d'authentification NextAuth.js. Le token est envoye automatiquement via les cookies de session ou via le header Authorization.
// Option 1: Cookie session (automatique via NextAuth.js)
const response = await fetch('/api/payments', {
method: 'POST',
credentials: 'include', // Cookies envoyes automatiquement
body: JSON.stringify({ amount: 1099 }),
});
// Option 2: Bearer token (API externe)
const response = await fetch('https://app.yanipay.com/api/payments', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ amount: 1099 }),
});POST /api/payments
Cree un nouveau paiement via Stripe PaymentIntent. Retourne le clientSecret pour confirmer le paiement cote client.
1 // POST /api/payments 2 { 3 "amount": 1099, // Montant en centimes (10.99 EUR) 4 "currency": "eur", // Code devise ISO 4217 5 "description": "Achat premium", 6 "metadata": { 7 "orderId": "ORD-2024-001", 8 "userId": "usr_abc123" 9 } 10 }
1 { 2 "success": true, 3 "data": { 4 "id": "pi_3PQ123abc456def", 5 "clientSecret": "pi_3PQ123abc456def_secret_xyz", 6 "amount": 1099, 7 "currency": "eur", 8 "status": "requires_payment_method", 9 "created": "2024-12-20T10:30:00Z" 10 } 11 }
GET /api/payments/cards
Recupere la liste des cartes enregistrees pour l'utilisateur authentifie. Les numeros de carte sont tokenises et masques.
1 { 2 "success": true, 3 "data": [ 4 { 5 "id": "card_1abc2def3ghi", 6 "brand": "visa", 7 "last4": "4242", 8 "expMonth": 12, 9 "expYear": 2027, 10 "isDefault": true, 11 "status": "active", 12 "type": "virtual" 13 }, 14 { 15 "id": "card_4jkl5mno6pqr", 16 "brand": "mastercard", 17 "last4": "8210", 18 "expMonth": 6, 19 "expYear": 2026, 20 "isDefault": false, 21 "status": "active", 22 "type": "physical" 23 } 24 ] 25 }
POST /api/payments/cards
Ajoute une nouvelle carte de paiement a l'utilisateur. Utilise un Stripe SetupIntent pour tokeniser la carte.
1 // POST /api/payments/cards 2 { 3 "type": "virtual", // "virtual" | "physical" 4 "setDefault": true, // Definir comme carte par defaut 5 "setupIntentId": "seti_1abc2def3ghi" // SetupIntent confirme cote client 6 }
1 { 2 "success": true, 3 "data": { 4 "id": "card_7stu8vwx9yz", 5 "brand": "visa", 6 "last4": "1234", 7 "expMonth": 3, 8 "expYear": 2028, 9 "isDefault": true, 10 "status": "active", 11 "type": "virtual" 12 } 13 }
GET /api/payments/merchant
Recupere les informations de configuration du compte marchand (professionnel). Inclut les donnees Stripe Connect, les taux de commission et les plafonds.
1 { 2 "success": true, 3 "data": { 4 "id": "merch_abc123", 5 "stripeAccountId": "acct_1abc2def3ghi", 6 "businessName": "Ma Boutique", 7 "commissionRate": 1.4, 8 "currency": "eur", 9 "payoutsEnabled": true, 10 "chargesEnabled": true, 11 "monthlyVolume": 45600, 12 "status": "active" 13 } 14 }
POST /api/payments/merchant
Configure ou met a jour le compte marchand. Permet d'activer Stripe Connect et de personnaliser les parametres de paiement.
1 // POST /api/payments/merchant 2 { 3 "businessName": "Ma Boutique Premium", 4 "businessType": "company", 5 "country": "FR", 6 "defaultCurrency": "eur", 7 "statementDescriptor": "YANIPAY*MABOUTIQUE" 8 }
POST /api/payments/validate
Valide un paiement en attente. Utilise pour les paiements qui necessitent une approbation manuelle (montants eleves, nouveau client).
1 // POST /api/payments/validate 2 { 3 "paymentId": "pi_3PQ123abc456def", 4 "action": "approve", // "approve" | "reject" 5 "reason": "Verified by admin" 6 }
1 { 2 "success": true, 3 "data": { 4 "id": "pi_3PQ123abc456def", 5 "status": "succeeded", 6 "validatedAt": "2024-12-20T11:00:00Z", 7 "validatedBy": "admin_usr_xyz" 8 } 9 }
GET /api/payments/transactions
Recupere l'historique des transactions avec pagination, filtres et tri.
GET /api/payments/transactions?page=1&limit=20&status=succeeded&from=2024-01-01&to=2024-12-31&sort=createdAt:desc1 { 2 "success": true, 3 "data": { 4 "transactions": [ 5 { 6 "id": "txn_abc123", 7 "amount": 1099, 8 "currency": "eur", 9 "status": "succeeded", 10 "type": "payment", 11 "description": "Achat premium", 12 "cardLast4": "4242", 13 "createdAt": "2024-12-20T10:30:00Z" 14 } 15 ], 16 "pagination": { 17 "page": 1, 18 "limit": 20, 19 "total": 156, 20 "totalPages": 8 21 } 22 } 23 }
POST /api/payments/stripe
Cree une session Stripe Checkout hebergee. Redirige l'utilisateur vers le formulaire de paiement Stripe securise.
1 // POST /api/payments/stripe 2 { 3 "lineItems": [ 4 { 5 "name": "Abonnement YaniPay Pro", 6 "amount": 2999, 7 "currency": "eur", 8 "quantity": 1 9 } 10 ], 11 "mode": "payment", // "payment" | "subscription" 12 "successUrl": "/dashboard/payments?success=true", 13 "cancelUrl": "/dashboard/payments?canceled=true", 14 "metadata": { 15 "planId": "pro_monthly" 16 } 17 }
1 { 2 "success": true, 3 "data": { 4 "sessionId": "cs_test_abc123def456", 5 "url": "https://checkout.stripe.com/c/pay/cs_test_abc123def456" 6 } 7 }
POST /api/webhooks/stripe
Endpoint de webhook Stripe pour recevoir les evenements asynchrones. Protege par verification de signature HMAC-SHA256.
Securite webhook
STRIPE_WEBHOOK_SECRET. Ne jamais exposer cette cle.1 import { NextResponse } from 'next/server'; 2 import Stripe from 'stripe'; 3 import { prisma } from '@/lib/prisma'; 4 5 const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); 6 const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!; 7 8 export async function POST(request: Request) { 9 const body = await request.text(); 10 const signature = request.headers.get('stripe-signature')!; 11 12 let event: Stripe.Event; 13 try { 14 event = stripe.webhooks.constructEvent(body, signature, webhookSecret); 15 } catch (err) { 16 console.error('Webhook signature verification failed'); 17 return NextResponse.json({ error: 'Invalid signature' }, { status: 401 }); 18 } 19 20 switch (event.type) { 21 case 'payment_intent.succeeded': 22 const paymentIntent = event.data.object as Stripe.PaymentIntent; 23 await prisma.transaction.update({ 24 where: { stripePaymentIntentId: paymentIntent.id }, 25 data: { status: 'SUCCEEDED', completedAt: new Date() }, 26 }); 27 break; 28 29 case 'payment_intent.payment_failed': 30 const failedIntent = event.data.object as Stripe.PaymentIntent; 31 await prisma.transaction.update({ 32 where: { stripePaymentIntentId: failedIntent.id }, 33 data: { status: 'FAILED', failureReason: failedIntent.last_payment_error?.message }, 34 }); 35 break; 36 37 case 'checkout.session.completed': 38 const session = event.data.object as Stripe.Checkout.Session; 39 // Process checkout completion 40 break; 41 42 default: 43 console.log(`Unhandled event type: ${event.type}`); 44 } 45 46 return NextResponse.json({ received: true }); 47 }
Evenements geres
| Evenement | Action |
|---|---|
| payment_intent.succeeded | Marque la transaction comme reussie |
| payment_intent.payment_failed | Marque la transaction comme echouee avec raison |
| checkout.session.completed | Active l'abonnement ou confirme la commande |
| customer.subscription.updated | Met a jour le plan de l'utilisateur |
| customer.subscription.deleted | Desactive l'abonnement |
| charge.refunded | Enregistre le remboursement en base |
Codes d'erreur
Tous les endpoints retournent des erreurs dans un format standardise :
{
"success": false,
"error": {
"code": 422,
"message": "Validation failed",
"details": [
{ "field": "amount", "message": "Must be a positive integer" }
]
}
}| Code | Nom | Description |
|---|---|---|
| 400 | Bad Request | Parametres manquants ou invalides |
| 401 | Unauthorized | Token d'authentification manquant ou expire |
| 402 | Payment Required | Fonds insuffisants ou carte refusee |
| 404 | Not Found | Ressource inexistante (transaction, carte) |
| 409 | Conflict | Transaction deja traitee (idempotence) |
| 422 | Unprocessable | Validation schema echouee (Zod) |
| 429 | Rate Limited | Trop de requetes (100 req/min/IP) |
| 500 | Server Error | Erreur interne ou indisponibilite Stripe |
Idempotence
Idempotency-Keypour eviter les doublons en cas de retry. L'API retourne 409 Conflict si une requete identique a deja ete traitee.