Documentation

Brancher une boutique

Le paiement est hébergé par LuminaPay, sur un sous-domaine de votre boutique. Votre serveur crée une commande, votre client est redirigé, il paie, il revient. Il n'y a rien à installer côté Stripe.

Le principe

  1. Le client clique sur « Commander » dans votre boutique.
  2. Votre serveur appelle POST /api/commande avec le panier, et reçoit une référence ord_….
  3. Vous redirigez le client vers https://checkout.votre-boutique.fr/ord_…. La page de paiement s'affiche à votre marque, encaisse, puis renvoie le client chez vous.
L'appel se fait côté serveur, jamais depuis le navigateur. C'est votre serveur qui fixe les prix, et la clé d'API ne doit apparaître dans aucun code client.

Clés et environnement

À l'ouverture du compte, vous recevez une clé d'API et l'adresse de votre checkout. Rangez les deux dans les variables d'environnement de votre boutique.

.env
LUMINA_API_KEY=<votre clé, à garder secrète>
LUMINA_CHECKOUT_URL=https://checkout.votre-boutique.fr

Le sous-domaine checkout est un simple enregistrement CNAME que vous posez chez votre registrar. On vous donne la valeur exacte pendant l'ouverture, et le certificat est émis automatiquement.

Créer une commande

POST/api/commande

requête
POST https://checkout.votre-boutique.fr/api/commande
Authorization: Bearer $LUMINA_API_KEY
Content-Type: application/json

{
  "reference": "CMD-10428",
  "devise": "eur",
  "articles": [
    {
      "nom": "Nom du produit",
      "prix": 2490,
      "quantite": 2,
      "variante": "Taille M",
      "image": "https://votre-boutique.fr/photo.jpg"
    }
  ],
  "livraisons": [
    { "id": "offerte", "nom": "Livraison offerte", "delai": "3 à 5 jours", "prix": 0 }
  ]
}

Le même appel depuis un serveur Node :

node
// Route serveur de votre boutique, appelée au clic sur « Commander »
const r = await fetch(process.env.LUMINA_CHECKOUT_URL + "/api/commande", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.LUMINA_API_KEY,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ reference, devise: "eur", articles, livraisons })
});

if (!r.ok) throw new Error((await r.json()).error);
const { url } = await r.json();

// Il ne reste qu'à rediriger le client
res.redirect(303, url);

Champs du panier

ChampTypeÀ savoir
referencetexteVotre numéro de commande. Il est repris dans la description du paiement, ce qui permet le rapprochement des deux côtés. Fortement conseillé.
devisetexteCode ISO en minuscules, eur par exemple.
articleslisteNe peut pas être vide. Une trentaine de lignes au maximum.
articles[].prixentierPrix unitaire en centimes. 24,90 € s'écrit 2490.
articles[].quantiteentierRamenée entre 1 et 999.
articles[].variantetexteFacultatif. Affiché sous le nom du produit.
articles[].imageURLFacultatif. Vignette affichée dans le récapitulatif.
livraisonslisteLes options proposées au client. La première est présélectionnée. Si le champ est absent, une livraison standard à 0 est appliquée.
livraisons[].prixentierEn centimes, comme les articles.

Le total doit atteindre le minimum accepté par Stripe pour la devise, soit 1 € en euros.

Réponse

Une commande créée répond 201 :

201 Created
{
  "reference": "ord_3RxAbC…",
  "url": "https://checkout.votre-boutique.fr/ord_3RxAbC…",
  "total": 4980,
  "devise": "eur"
}

Redirigez le client vers url. Il n'y a rien d'autre à construire : la page gère la saisie de la carte, l'authentification forte, les portefeuilles et l'écran de confirmation.

Codes d'erreur

CodeSignificationQuoi faire
400Commande invalideLe message précise le champ en cause : panier vide, montant sous le minimum, panier trop volumineux.
401Clé d'API invalideVérifier l'en-tête Authorization et la variable d'environnement.
404Domaine non déclaréLe sous-domaine de checkout n'est pas encore rattaché à votre compte. Nous écrire.
405Méthode non autoriséeSeuls POST et GET sont acceptés sur cette route.
503Plateforme indisponibleRéessayer après quelques secondes. Si ça dure, nous écrire.

Toutes les erreurs ont la même forme : { "error": "message lisible" }.

Retour sur la boutique

Une fois le paiement accepté, l'écran de confirmation propose au client de revenir chez vous. Il arrive sur la racine de votre domaine, avec la référence en paramètre :

redirection
https://votre-boutique.fr/?commande=ord_3RxAbC…

C'est le seul signal que votre boutique reçoit dans le navigateur. Servez-vous-en pour vider le panier, et seulement là : un client qui abandonne le paiement doit retrouver son panier intact.

Ce paramètre n'est pas une preuve de paiement. Il est visible dans l'URL, donc devinable. Avant d'afficher une commande comme payée, relisez-la avec l'appel ci-dessous.

Relire une commande

GET/api/commande?ref=ord_…

Renvoie le panier, les options de livraison, les totaux et l'état du paiement. Aucune clé n'est nécessaire, la référence étant déjà imprévisible.

200 OK
{
  "etat": "succeeded",
  "dejaPayee": true,
  "reference": "CMD-10428",
  "articles": [ { "nom": "Nom du produit", "prix": 2490, "quantite": 2 } ],
  "livraisons": [ { "id": "offerte", "nom": "Livraison offerte", "prix": 0 } ],
  "livraisonId": "offerte",
  "sousTotal": 4980,
  "fraisLivraison": 0,
  "total": 4980,
  "devise": "eur"
}
etatCe que ça veut dire
requires_payment_methodLa commande existe, le client n'a pas encore payé.
processingPaiement en cours de traitement par la banque. dejaPayee vaut déjà true.
succeededPaiement accepté. Vous pouvez préparer la commande.
canceledCommande annulée, aucun débit.

Devises et montants

À ne pas faire

Recette avant mise en production

  1. Passer une commande d'un article à 1 €, avec une vraie carte.
  2. Vérifier que le paiement apparaît sur votre compte Stripe.
  3. Vérifier que votre référence est visible dans la description du paiement.
  4. Rembourser depuis votre tableau de bord Stripe, et vérifier que la commission est rendue.

Une question sur l'intégration ? contact@lumina-pay.com, réponse sous 24 h ouvrées.