Qué dice GoCardless
| Reason | Tipo | HTTP | Texto de GoCardless |
|---|---|---|---|
rate_limit_exceeded | invalid_api_usage | 429 | Rate limit reached. Check headers for reset time. |
La página de límites de GoCardless pone la cifra: 1.600 peticiones por minuto en una integración estándar y 1.600 por minuto y comercio en una integración de partner. Al pasarse, la API devuelve el 429, y GoCardless aclara que esas peticiones se pueden repetir sin problema: «These requests are safe to retry.». Para saber cuándo, remite a las cabeceras de la respuesta: ratelimit-limit, ratelimit-remaining y ratelimit-reset.

De dónde salen tantas peticiones
El límite cuenta todas las peticiones a la API, no solo las que crean cobros. Con el conector, cada cobro con un mandato guardado es una petición, venga de una suscripción que se renueva o de un pago registrado con el método de pago del cliente. Cada evento de un pago que llega a Odoo es otra, porque el conector no se fía solo del aviso: pide ese pago a GoCardless y aplica el estado que le devuelve. Una tanda grande en el mismo momento, como muchas renovaciones a la vez mientras llegan los eventos de los cobros anteriores, suma las dos cosas.
GoCardless clasifica este reason entre los errores invalid_api_usage, los que vienen de cómo se hace la petición, y para esos pide avisar al equipo técnico («alert your dev team»). Un 429 suelto no lo necesita; uno que se repite cada día, sí.
Lo que hace el conector
- Lee la cabecera
ratelimit-resety calcula cuánto falta: la hora que trae menos la del servidor de Odoo. - Espera ese tiempo, como mínimo 1 segundo y como mucho 65. Si la cabecera falta o no se puede leer, espera 1 segundo. El tope está para que un reloj mal puesto no deje colgado el proceso de Odoo que espera.
- Repite la petición una sola vez.
- Si la repetición vuelve a recibir un 429, ya no espera más: lo trata como cualquier otro rechazo de la API.
El conector no cuenta sus peticiones ni las frena por adelantado. No lee ratelimit-remaining: solo espera cuando GoCardless ya ha contestado 429.

Si el segundo intento también choca
Depende de lo que estaba haciendo Odoo en ese momento.
- Si era un cobro, la transacción pasa a «Error» con «GoCardless rechazó la solicitud.» y, debajo, el mensaje de GoCardless con
rate_limit_exceededy elrequest_identre corchetes. La factura sigue pendiente de cobro. - Si estaba aplicando un evento de GoCardless, el webhook contesta 500 para que GoCardless vuelva a mandar el envío, y los eventos que ya se aplicaron no se aplican dos veces. La recuperación de cada hora tampoco deja atrás un evento que falló: lo vuelve a pedir en la pasada siguiente.
Un 429 no es lo mismo que un cobro sin respuesta. Sin respuesta, el conector no sabe si GoCardless creó el cobro, así que lo deja pendiente y lo vuelve a mandar, con la misma clave, en menos de una hora. Con un 429 sí hay respuesta: GoCardless no aceptó la petición, y por eso la transacción queda en error.
Ese mensaje sale en el idioma de quien lanza el cobro. Si lo lanza una tarea programada, como la renovación de una suscripción, se escribe sin nadie delante: en una base de datos creada en castellano sale así, y en una creada en inglés y pasada después a castellano, en inglés: «GoCardless rejected the request.».
Qué hacer
- Abre la transacción desde la factura, con el botón «Transacción de pago» de arriba; el menú de transacciones solo sale en modo desarrollador, y en Odoo 20 no existe. Si el mensaje nombra
rate_limit_exceeded, GoCardless rechazó esa petición por el límite, no por el cliente ni por su mandato. - Pasado un rato, vuelve a cobrar la factura con el método de pago guardado del cliente.
- Si te pasa a menudo, comprueba la hora del servidor de Odoo: la espera sale de restarla a la de
ratelimit-reset, y un reloj adelantado la acorta. - Si necesitas a GoCardless, guarda el
request_iddel mensaje: su documentación pide incluirlo al contactar con su soporte.
¿El conector reparte las peticiones para no llegar al límite?
No. No las cuenta ni las frena por adelantado: reacciona cuando GoCardless contesta 429, con una espera y una sola repetición.
¿Por qué espera como mucho 65 segundos?
Mientras espera, el proceso de Odoo que hace la petición no hace otra cosa. El código del conector pone ese tope para que un reloj mal puesto no lo deje colgado.
¿Se pierde algún evento de GoCardless por el límite?
No se da por perdido: el webhook pide a GoCardless que lo vuelva a mandar, y la recuperación de cada hora lo vuelve a pedir en la pasada siguiente.
Con nuestro conector
En Odoo 17, 18, 19 y 20 el conector trata el 429 como una pausa: espera lo que pide GoCardless, repite una vez y, si el límite sigue, deja la transacción en error con el request_id para que sepas qué pasó y qué darle a GoCardless.
Sigue leyendo
Comprobado en el código del conector (versión 17.0, 18.0, 19.0 y 20.0) y en las fuentes enlazadas
Fuentes
- docs.gocardless.com/docs/api-reference/limits
- docs.gocardless.com/docs/api-reference/responses-and-errors
- Código del módulo: flexigo_payment_gocardless: const.py, línea 113 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) y 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_provider.py, línea 378 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) y 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_provider.py, línea 408 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) y 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_provider.py, línea 379 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) y 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_provider.py, línea 383 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) y 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_provider.py, línea 397 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) y 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_provider.py, línea 462 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) y 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_transaction.py, línea 281 en 17.0 (d203ee6), línea 281 en 18.0 (e2ab18b), línea 281 en 19.0 (ce7f5a3) y línea 292 en 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_transaction.py, línea 247 en 17.0 (d203ee6), línea 247 en 18.0 (e2ab18b), línea 247 en 19.0 (ce7f5a3) y línea 258 en 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_transaction.py, línea 299 en 17.0 (d203ee6), línea 299 en 18.0 (e2ab18b), línea 299 en 19.0 (ce7f5a3) y línea 310 en 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_transaction.py, línea 589 en 17.0 (d203ee6), línea 589 en 18.0 (e2ab18b), línea 588 en 19.0 (ce7f5a3) y línea 607 en 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: controllers/main.py, línea 124 en 17.0 (d203ee6), línea 124 en 18.0 (e2ab18b), línea 124 en 19.0 (ce7f5a3) y línea 127 en 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: controllers/main.py, línea 96 en 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/gocardless_webhook_event.py, línea 7 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) y 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: const.py, línea 117 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) y 20.0 (688d86b)
- Código del módulo: flexigo_payment_gocardless: models/payment_provider.py, línea 603 en 17.0 (d203ee6), línea 603 en 18.0 (e2ab18b), línea 603 en 19.0 (ce7f5a3) y línea 605 en 20.0 (688d86b)
- docs.gocardless.com/docs/api-reference/webhooks
- Código del módulo: flexigo_payment_gocardless: i18n/es.po, línea 560 en 17.0 (d203ee6), línea 560 en 18.0 (e2ab18b), línea 560 en 19.0 (ce7f5a3) y línea 565 en 20.0 (688d86b)
- github.com/odoo/odoo/blob/20.0/addons/payment/i18n/es.po
- github.com/odoo/odoo/blob/20.0/addons/payment/views/payment_transaction_views.xml
- github.com/odoo/odoo/blob/17.0/odoo/http.py
- github.com/odoo/odoo/blob/20.0/addons/account_payment/views/account_move_views.xml
- Código del módulo: flexigo_payment_gocardless: __manifest__.py, línea 31 en 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) y 20.0 (688d86b)
