Aller au contenu principal
GoCardless API · invalid_state · 409

GoCardless 409 idempotent_creation_conflict : le prélèvement existait déjà

Cette erreur inquiète plus qu'elle ne devrait. GoCardless répond 409 idempotent_creation_conflict lorsqu'il reçoit une deuxième fois une demande de création avec une clé d'idempotence déjà utilisée. Bien géré, c'est précisément ce qui empêche de prélever deux fois la même échéance.

FlexigoTech · Responsable : Víctor Gómez · Mis à jour le 6 novembre 2026

L'essentiel

Versions
Odoo 17, 18, 19 et 20
Vérifié
dans le code du connecteur, version 17.0, 18.0, 19.0 et 20.0 · dans les sources citées à la fin
Lecture
4 min

Ce que dit GoCardless

ReasonTipoHTTPTexto de GoCardless
idempotent_creation_conflictinvalid_state409A resource already exists for the supplied idempotency key.

La page des limites de GoCardless le complète : si une ressource existe déjà avec cette clé, la réponse est un 409 avec links.conflicting_resource_id, qui désigne la ressource déjà créée. Les clés peuvent comporter jusqu'à 128 caractères, et GoCardless s'en souvient pendant au moins 30 jours.

Carte de l'erreur idempotent_creation_conflict de GoCardless
Le reason, le code HTTP 409 et le texte avec lequel GoCardless la documente.

Le problème que cela résout

Une demande peut prendre du temps : GoCardless coupe celles qui dépassent 29 secondes, et le réseau peut couper avant. Si Odoo envoie un prélèvement et ne reçoit pas de réponse, il ne sait pas si GoCardless l'a créé. Répéter la demande sans précaution est dangereux ; la documentation même de GoCardless prévient que relancer sans clé d'idempotence après un délai d'attente peut prélever deux fois le même paiement.

Avec une clé, la deuxième tentative ne crée rien : si la première est bien arrivée, GoCardless répond par ce 409 et l'identifiant du prélèvement déjà existant.

Comment le connecteur l'utilise

Le connecteur envoie une clé d'idempotence à chaque demande qui crée un prélèvement, un remboursement, une nouvelle tentative ou la demande de mandat. La clé n'est pas aléatoire. Elle est calculée à partir de l'opération, de la transaction Odoo et de l'identifiant de la base de données, de sorte que :

  • répéter le même prélèvement envoie exactement la même clé ;
  • une copie de la base destinée aux tests n'entre pas en conflit avec celle de production, même si les deux émettent la même facture.

Lorsque le 409 arrive, le connecteur lit conflicting_resource_id, demande cette ressource à GoCardless et l'adopte comme réponse. Pour vous, il n'y a pas d'erreur : la transaction reste liée au prélèvement qui existait déjà, et la facture suit son cours normal.

Quand GoCardless ne répond pas

Si la demande reste sans réponse, le connecteur la renvoie une fois avec la même clé. Sans clé, il ne renvoie rien. Si la réponse manque toujours, il signale la situation sans considérer le prélèvement comme perdu : « GoCardless did not answer, so it is not known yet whether it took the request. It will be sent again, safely, within the hour. ». La transaction reste en attente, et non en erreur, car en erreur Odoo pourrait générer un autre prélèvement avec une autre référence et une autre clé.

Ce message s'affiche dans la langue de la personne qui lance le prélèvement. Si c'est une action planifiée, comme le renouvellement d'un abonnement ou la relance du connecteur lui-même, il s'affiche sans personne devant : le connecteur n'est pas traduit en français, et ces messages sortent toujours en anglais : « GoCardless did not answer, so it is not known yet whether it took the request. It will be sent again, safely, within the hour. ».

Schéma : ce que GoCardless répond avec un 409 et ce qu'Odoo fait avec le connecteur
Schéma réalisé à partir du code du connecteur (17.0, 18.0, 19.0 et 20.0) et de la documentation de GoCardless ; ce qui est barré est ce que le 409 évite.

Que faire

Avec le connecteur, normalement rien : le 409 se résout tout seul. Si vous le voyez dans un autre logiciel connecté au même compte GoCardless, vérifiez deux choses. D'abord, que vous ne réutilisez pas une clé pour des opérations différentes. Ensuite, que la ressource de conflicting_resource_id est bien celle que vous attendiez : si c'est le cas, la nouvelle tentative a fonctionné comme prévu. Si ce n'est pas le cas, conservez le request_id de la réponse : GoCardless le demande lorsqu'on contacte son support, et le connecteur l'ajoute à ses messages d'erreur.

Un 409 signifie-t-il que le client a payé deux fois ?

Bien au contraire. Cela signifie que GoCardless a refusé de créer le second prélèvement parce que la clé en avait déjà un. Le client ne paie qu'une seule fois.

Que se passe-t-il si l'on change la référence de la transaction ?

La clé change, et GoCardless la traite comme un nouveau prélèvement. C'est pourquoi le connecteur laisse en attente, et non en erreur, un prélèvement sans réponse : ainsi, il n'en crée pas un autre avec une autre référence.

Avec notre connecteur

Dans Odoo 17, 18, 19 et 20, le connecteur applique la règle que GoCardless demande pour ne pas prélever deux fois : clé fixe par opération, nouvelle tentative uniquement avec la même clé, et adoption de la ressource existante lorsque le 409 arrive.

À lire aussi

Erreur mandate_is_inactive de GoCardless lors de la création d'un encaissement depuis OdooGoCardless répond mandate_is_inactive quand un paiement est créé avec un mandat annulé, échoué ou expiré. Pourquoi et comment le connecteur le gère.Erreur retry_failed de GoCardless lors d'une nouvelle tentative de prélèvement depuis OdooGoCardless répond retry_failed si le paiement n'a pas échoué ou n'admet plus de relance. Quand Odoo montre « Retry collection » et ce que fait le connecteur.Webhook GoCardless : 498 Token Invalid, 204 et la signature Webhook-SignatureGoCardless arrête les nouvelles tentatives sur 498 comme sur 204. Ce que répond Odoo 17, 18, 19 et 20, et pourquoi c'est un 401 sur Odoo 20.
Vérifié dans le code du connecteur (version 17.0, 18.0, 19.0 et 20.0) et dans les sources citées

Sources

  • docs.gocardless.com/docs/api-reference/limits
  • Code du module : flexigo_payment_gocardless: models/payment_provider.py, ligne 462 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) et 20.0 (688d86b)
  • Code du module : flexigo_payment_gocardless: models/payment_provider.py, ligne 352 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) et 20.0 (688d86b)
  • Code du module : flexigo_payment_gocardless: models/payment_transaction.py, ligne 68 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) et 20.0 (688d86b)
  • Code du module : flexigo_payment_gocardless: models/payment_provider.py, ligne 391 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) et 20.0 (688d86b)
  • Code du module : flexigo_payment_gocardless: models/payment_provider.py, ligne 357 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) et 20.0 (688d86b)
  • Code du module : flexigo_payment_gocardless: models/payment_provider.py, ligne 373 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) et 20.0 (688d86b)
  • Code du module : flexigo_payment_gocardless: models/payment_transaction.py, ligne 299 en 17.0 (d203ee6), ligne 299 en 18.0 (e2ab18b), ligne 299 en 19.0 (ce7f5a3) et ligne 310 en 20.0 (688d86b)
  • Code du module : flexigo_payment_gocardless: i18n/flexigo_payment_gocardless.pot, ligne 448 en 17.0 (d203ee6), ligne 448 en 18.0 (e2ab18b), ligne 448 en 19.0 (ce7f5a3) et ligne 450 en 20.0 (688d86b)
  • Code du module : flexigo_payment_gocardless: i18n/flexigo_payment_gocardless.pot, ligne 29 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) et 20.0 (688d86b)
  • Code du module : flexigo_payment_gocardless: __manifest__.py, ligne 31 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) et 20.0 (688d86b)
  • docs.gocardless.com/docs/api-reference/responses-and-errors
  • Code du module : flexigo_payment_gocardless: models/payment_transaction.py, ligne 123 en 17.0 (d203ee6), ligne 123 en 18.0 (e2ab18b), ligne 123 en 19.0 (ce7f5a3) et ligne 126 en 20.0 (688d86b)
  • Code du module : flexigo_payment_gocardless: models/payment_transaction.py, ligne 247 en 17.0 (d203ee6), ligne 247 en 18.0 (e2ab18b), ligne 247 en 19.0 (ce7f5a3) et ligne 258 en 20.0 (688d86b)
  • github.com/odoo/odoo/blob/17.0/odoo/http.py