Parcourir la documentation
Démarrage rapide
L’API est disponible pour les commerces actifs ayant un programme de fidélité à tampons ou à points.
Dans Tableau marchand → Paramètres → API checkout.
Après paiement, envoyez le montant de fidélité et l’identifiant unique de la commande.
Affichez-le sur la page de confirmation ou l’écran client, ou imprimez-le sur le ticket de caisse.
Authentification
Transmettez la clé avec le schéma Bearer dans l’en-tête Authorization. Les clés dans l’URL ou le corps sont refusées.
Authorization: Bearer sourdi_live_KEY_ID.API_SECRET Content-Type: application/json
Une seule clé peut être active. Après révocation, elle cesse de fonctionner immédiatement et une nouvelle clé peut être créée.
Checkout d’une carte à tampons
À la confirmation du paiement, votre serveur demande un stamp_code signé. Le QR est lié à votre commerce, expire après 10 minutes par défaut et ne peut être validé qu’une fois.
/api/v1/checkout/stampsRequête serveur
curl --request POST "/api/v1/checkout/stamps" \
--header "Authorization: Bearer $SOURDI_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"stamps": 2,
"transaction_id": "order-2026-000184"
}'
| Champ | Type | Description |
|---|---|---|
stamps requis | integer | Nombre de tampons à collecter : 1, 2 ou 3. |
transaction_id requis | string | Identifiant stable et unique de la commande, de 8 à 128 caractères. |
Réponse — HTTP 201
{
"status": true,
"data": {
"reward_type": "stamps",
"stamps": 2,
"stamp_code": "sourdi_checkout_v1.…",
"transaction_id": "order-2026-000184",
"expires_at": "2026-08-14T12:10:00.000Z",
"qr": {
"data": "sourdi_checkout_v1.…",
"image_data_url": "data:image/png;base64,iVBOR…"
}
},
"idempotent_replay": false
}
Checkout d’une carte à points
Pour une carte à points, le checkout retourne un QR adapté au solde de crédits. Le client le scanne avec la même fonctionnalité de scan de l’application ; les points sont ajoutés après validation serveur.
/api/v1/checkout/pointsRequête serveur
curl --request POST "/api/v1/checkout/points" \
--header "Authorization: Bearer $SOURDI_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"points": 25,
"transaction_id": "order-2026-000185",
"purchases": ["PRODUCT-001", "PRODUCT-002"]
}'
| Champ | Type | Description |
|---|---|---|
points requis | integer | De 1 à 100 000 points à créditer. |
transaction_id requis | string | Identifiant stable et unique de la commande. |
purchases | string[] | Jusqu’à 100 références produit facultatives. |
Réponse — HTTP 201
{
"status": true,
"data": {
"reward_type": "points",
"points": 25,
"transaction_id": "order-2026-000185",
"expires_at": "2026-08-14T12:10:00.000Z",
"qr": {
"data": "sourdi_checkout_v1.…",
"image_data_url": "data:image/png;base64,iVBOR…"
}
},
"idempotent_replay": false
}
Afficher le QR sur la page de confirmation
Votre backend appelle Sourdi avec la clé secrète, puis renvoie uniquement data.qr.image_data_url à votre navigateur. L’exemple suivant suppose que votre propre endpoint /api/order/reward effectue cet appel serveur-à-serveur.
Le navigateur reçoit l’image du QR, jamais l’en-tête Authorization. Servez la page et votre endpoint de commande en HTTPS.
Sourdi dans votre caisse
Votre logiciel de caisse appelle l’API avec la même clé que le checkout web. Le parcours dépend du type de carte de votre commerce.
- Après l’encaissement, la caisse demande un QR à usage unique pour 1 à 3 tampons.
- Elle l’imprime sur le ticket grâce au flux ESC/POS fourni, ou l’affiche sur l’écran client.
- Le client scanne le QR avec l’application Sourdi, sur place ou chez lui, dans les 48 heures.
- Le client présente le QR de sa carte dans l’application Sourdi.
- Le lecteur de la caisse le scanne et transmet la valeur lue à votre logiciel.
- La caisse envoie cette valeur et le nombre de points calculé : Sourdi crédite la carte et renvoie le nouveau solde.
Ne stockez jamais la clé API sur un poste accessible aux clients. Chaque ticket utilise son propre transaction_id, par exemple le numéro du ticket.
QR à tampons pour la caisse
À la fin de l’encaissement, demandez un QR pour 1 à 3 tampons. Il reste valable 48 heures pour pouvoir être scanné depuis un ticket imprimé, et ne peut être utilisé qu’une fois. La réponse contient l’image du QR, les textes du ticket et le flux d’impression ESC/POS.
/api/v1/pos/stampsRequête serveur
curl --request POST "/api/v1/pos/stamps" \
--header "Authorization: Bearer $SOURDI_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"stamps": 2,
"transaction_id": "ticket-2026-000186",
"locale": "fr",
"paper_width": 80,
"qr_mode": "native"
}'
| Champ | Type | Description |
|---|---|---|
stamps requis | integer | Nombre de tampons à collecter : 1, 2 ou 3. |
transaction_id requis | string | Identifiant unique du ticket, de 8 à 128 caractères. Le renvoyer réimprime le même QR. |
locale | string | Langue du ticket : fr, en, ar, nl, de, el, it, pt, es, sv ou tr. Par défaut, la langue de votre compte Sourdi. |
message | string | Message imprimé au-dessus du QR pour ce ticket uniquement, 160 caractères maximum. Remplace le message enregistré dans le tableau de bord. |
paper_width | integer | Largeur du papier en millimètres : 58 ou 80. Par défaut 80. |
qr_mode | string | native, par défaut : l’imprimante dessine le QR. raster : Sourdi l’envoie sous forme d’image, pour les imprimantes sans commande QR. |
time_zone | string | Fuseau horaire IANA de la date de validité imprimée, par exemple Europe/Paris. Par défaut Africa/Tunis. |
Réponse : HTTP 201
{
"status": true,
"data": {
"reward_type": "stamps",
"amount": 2,
"stamps": 2,
"stamp_code": "sourdi_checkout_v1.…",
"transaction_id": "ticket-2026-000186",
"expires_at": "2026-10-17T11:30:00.000Z",
"qr": {
"data": "sourdi_checkout_v1.…",
"image_data_url": "data:image/png;base64,iVBOR…"
},
"receipt": {
"locale": "fr",
"message": "Merci pour votre visite chez Burger Spot !",
"scan_text": "Scannez ce QR code avec l’application Sourdi pour collecter vos tampons.",
"valid_until_text": "Valable jusqu’au 17/10/2026 12:30",
"logo_url": "https://sourdi.net/landing/iconlogo.png"
},
"escpos": {
"base64": "G0AbYQEddjAAFABgAA…",
"paper_width": 80,
"qr_mode": "native",
"printed_locale": "fr"
}
},
"idempotent_replay": false
}
Renvoyez la même requête avec le même transaction_id : tant que le QR n’a pas été scanné, l’API renvoie le même QR avec HTTP 200 et idempotent_replay: true. Une fois le QR scanné, la réponse est 409 CHECKOUT_REWARD_ALREADY_USED.
Imprimer le ticket ou afficher le QR
escpos.base64 contient le ticket complet, prêt pour une imprimante thermique compatible ESC/POS : logo Sourdi, message, QR code, instructions pour le client et date de validité, puis coupe du papier. Décodez-le en octets et envoyez-le sans le modifier.
Envoyer le flux à l’imprimante
Imprimante réseau : port TCP 9100 (impression RAW). Imprimante USB ou série : écrivez les octets sur le port, ou passez par une file d’impression en mode RAW.
// Node.js
const net = require('net');
const receipt = Buffer.from(data.escpos.base64, 'base64');
const printer = net.connect(9100, '192.168.1.50', () => printer.end(receipt));
# Python
import base64, socket
receipt = base64.b64decode(data["escpos"]["base64"])
with socket.create_connection(("192.168.1.50", 9100)) as printer:
printer.sendall(receipt)
# Shell
echo "$ESCPOS_BASE64" | base64 --decode | nc 192.168.1.50 9100
Mode natif ou raster
nativeL’imprimante génère le QR avec la commande GS ( k (modèle 2, correction M). Flux léger et rendu net : c’est le mode recommandé.rasterSourdi envoie le QR sous forme d’image (GS v 0). Utilisez ce mode si votre imprimante n’imprime pas de QR en mode natif.
Largeur du papier
| Papier | Points imprimables | Caractères par ligne |
|---|---|---|
paper_width: 58 | 384 | 32 |
paper_width: 80 | 576 | 48 |
Message du ticket
Le message imprimé au-dessus du QR est choisi dans cet ordre :
- le champ message de la requête, s’il est fourni ;
- sinon, le message enregistré dans Tableau marchand → Paramètres → Message du ticket de caisse ;
- sinon, un remerciement traduit dans la langue du ticket, par exemple « Merci pour votre visite chez Burger Spot ! ».
Langues et jeux de caractères
Le texte est encodé avec la page de code adaptée à la langue : WPC1252 pour les langues latines, WPC1253 pour le grec, WPC1254 pour le turc (numérotation Epson). Un caractère qu’aucune page de code ne contient, comme un emoji, fait imprimer le message par défaut.
Les imprimantes thermiques ne savent pas lier les lettres arabes. Pour un ticket en arabe, le flux ESC/POS imprime le texte en français et receipt contient le texte arabe, pour les caisses qui composent leur propre ticket. escpos.printed_locale indique la langue imprimée.
Écran client ou ticket composé par votre caisse
Sur un écran client, affichez qr.image_data_url. Si votre caisse compose elle-même ses tickets, générez le QR à partir de qr.data et utilisez les textes de receipt : message, scan_text, valid_until_text et logo_url.
Suivre un QR de caisse
Vérifiez si le client a collecté ses tampons, par exemple pour l’indiquer sur l’écran de la caisse.
/api/v1/pos/stamps/{transaction_id}curl "/api/v1/pos/stamps/ticket-2026-000186" \ --header "Authorization: Bearer $SOURDI_API_KEY"
{
"status": true,
"data": {
"transaction_id": "ticket-2026-000186",
"stamps": 2,
"status": "redeemed",
"expires_at": "2026-10-17T11:30:00.000Z",
"redeemed_at": "2026-10-15T18:02:41.000Z"
}
}
| Statut | Description |
|---|---|
issued | QR pas encore scanné. |
processing | Le client est en train de collecter ses tampons. |
redeemed | Tampons ajoutés à la carte du client. |
expired | QR non scanné dans les 48 heures. |
Points après le scan de la carte
Le client présente le QR de sa carte dans l’application Sourdi. Votre caisse calcule les points selon vos propres règles et envoie la valeur scannée telle quelle : Sourdi retrouve la carte du client dans votre commerce et applique les points une seule fois par transaction_id.
Configurer le lecteur
- Mode clavier (HID ou keyboard wedge), lecture des QR codes activée.
- Suffixe Entrée pour valider la lecture, sans préfixe.
- Même disposition de clavier que le poste, pour que les accolades et les guillemets du QR arrivent intacts.
- Envoyez la valeur lue sans la modifier : les espaces et retours à la ligne en début et en fin sont ignorés.
Valeurs acceptées dans scan
| Valeur scannée | Description |
|---|---|
{"type":"sourdi_user","userId":"66b8a42f9759d5ee8c90c123"} | QR de la carte affiché dans l’application Sourdi. Sourdi retrouve la carte du client dans votre commerce. |
66b8a42f9759d5ee8c90c456 | Identifiant de carte Sourdi : 24 caractères hexadécimaux. |
/api/v1/pos/pointsRequête serveur
curl --request POST "/api/v1/pos/points" \
--header "Authorization: Bearer $SOURDI_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"scan": "{\"type\":\"sourdi_user\",\"userId\":\"66b8a42f9759d5ee8c90c123\"}",
"points": 25,
"transaction_id": "ticket-2026-000187"
}'
| Champ | Type | Description |
|---|---|---|
scan | string | Valeur lue par le lecteur. Requis si card_id est absent. |
card_id | string | Identifiant de carte, à la place de scan. |
points requis | integer | Points à créditer (positif) ou à débiter (négatif), de -100 000 à 100 000, jamais 0. |
transaction_id requis | string | Identifiant stable et unique de la commande. |
purchases | string[] | Jusqu’à 100 références produit facultatives. |
Réponse : HTTP 201
{
"status": true,
"data": {
"cardId": "66b8a42f9759d5ee8c90c456",
"pointsApplied": 25,
"balance": 140,
"transactionId": "ticket-2026-000187",
"completedAt": "2026-10-15T18:05:12.000Z"
},
"idempotent_replay": false
}
Un débit supérieur au solde est refusé avec 409 INSUFFICIENT_BALANCE. Si le client n’a pas encore de carte dans votre commerce, la réponse est 404 MERCHANT_CARD_NOT_FOUND : il l’ajoute dans l’application, puis vous scannez de nouveau.
Alternative : identifiant de carte ou d’utilisateur connu
Une caisse qui lit déjà l’identifiant de carte peut créditer ou débiter le solde sans afficher de QR. Cette route est réservée aux programmes à points.
/api/v1/points/transactionscurl --request POST "/api/v1/points/transactions" \
--header "Authorization: Bearer $SOURDI_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"card_id": "66b8a42f9759d5ee8c90c123",
"points": -20,
"transaction_id": "ticket-2026-000186"
}'
Retries, expiration et usage unique
En cas de coupure réseau, renvoyez exactement la même requête avec le même transaction_id. Tant que le QR est valide et inutilisé, l’API retourne le même QR avec HTTP 200 et idempotent_replay: true.
Un transaction_id ne peut pas être réutilisé avec un autre type, montant ou panier. Après expiration, créez une nouvelle opération avec un nouvel identifiant. Dès qu’un QR est scanné, toute nouvelle tentative est refusée globalement, même depuis une autre carte.
Erreurs
| HTTP | Code | Action recommandée |
|---|---|---|
| 400 | Invalid input | Corriger les champs envoyés. |
| 400 | INVALID_SCAN | Scanner de nouveau le QR de la carte dans l’application Sourdi. |
| 401 | INVALID_API_KEY | Vérifier la clé ou en créer une nouvelle après révocation. |
| 403 | LOYALTY_API_NOT_ENABLED | Activer le programme de fidélité du commerce. |
| 403 | STAMPS_API_NOT_ENABLED / POINTS_API_NOT_ENABLED | Utiliser la route correspondant au type de carte du commerce. |
| 404 | MERCHANT_CARD_NOT_FOUND | Le client n’a pas de carte dans votre commerce : il doit l’ajouter dans l’application. |
| 404 | POS_QR_NOT_FOUND | Vérifier le transaction_id du ticket. |
| 409 | IDEMPOTENCY_CONFLICT | Utiliser un nouvel identifiant pour une nouvelle commande. |
| 409 | CHECKOUT_QR_ALREADY_USED | Ne pas appliquer la fidélité une seconde fois. |
| 409 | CHECKOUT_REWARD_ALREADY_USED | QR déjà scanné : la fidélité est déjà appliquée, ne pas réimprimer. |
| 409 | INSUFFICIENT_BALANCE | Ne pas débiter plus que le solde de la carte. |
| 409 | TRANSACTION_IN_PROGRESS | Renvoyer la même requête après quelques secondes. |
| 410 | CHECKOUT_QR_EXPIRED | Générer un nouveau QR avec un nouveau transaction_id. |
| 429 | RATE_LIMITED | Respecter RateLimit-Reset avant de réessayer. |
Bonnes pratiques de sécurité
- Appelez l’API exclusivement depuis votre serveur ou un terminal sécurisé, toujours en HTTPS.
- N’insérez jamais la clé dans le JavaScript du navigateur, une application mobile, Git, les logs ou les outils d’analytics.
- Masquez les en-têtes Authorization et les données QR dans les journaux.
- Rendez le QR uniquement après confirmation effective du paiement et ne le placez pas dans une page mise en cache.
- Révoquez immédiatement une clé suspectée d’avoir fuité, puis générez-en une nouvelle.
- Utilisez un transaction_id unique par commerce et conservez-le avec la commande.
API partenaires livraison
Pour les plateformes de livraison : donnez des tampons Sourdi pour les commandes livrées, acceptez les codes promo SRD- au paiement et annulez-les quand une commande est annulée ou remboursée. Toutes les routes ci-dessous sont relatives à /api/v1/partner.
Télécharger la description OpenAPI 3.1
Sourdi vous fournit une clé Bearer. Les clés live commencent par sourdi_partner_, les clés sandbox par sourdi_partner_test_. L’en-tête de réponse X-Sourdi-Mode vaut live ou test.
Authorization: Bearer sourdi_partner_test_KEY_ID.API_SECRET Content-Type: application/json
Chaque environnement accepte deux clés actives à la fois. Pour changer de clé sans interruption, créez la nouvelle dans la console, déployez-la, puis révoquez l’ancienne.
Identifiants
external_store_id, order_id et order_ref : de 1 à 128 caractères parmi les lettres, les chiffres et . _ : - (motif ^[A-Za-z0-9._:-]+$). Toute autre valeur reçoit 400 VALIDATION_ERROR.
Limites de débit
Chaque partenaire peut envoyer 600 requêtes par minute, dont 120 par minute sur les routes /coupons. Au-delà, l’API répond 429 RATE_LIMITED : attendez RateLimit-Reset avant de réessayer. Dix authentifications échouées depuis une même IP en 15 minutes bloquent cette IP jusqu’à la fin de la fenêtre.
Console partenaire
Votre équipe gère son intégration dans la console partenaire Sourdi : clés API de sandbox et de production, bac à sable interactif, journal des requêtes et graphiques d’usage, magasins liés, activité par commande avec export CSV, et membres de l’équipe.
Postulez depuis la page du programme partenaires livraison : Sourdi crée votre compte avec un sandbox, puis active la production quand votre intégration fonctionne. Vous pouvez d’abord explorer la console en mode démo.
Se connecter à la console partenaire Découvrir le programme partenaires
Sandbox
Demandez une clé sandbox avant d’écrire la moindre ligne. Elle n’atteint que votre commerce de test « Sourdi Sandbox <votre-slug> » et ne touche jamais de vraies cartes clients.
- POST /sandbox/reset remet votre commerce de test à zéro et renvoie un link_code (valable 30 jours) ainsi que vos codes promo de test.
- Liez-le avec POST /merchants/link, puis émettez des liens de tampons et utilisez les codes exactement comme en production.
- POST /stamps/claims/{order_id}/simulate-redeem joue le rôle du client qui ouvre le lien de tampons.
/api/v1/partner/sandbox/resetRéponse : HTTP 200
{
"status": true,
"data": {
"merchant": {
"name": "Sourdi Sandbox glovo-sandbox",
"stamps_to_reward": 10,
"coupon_value": "-15%",
"max_discount_cents": 1500,
"min_order_cents": 1000
},
"linked": false,
"external_store_id": null,
"link_code": "SRD-7K3M-9QX2-AB4C",
"link_code_expires_at": "2026-11-13T10:00:00.000Z",
"test_codes": [
{ "promo_code": "SRD-4F8KQVAD", "expected_status": "valid", "description": "-15%, max €15 discount, min order €10" },
{ "promo_code": "SRD-4F8KQEXP", "expected_status": "expired", "description": "Expired yesterday" }
]
}
}
Codes de test
| Code | Résultat attendu |
|---|---|
SRD-xxxxxVAD | Valide : -15 %, réduction maximale 15 €, commande minimale 10 €. |
SRD-xxxxxCAP | Valide : -100 %, plafonné à 15 € pour tester max_discount. |
SRD-xxxxxEXP | Expiré. |
SRD-xxxxxTXT | Pas un pourcentage : inutilisable en livraison. |
SRD-xxxxxRED | Déjà utilisé sur la commande sandbox-used-order. |
curl --request POST "/api/v1/partner/stamps/claims/order-1001/simulate-redeem" \
--header "Authorization: Bearer $SOURDI_PARTNER_KEY" \
--header "Content-Type: application/json" \
--data '{ "external_store_id": "store-42" }'
Lier un magasin
Le commerçant génère un code de connexion (15 minutes, usage unique) dans son tableau de bord Sourdi et le saisit dans votre back-office. Envoyez-le avec l’identifiant de votre magasin.
/api/v1/partner/merchants/linkcurl --request POST "/api/v1/partner/merchants/link" \
--header "Authorization: Bearer $SOURDI_PARTNER_KEY" \
--header "Content-Type: application/json" \
--data '{ "link_code": "SRD-7K3M-9QX2-AB4C", "external_store_id": "store-42" }'
Vérifier ou retirer un lien
GET /merchants/{external_store_id} renvoie le lien et le commerce (nom, logo, stamps_to_reward) ; eligible vaut false quand le commerçant a mis ses tampons en pause. DELETE /merchants/{external_store_id} retire le lien de votre côté.
/api/v1/partner/merchants/{external_store_id}/api/v1/partner/merchants/{external_store_id}curl "/api/v1/partner/merchants/store-42" \ --header "Authorization: Bearer $SOURDI_PARTNER_KEY"
{
"status": true,
"data": {
"link_id": "6710c0ffee0000000000002a",
"external_store_id": "store-42",
"status": "active",
"linked_at": "2026-10-14T09:00:00.000Z",
"revoked_at": null,
"merchant": { "name": "Burger Spot", "logo_url": "https://…", "stamps_to_reward": 10 },
"eligible": true
}
}
Tampons pour une commande
Après la livraison, demandez un lien de 1 à 3 tampons et transmettez claim_url au client. Il est à usage unique et valable 48 heures ; renvoyer le même order_id renvoie le même lien.
/api/v1/partner/stamps/claimscurl --request POST "/api/v1/partner/stamps/claims" \
--header "Authorization: Bearer $SOURDI_PARTNER_KEY" \
--header "Content-Type: application/json" \
--data '{ "external_store_id": "store-42", "order_id": "order-1001", "stamps": 1 }'
Réponse : HTTP 201
{
"status": true,
"data": {
"claim_url": "https://app.backend.sourdi.net/claim/…",
"order_id": "order-1001",
"external_store_id": "store-42",
"stamps": 1,
"status": "issued",
"expires_at": "2026-10-16T09:00:00.000Z"
},
"idempotent_replay": false
}
Statut d’un lien de tampons
GET /stamps/claims/{order_id} renvoie le statut des tampons d’une commande : issued (lien pas encore ouvert), processing (le client est en train de les collecter), redeemed, expired ou voided.
/api/v1/partner/stamps/claims/{order_id}{
"status": true,
"data": {
"order_id": "order-1001",
"stamps": 1,
"status": "redeemed",
"expires_at": "2026-10-16T09:00:00.000Z",
"redeemed_at": "2026-10-14T19:42:10.000Z",
"voided_at": null
}
}
Codes promo
Le client copie son code SRD-XXXXXXXX depuis l’application Sourdi. verify ne consomme rien ; redeem utilise le code pour une commande. Les coupons utilisables en livraison sont toujours des pourcentages de 10 à 100 %.
/api/v1/partner/coupons/verify/api/v1/partner/coupons/redeemcurl --request POST "/api/v1/partner/coupons/redeem" \
--header "Authorization: Bearer $SOURDI_PARTNER_KEY" \
--header "Content-Type: application/json" \
--data '{ "external_store_id": "store-42", "promo_code": "SRD-7K3M9QX2", "order_id": "order-1001", "order_subtotal_cents": 2450 }'
Réduction maximale et commande minimale
Appliquez la réduction exactement comme renvoyée : réduction = arrondi(sous-total × discount_percent / 100), plafonnée à max_discount, et aucune réduction si le sous-total est inférieur à min_order. Les deux valent null quand le commerçant n’a fixé aucune limite. Envoyez order_subtotal_cents à redeem : Sourdi vérifie le minimum et renvoie discount_cents.
{
"valid": true,
"status": "valid",
"promo_code": "SRD-7K3M9QX2",
"discount_percent": 15,
"coupon_value": "-15%",
"expires_at": "2026-11-02T10:00:00.000Z",
"max_discount": { "amount_cents": 1500, "currency": "EUR" },
"min_order": { "amount_cents": 1000, "currency": "EUR" },
"discount_rule": "percent_of_subtotal_capped"
}
Code utilisé en magasin pendant le paiement
Un code peut passer verify puis être utilisé en magasin avant que votre client paie : redeem répond alors 409 COUPON_ALREADY_REDEEMED. Retirez la réduction et demandez au client de payer la différence ou d’utiliser un autre code. Pour l’éviter, appelez POST /coupons/hold quand le client applique le code : il vous est réservé 10 minutes, magasin compris.
/api/v1/partner/coupons/hold/api/v1/partner/coupons/hold/releaseRéserver un code
curl --request POST "/api/v1/partner/coupons/hold" \
--header "Authorization: Bearer $SOURDI_PARTNER_KEY" \
--header "Content-Type: application/json" \
--data '{ "external_store_id": "store-42", "promo_code": "SRD-7K3M9QX2", "order_ref": "cart-5531" }'
{
"held": true,
"order_ref": "cart-5531",
"hold_expires_at": "2026-10-14T19:52:00.000Z",
"valid": true,
"status": "valid",
"promo_code": "SRD-7K3M9QX2",
"discount_percent": 15,
"coupon_value": "-15%",
"expires_at": "2026-11-02T10:00:00.000Z",
"max_discount": { "amount_cents": 1500, "currency": "EUR" },
"min_order": { "amount_cents": 1000, "currency": "EUR" },
"discount_rule": "percent_of_subtotal_capped"
}
Commandes annulées ou remboursées
Annulez ce que la commande a donné. Les deux appels sont idempotents : les répéter renvoie le même résultat.
Les annulations (void, coupons/release et coupons/hold/release) fonctionnent même après que le commerçant a mis son programme en pause, tant que le magasin est lié.
/api/v1/partner/stamps/claims/{order_id}/voidTampons : un lien non utilisé cesse de fonctionner ; des tampons déjà collectés sont retirés de la carte. S’ils avaient complété la carte et que le coupon de récompense n’est pas encore utilisé, il est retiré aussi ; sinon shortfall indique les tampons qui n’ont pas pu être retirés.
curl --request POST "/api/v1/partner/stamps/claims/order-1001/void" \
--header "Authorization: Bearer $SOURDI_PARTNER_KEY" \
--header "Content-Type: application/json" \
--data '{ "external_store_id": "store-42", "reason": "customer_cancelled" }'
/api/v1/partner/coupons/releaseCoupon : le client récupère le même code, avec sa date d’expiration et ses limites d’origine. Un coupon expiré entre-temps n’est pas restauré (restored: false).
curl --request POST "/api/v1/partner/coupons/release" \
--header "Authorization: Bearer $SOURDI_PARTNER_KEY" \
--header "Content-Type: application/json" \
--data '{ "external_store_id": "store-42", "order_id": "order-1001" }'
Tampons et coupon sur la même commande
Une commande peut recevoir un lien de tampons et utiliser un code promo, avec le même order_id. Un second code différent sur la même commande est refusé (ORDER_ALREADY_HAS_COUPON).
Erreurs partenaires
| HTTP | Code | Action recommandée |
|---|---|---|
| 400 | VALIDATION_ERROR | Corriger les champs envoyés. |
| 400 | STAMPS_LIMIT_EXCEEDED | Envoyez au plus 3 tampons par commande. |
| 401 | MISSING_API_KEY | Envoyez l’en-tête Authorization: Bearer. |
| 401 | INVALID_API_KEY | Vérifier la clé ou en créer une nouvelle après révocation. |
| 403 | PARTNER_INACTIVE | Votre compte partenaire est désactivé : contactez Sourdi. |
| 403 | STAMPS_API_NOT_ENABLED | Le commerçant a mis en pause ou n’a pas de programme à tampons : ne proposez pas Sourdi sur cette commande. |
| 404 | STORE_NOT_LINKED | Lier le magasin ou vérifier external_store_id. |
| 404 | CLAIM_NOT_FOUND | Aucun lien de tampons pour cet order_id : vérifiez l’identifiant. |
| 404 | REDEMPTION_NOT_FOUND | Aucun coupon utilisé pour cette commande : rien à rendre. |
| 410 | COUPON_EXPIRED | Le code a expiré : retirez la réduction. |
| 422 | COUPON_NOT_PERCENTAGE | Ce coupon n’est pas un pourcentage et ne peut pas être utilisé en livraison. |
| 409 | COUPON_ALREADY_REDEEMED | Retirer la réduction : le code a été utilisé ailleurs. |
| 409 | COUPON_ON_HOLD | Un autre paiement a réservé le code : réessayer après details.hold_expires_at. |
| 409 | ORDER_ALREADY_HAS_COUPON | Une seule réduction Sourdi par commande. |
| 409 | CLAIM_IN_PROGRESS | Le client collecte les tampons à cet instant : réessayer après quelques secondes. |
| 422 | ORDER_BELOW_MINIMUM | Sous-total inférieur à min_order : ne pas appliquer la réduction. |
| 403 | SANDBOX_ONLY | Route réservée aux clés sandbox. |
| 429 | RATE_LIMITED | Respecter RateLimit-Reset avant de réessayer. |