Les caisses scannent la carte Fidelia du client (QR ou code-barres) et ajoutent tampons, points, cashback, passages d'abonnement, paiements prépayés et articles de carnet. Tous les montants sont des entiers en centimes (unités mineures) de la devise du commerce. Guides : https://fidelia.se/developers/fr/
Cards
Lire une carte et agir dessus.
GET /cards/{code}
Lire une carte
code est ce que le scanner a lu : le numéro de série de 32 caractères (QR) ou le numéro de carte à 13 chiffres (code-barres). Renvoie le prénom du client, les soldes, les récompenses disponibles et, pour les abonnements, la remise à appliquer au panier.
| Nom | Où | Description |
|---|
code · obligatoire | path | Numéro de série (QR, 32 hexadécimaux) ou numéro de carte (code-barres, 13 chiffres). |
lang | query | Langue des noms de récompenses et de cartes (une des langues du commerce ; aussi lue dans Accept-Language). |
Réponses
200 OK401 Clé absente, mal formée ou révoquée (invalid_key)402 Le commerce doit avoir Pro (plan_required) ou son abonnement a pris fin (subscription_inactive)404 Introuvable (card_not_found, receipt_not_found, pairing_not_found, milestone_not_found)410 N'existe plus (card_voided, pairing_expired)429 Trop de requêtes (rate_limited) ; attendez Retry-After secondes
POST /cards/{code}/sale
Enregistrer une vente
À envoyer à la clôture du ticket. Fidelia applique les règles de caisse de la carte : un tampon (cartes à tampons, à partir du montant minimum), des points (cartes à points), du cashback sur la partie non payée avec le solde de la carte, un passage (abonnements). Les cartes prépayées et carnets ne gagnent rien sur une vente. Une vente n'échoue jamais pour une raison métier : applied vaut false avec une reason (ex. cooldown, reward_ready, below_min_amount).
| Nom | Où | Description |
|---|
code · obligatoire | path | Numéro de série (QR, 32 hexadécimaux) ou numéro de carte (code-barres, 13 chiffres). |
Idempotency-Key · obligatoire | header | Unique par action (ex. un UUID). Une nouvelle tentative avec la même clé et le même corps renvoie la première réponse (en-tête Idempotent-Replayed: true) ; conservée 24 h. |
Fidelia-Device | header | Nom de la caisse affiché dans l'historique (par défaut : le nom de la clé). |
lang | query | Langue des noms de récompenses et de cartes (une des langues du commerce ; aussi lue dans Accept-Language). |
Corps de la requête (exemple)
{
"amount": 1250,
"receipt_ref": "T1-000042"
}
Réponses
200 OK400 Paramètre invalide (invalid_input + field)401 Clé absente, mal formée ou révoquée (invalid_key)402 Le commerce doit avoir Pro (plan_required) ou son abonnement a pris fin (subscription_inactive)403 La clé ne peut pas faire cela (scope_denied)404 Introuvable (card_not_found, receipt_not_found, pairing_not_found, milestone_not_found)409 L'état de la carte le refuse (insufficient_balance, not_ready, already_claimed, wrong_card_type, reverse_conflict, idempotency_mismatch, …)410 N'existe plus (card_voided, pairing_expired)429 Trop de requêtes (rate_limited) ; attendez Retry-After secondes
POST /cards/{code}/rewards/{reward_id}/redeem
Utiliser une récompense
Cartes à tampons : reward_id vaut ready (carte pleine) ou milestone:<id> (une récompense intermédiaire, listée dans stamps.milestones ; la carte continue de se remplir). Cartes à points : l'id d'une récompense du programme (voir GET /me). La réponse contient l'article de caisse lié par le commerçant (product.ref, product.value) pour que la caisse ajoute l'article offert.
| Nom | Où | Description |
|---|
code · obligatoire | path | Numéro de série (QR, 32 hexadécimaux) ou numéro de carte (code-barres, 13 chiffres). |
reward_id · obligatoire | path | ready, milestone:<id> ou l'id d'une récompense à points |
Idempotency-Key · obligatoire | header | Unique par action (ex. un UUID). Une nouvelle tentative avec la même clé et le même corps renvoie la première réponse (en-tête Idempotent-Replayed: true) ; conservée 24 h. |
Fidelia-Device | header | Nom de la caisse affiché dans l'historique (par défaut : le nom de la clé). |
lang | query | Langue des noms de récompenses et de cartes (une des langues du commerce ; aussi lue dans Accept-Language). |
Corps de la requête (exemple)
{
"receipt_ref": "T1-000042"
}
Réponses
200 OK400 Paramètre invalide (invalid_input + field)401 Clé absente, mal formée ou révoquée (invalid_key)402 Le commerce doit avoir Pro (plan_required) ou son abonnement a pris fin (subscription_inactive)403 La clé ne peut pas faire cela (scope_denied)404 Introuvable (card_not_found, receipt_not_found, pairing_not_found, milestone_not_found)409 L'état de la carte le refuse (insufficient_balance, not_ready, already_claimed, wrong_card_type, reverse_conflict, idempotency_mismatch, …)410 N'existe plus (card_voided, pairing_expired)429 Trop de requêtes (rate_limited) ; attendez Retry-After secondes
POST /cards/{code}/balance/spend
Payer avec le solde de la carte
Cartes cashback et prépayées. amount est un nombre d'unités mineures ou "all" ; jamais plus que receipt_total s'il est donné. Traitez spent comme une ligne de paiement (paiement fractionné : le client paie le reste autrement). Envoyez-le avant la vente sur le même receipt_ref, pour que le cashback ne soit pas gagné sur la partie payée avec le solde.
| Nom | Où | Description |
|---|
code · obligatoire | path | Numéro de série (QR, 32 hexadécimaux) ou numéro de carte (code-barres, 13 chiffres). |
Idempotency-Key · obligatoire | header | Unique par action (ex. un UUID). Une nouvelle tentative avec la même clé et le même corps renvoie la première réponse (en-tête Idempotent-Replayed: true) ; conservée 24 h. |
Fidelia-Device | header | Nom de la caisse affiché dans l'historique (par défaut : le nom de la clé). |
lang | query | Langue des noms de récompenses et de cartes (une des langues du commerce ; aussi lue dans Accept-Language). |
Corps de la requête (exemple)
{
"amount": "all",
"receipt_total": 1250,
"receipt_ref": "T1-000042"
}
Réponses
200 OK400 Paramètre invalide (invalid_input + field)401 Clé absente, mal formée ou révoquée (invalid_key)402 Le commerce doit avoir Pro (plan_required) ou son abonnement a pris fin (subscription_inactive)403 La clé ne peut pas faire cela (scope_denied)404 Introuvable (card_not_found, receipt_not_found, pairing_not_found, milestone_not_found)409 L'état de la carte le refuse (insufficient_balance, not_ready, already_claimed, wrong_card_type, reverse_conflict, idempotency_mismatch, …)410 N'existe plus (card_voided, pairing_expired)429 Trop de requêtes (rate_limited) ; attendez Retry-After secondes
POST /cards/{code}/balance/topup
Recharger une carte prépayée
Le client a payé amount en caisse ; la carte est créditée de amount plus le bonus du programme (credited).
| Nom | Où | Description |
|---|
code · obligatoire | path | Numéro de série (QR, 32 hexadécimaux) ou numéro de carte (code-barres, 13 chiffres). |
Idempotency-Key · obligatoire | header | Unique par action (ex. un UUID). Une nouvelle tentative avec la même clé et le même corps renvoie la première réponse (en-tête Idempotent-Replayed: true) ; conservée 24 h. |
Fidelia-Device | header | Nom de la caisse affiché dans l'historique (par défaut : le nom de la clé). |
lang | query | Langue des noms de récompenses et de cartes (une des langues du commerce ; aussi lue dans Accept-Language). |
Corps de la requête (exemple)
{
"amount": 2000,
"receipt_ref": "T1-000043"
}
Réponses
200 OK400 Paramètre invalide (invalid_input + field)401 Clé absente, mal formée ou révoquée (invalid_key)402 Le commerce doit avoir Pro (plan_required) ou son abonnement a pris fin (subscription_inactive)403 La clé ne peut pas faire cela (scope_denied)404 Introuvable (card_not_found, receipt_not_found, pairing_not_found, milestone_not_found)409 L'état de la carte le refuse (insufficient_balance, not_ready, already_claimed, wrong_card_type, reverse_conflict, idempotency_mismatch, …)410 N'existe plus (card_voided, pairing_expired)429 Trop de requêtes (rate_limited) ; attendez Retry-After secondes
POST /cards/{code}/membership/renew
Renouveler ou activer un abonnement
Prolonge l'abonnement de la durée du programme, ou active un abonnement en attente de paiement.
| Nom | Où | Description |
|---|
code · obligatoire | path | Numéro de série (QR, 32 hexadécimaux) ou numéro de carte (code-barres, 13 chiffres). |
Idempotency-Key · obligatoire | header | Unique par action (ex. un UUID). Une nouvelle tentative avec la même clé et le même corps renvoie la première réponse (en-tête Idempotent-Replayed: true) ; conservée 24 h. |
Fidelia-Device | header | Nom de la caisse affiché dans l'historique (par défaut : le nom de la clé). |
lang | query | Langue des noms de récompenses et de cartes (une des langues du commerce ; aussi lue dans Accept-Language). |
Corps de la requête (exemple)
{
"receipt_ref": "T1-000044"
}
Réponses
200 OK400 Paramètre invalide (invalid_input + field)401 Clé absente, mal formée ou révoquée (invalid_key)402 Le commerce doit avoir Pro (plan_required) ou son abonnement a pris fin (subscription_inactive)403 La clé ne peut pas faire cela (scope_denied)404 Introuvable (card_not_found, receipt_not_found, pairing_not_found, milestone_not_found)409 L'état de la carte le refuse (insufficient_balance, not_ready, already_claimed, wrong_card_type, reverse_conflict, idempotency_mismatch, …)410 N'existe plus (card_voided, pairing_expired)429 Trop de requêtes (rate_limited) ; attendez Retry-After secondes
POST /cards/{code}/pack/sell
Vendre ou activer un carnet
Un carnet en attente de paiement est activé ; un carnet actif reçoit count carnets de plus.
| Nom | Où | Description |
|---|
code · obligatoire | path | Numéro de série (QR, 32 hexadécimaux) ou numéro de carte (code-barres, 13 chiffres). |
Idempotency-Key · obligatoire | header | Unique par action (ex. un UUID). Une nouvelle tentative avec la même clé et le même corps renvoie la première réponse (en-tête Idempotent-Replayed: true) ; conservée 24 h. |
Fidelia-Device | header | Nom de la caisse affiché dans l'historique (par défaut : le nom de la clé). |
lang | query | Langue des noms de récompenses et de cartes (une des langues du commerce ; aussi lue dans Accept-Language). |
Corps de la requête (exemple)
{
"count": 1,
"receipt_ref": "T1-000045"
}
Réponses
200 OK400 Paramètre invalide (invalid_input + field)401 Clé absente, mal formée ou révoquée (invalid_key)402 Le commerce doit avoir Pro (plan_required) ou son abonnement a pris fin (subscription_inactive)403 La clé ne peut pas faire cela (scope_denied)404 Introuvable (card_not_found, receipt_not_found, pairing_not_found, milestone_not_found)409 L'état de la carte le refuse (insufficient_balance, not_ready, already_claimed, wrong_card_type, reverse_conflict, idempotency_mismatch, …)410 N'existe plus (card_voided, pairing_expired)429 Trop de requêtes (rate_limited) ; attendez Retry-After secondes
POST /cards/{code}/pack/use
Utiliser des articles du carnet
Retire count articles (1–10) d'un carnet actif.
| Nom | Où | Description |
|---|
code · obligatoire | path | Numéro de série (QR, 32 hexadécimaux) ou numéro de carte (code-barres, 13 chiffres). |
Idempotency-Key · obligatoire | header | Unique par action (ex. un UUID). Une nouvelle tentative avec la même clé et le même corps renvoie la première réponse (en-tête Idempotent-Replayed: true) ; conservée 24 h. |
Fidelia-Device | header | Nom de la caisse affiché dans l'historique (par défaut : le nom de la clé). |
lang | query | Langue des noms de récompenses et de cartes (une des langues du commerce ; aussi lue dans Accept-Language). |
Corps de la requête (exemple)
{
"count": 1,
"receipt_ref": "T1-000046"
}
Réponses
200 OK400 Paramètre invalide (invalid_input + field)401 Clé absente, mal formée ou révoquée (invalid_key)402 Le commerce doit avoir Pro (plan_required) ou son abonnement a pris fin (subscription_inactive)403 La clé ne peut pas faire cela (scope_denied)404 Introuvable (card_not_found, receipt_not_found, pairing_not_found, milestone_not_found)409 L'état de la carte le refuse (insufficient_balance, not_ready, already_claimed, wrong_card_type, reverse_conflict, idempotency_mismatch, …)410 N'existe plus (card_voided, pairing_expired)429 Trop de requêtes (rate_limited) ; attendez Retry-After secondes
Card
{
"type": "object",
"required": [
"serial",
"card_number",
"type",
"program",
"customer",
"currency",
"rewards_available",
"cooldown_remaining_seconds"
],
"properties": {
"serial": {
"type": "string"
},
"card_number": {
"type": "string",
"pattern": "^[0-9]{13}$"
},
"type": {
"$ref": "#/components/schemas/CardType"
},
"program": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"name": {
"type": [
"string",
"null"
]
}
}
},
"customer": {
"type": "object",
"properties": {
"first_name": {
"type": [
"string",
"null"
]
},
"locale": {
"type": [
"string",
"null"
]
}
}
},
"currency": {
"type": "string",
"enum": [
"EUR",
"SEK"
]
},
"tier": {
"type": [
"object",
"null"
],
"properties": {
"id": {
"type": "string"
},
"name": {
"type": [
"string",
"null"
]
},
"perk": {
"type": [
"string",
"null"
]
}
}
},
"cooldown_remaining_seconds": {
"type": "integer",
"description": "Seconds before the next stamp / check-in counts."
},
"rewards_available": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"label": {
"type": [
"string",
"null"
]
},
"points": {
"type": "integer"
}
}
},
"description": "Ask the customer \"Use reward now?\" when not empty."
},
"stamps": {
"type": "object",
"description": "Stamp cards.",
"properties": {
"count": {
"type": "integer"
},
"required": {
"type": "integer"
},
"cycle": {
"type": "integer"
},
"reward_ready": {
"type": "boolean"
},
"reward": {
"type": [
"string",
"null"
]
},
"milestones": {
"type": "array",
"description": "Smaller rewards on the way (this round of stamps).",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"example": "milestone:cookie"
},
"stamps": {
"type": "integer"
},
"label": {
"type": [
"string",
"null"
]
},
"claimed": {
"type": "boolean"
},
"available": {
"type": "boolean"
}
}
}
}
}
},
"points": {
"type": "object",
"description": "Points cards.",
"properties": {
"balance": {
"type": "integer"
},
"spend_per_point": {
"type": [
"integer",
"null"
]
},
"rewards": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"label": {
"type": [
"string",
"null"
]
},
"points": {
"type": "integer"
},
"available": {
"type": "boolean"
}
}
}
}
}
},
"balance": {
"type": "object",
"description": "Cashback and prepaid cards (minor units).",
"properties": {
"amount": {
"type": "integer"
},
"percent": {
"type": [
"integer",
"null"
]
},
"bonus_percent": {
"type": "integer"
}
}
},
"membership": {
"type": "object",
"description": "Membership cards: apply discount_percent to the basket while active.",
"properties": {
"active": {
"type": "boolean"
},
"waiting_activation": {
"type": "boolean"
},
"valid_until": {
"type": [
"string",
"null"
],
"format": "date"
},
"discount_percent": {
"type": "integer"
},
"perk": {
"type": [
"string",
"null"
]
}
}
},
"pack": {
"type": "object",
"description": "Pack cards.",
"properties": {
"items_left": {
"type": "integer"
},
"items_per_pack": {
"type": "integer"
},
"item": {
"type": [
"string",
"null"
]
},
"active": {
"type": "boolean"
},
"price": {
"type": [
"integer",
"null"
]
}
}
}
}
}
ActionResult
{
"type": "object",
"required": [
"action",
"applied",
"card"
],
"properties": {
"action": {
"type": "string",
"enum": [
"sale",
"redeem",
"balance_spend",
"balance_topup",
"membership_renew",
"pack_sell",
"pack_use"
]
},
"applied": {
"type": "boolean"
},
"reason": {
"type": [
"string",
"null"
],
"description": "Sale only, when applied is false: cooldown, reward_ready, below_min_amount, auto_stamp_off, nothing_to_earn, membership_expired, membership_inactive, not_applicable, program_inactive, subscription_inactive."
},
"event": {
"type": [
"string",
"null"
]
},
"receipt_ref": {
"type": [
"string",
"null"
]
},
"earned_points": {
"type": "integer"
},
"earned_balance": {
"type": "integer"
},
"balance_spent_on_receipt": {
"type": "integer"
},
"redeemed_points": {
"type": "integer"
},
"reward_id": {
"type": "string"
},
"product": {
"type": [
"object",
"null"
],
"properties": {
"ref": {
"type": "string"
},
"value": {
"type": "integer"
}
}
},
"spent": {
"type": "integer"
},
"credited": {
"type": "integer"
},
"added_items": {
"type": "integer"
},
"used_items": {
"type": "integer"
},
"activated": {
"type": "boolean"
},
"card": {
"$ref": "#/components/schemas/Card"
}
}
}