Cobrança duplicada após retry sem idempotência
Esse erro ocorre quando a integração repete a criação de uma cobrança após timeout, falha temporária ou resposta inconclusiva, sem confirmar o resultado da tentativa anterior.
Um timeout significa que a integração não recebeu a resposta esperada. Isso não confirma que a cobrança deixou de ser criada no Asaas.
Como identificar
- existem duas ou mais cobranças relacionadas ao mesmo pedido;
- a duplicidade ocorreu após timeout ou falha de conexão;
- diferentes IDs do Asaas estão vinculados à mesma operação interna;
- o sistema não registra o resultado das tentativas anteriores;
- não existe identificador interno ou
externalReference; - mais de um processo pode criar a mesma cobrança simultaneamente.
Como corrigir
- Identifique as cobranças relacionadas à mesma operação.
- Compare cliente, valor, vencimento e referência.
- Confirme qual cobrança deve permanecer ativa.
- Cancele as cobranças duplicadas, quando aplicável.
- Relacione o ID correto ao registro interno.
- Analise o histórico das tentativas que causaram a duplicidade.
- Consulte o resultado da tentativa anterior antes de criar novamente.
- Implemente um identificador único para cada operação.
- Controle retries e execuções concorrentes.
Fluxo recomendado: registrar a tentativa → consultar o resultado → reutilizar o ID existente ou criar uma única vez → armazenar o resultado.
Fluxo de diagnóstico
1. Identificação e correção da duplicidade
%%{init: {"flowchart": {"nodeSpacing": 18,"rankSpacing": 24,"diagramPadding": 4,"padding": 7
}}}%%
flowchart TD
A["Foi identificada uma possível cobrança duplicada"] --> B{"Há mais de uma cobrança para o mesmo pedido?"}
B --> BSim(("Sim"))
B --> BNao(("Não"))
BNao --> C["Investigar outra causa da divergência"]
BSim --> D{"O ID correto está vinculado ao registro interno?"}
D --> DSim(("Sim"))
D --> DNao(("Não"))
D --> DDuvida(("Não sabe"))
DNao --> E["Consultar o histórico e as tentativas da operação"]
DDuvida --> E
DSim --> F["Confirmar qual cobrança deve permanecer ativa"]
E --> F
F --> G{"Existem cobranças duplicadas ativas?"}
G --> GSim(("Sim"))
G --> GNao(("Não"))
GSim --> H["Cancelar as cobranças duplicadas"]
GNao --> I["Manter somente a cobrança válida"]
H --> I
I --> J["Registrar o resultado e revisar a regra de retry"]
C --> J
classDef inicio fill:#DBEAFE,stroke:#2563EB,color:#1E3A8A,stroke-width:3px
classDef decisao fill:#FEF3C7,stroke:#D97706,color:#78350F,stroke-width:3px
classDef correcao fill:#FFEDD5,stroke:#EA580C,color:#7C2D12,stroke-width:2px
classDef validacao fill:#E0F2FE,stroke:#0284C7,color:#0C4A6E,stroke-width:2px
classDef sucesso fill:#DCFCE7,stroke:#16A34A,color:#14532D,stroke-width:3px
classDef analise fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D,stroke-width:3px
classDef respostaSim fill:#22C55E,stroke:#15803D,color:#FFFFFF,stroke-width:3px
classDef respostaNao fill:#EF4444,stroke:#B91C1C,color:#FFFFFF,stroke-width:3px
classDef respostaDuvida fill:#8B5CF6,stroke:#6D28D9,color:#FFFFFF,stroke-width:3px
class A inicio
class B,D,G decisao
class H,I correcao
class F validacao
class J sucesso
class C,E analise
class BSim,DSim,GSim respostaSim
class BNao,DNao,GNao respostaNao
class DDuvida respostaDuvida
linkStyle default stroke:#94A3B8,stroke-width:2px
linkStyle 1,5,13 stroke:#22C55E,stroke-width:4px
linkStyle 2,6,14 stroke:#EF4444,stroke-width:4px
linkStyle 7 stroke:#8B5CF6,stroke-width:4px
2. Retry seguro após resposta inconclusiva
%%{init: {"flowchart": {"nodeSpacing": 18,"rankSpacing": 24,"diagramPadding": 4,"padding": 7
}}}%%
flowchart TD
A["A tentativa terminou com timeout ou resposta inconclusiva"] --> B{"Existe identificador único da operação?"}
B --> BSim(("Sim"))
B --> BNao(("Não"))
BNao --> C["Gerar identificador interno e definir externalReference"]
C --> D["Registrar a tentativa e seu resultado"]
BSim --> D
D --> E{"Existe cobrança vinculada ao identificador?"}
E --> ESim(("Sim"))
E --> ENao(("Não"))
E --> EDuvida(("Não sabe"))
ESim --> F["Reutilizar o ID existente"]
ENao --> G{"Houve timeout ou falha temporária?"}
EDuvida --> H["Consultar histórico, referências e registros internos"]
G --> GSim(("Sim"))
G --> GNao(("Não"))
G --> GDuvida(("Não sabe"))
GSim --> H
GDuvida --> H
GNao --> I["Tratar o erro sem repetir a criação"]
H --> J{"A cobrança foi localizada?"}
J --> JSim(("Sim"))
J --> JNao(("Não"))
JSim --> F
JNao --> K["Criar a cobrança uma única vez"]
K --> L["Armazenar o ID e o resultado da tentativa"]
L --> M["Finalizar o retry com controle de concorrência"]
F --> M
I --> M
classDef inicio fill:#DBEAFE,stroke:#2563EB,color:#1E3A8A,stroke-width:3px
classDef decisao fill:#FEF3C7,stroke:#D97706,color:#78350F,stroke-width:3px
classDef correcao fill:#FFEDD5,stroke:#EA580C,color:#7C2D12,stroke-width:2px
classDef validacao fill:#E0F2FE,stroke:#0284C7,color:#0C4A6E,stroke-width:2px
classDef sucesso fill:#DCFCE7,stroke:#16A34A,color:#14532D,stroke-width:3px
classDef analise fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D,stroke-width:3px
classDef respostaSim fill:#22C55E,stroke:#15803D,color:#FFFFFF,stroke-width:3px
classDef respostaNao fill:#EF4444,stroke:#B91C1C,color:#FFFFFF,stroke-width:3px
classDef respostaDuvida fill:#8B5CF6,stroke:#6D28D9,color:#FFFFFF,stroke-width:3px
class A inicio
class B,E,G,J decisao
class C,D,F,K,L correcao
class H validacao
class M sucesso
class I analise
class BSim,ESim,GSim,JSim respostaSim
class BNao,ENao,GNao,JNao respostaNao
class EDuvida,GDuvida respostaDuvida
linkStyle default stroke:#94A3B8,stroke-width:2px
linkStyle 1,7,13,20 stroke:#22C55E,stroke-width:4px
linkStyle 2,8,14,21 stroke:#EF4444,stroke-width:4px
linkStyle 9,15 stroke:#8B5CF6,stroke-width:4px
O primeiro fluxo orienta como identificar e corrigir cobranças já duplicadas, enquanto o segundo mostra como executar um retry sem criar uma nova cobrança indevidamente.
Como prevenir
Gere um identificador único para cada operação, registre todas as tentativas e consulte o resultado anterior antes de repetir uma criação. Limite retries automáticos e impeça execuções concorrentes para a mesma operação.
O externalReference pode ajudar a relacionar e localizar a cobrança, mas deve ser utilizado junto ao controle interno de retries e concorrência.
Timeout não significa que a cobrança não foi criada. Verifique o resultado antes de tentar novamente.
Updated about 13 hours ago
