Pular para o conteúdo

A máquina de estados do pagamento

As transições de status são decididas somente pela API, de forma central, com um compare-and-set sobre a versão da intenção, e cada uma é gravada na linha do tempo append-only junto com a sua evidência. Os workers em segundo plano nunca alteram um status diretamente; eles enviam observações e a máquina de estados as avalia.

Máquina de estados do pagamentoCaminho feliz: created, awaiting_payment, detected, confirming, confirmed. created pode virar canceled. awaiting_payment pode virar expired; expired vira late_payment quando chega uma transferência após expirar. confirming pode virar underpaid, overpaid ou reorged. confirmed vira reorged após uma reorg profunda. reorged volta para confirming quando a transferência é reincluída, ou vai para manual_review quando é descartada. underpaid e late_payment vão para manual_review. manual_review e overpaid terminam em resolved com uma decisão registrada. failed só é usado com um motivo validado.cotação travadavistoem um bloco≥ exigidaslojista cancelacotação expirouexcedentefaltoureorg ⇄ reincluídareorg grandepago após expirarrequer decisãodecisão + evidênciadecisão do lojistatransferência caiucreatedawaiting_paymentdetectedconfirmingconfirmedcanceledexpiredunderpaidoverpaidreorgedfailedlate_paymentmanual_reviewresolved
em andamento / finalrequer decisãoreorganizado ou com falhaCada transição é decidida centralmente pela API com um compare-and-set na versão do pagamento e registrada, com suas evidências, na linha do tempo somente de acréscimo. Em telas pequenas, o diagrama rola para os lados.
Status Significa Entregável Sua ação
created Intenção criada; o cliente ainda não escolheu uma rede não Mostrar “aguardando pagamento”
awaiting_payment Cotação travada, endereço exclusivo atribuído não Aguardar
detected Uma transferência foi vista, mas ainda não está em um bloco não Aguardar — ela ainda pode desaparecer
confirming A transferência está em um bloco e acumulando confirmações não Aguardar
confirmed O valor esperado atingiu as confirmações exigidas sim Entregar (depois de verificar o webhook e reler a intenção)
underpaid Foi confirmado menos do que o cotado não Decidir: pedir o restante, aceitar parcialmente ou reembolsar fora da cadeia; depois resolver
overpaid Foi confirmado mais do que o cotado sim Entregar; contatar o cliente sobre o excedente; depois resolver
expired A cotação expirou antes de qualquer pagamento ser visto não Oferecer um novo checkout se o cliente ainda quiser pagar
late_payment Uma transferência chegou após a expiração não Revisar — o preço pode ter mudado; aceitar, reembolsar ou rejeitar; depois resolver
reorged Um bloco que continha o pagamento foi substituído não Pausar ou reverter a entrega; aguardar nova confirmação ou revisão
manual_review Retida para uma decisão documentada não Revisar a evidência; resolver
resolved Uma decisão registrada encerrou a intenção conforme a decisão Seguir a sua decisão (resolution.kind)
failed Falhou, apenas por um motivo validado não Ler status_reason
canceled Você cancelou antes de qualquer transferência não Nada
  • Crédito exatamente uma vez. Cada transferência na cadeia tem uma identidade determinística (rede + transação + saída ou índice de log). Entregar a mesma observação duas vezes nunca credita duas vezes.
  • Identidade do ativo, não símbolos. Uma transferência só conta se a rede, o endereço do contrato e as casas decimais corresponderem à entrada do registro do ativo cotado. Um token que apenas compartilha o símbolo é registrado e sinalizado, nunca creditado.
  • Nenhuma reversão silenciosa. Um status final nunca volta atrás em silêncio. Se a cadeia se reorganizar depois de confirmed, a intenção passa para reorged e um webhook payment.reorged é enviado; ela só volta a confirmar com nova evidência.
  • A pontualidade é decidida na primeira observação. Uma transferência vista pela primeira vez antes de a cotação expirar conta para o pagamento mesmo que confirme depois. Uma transferência vista pela primeira vez após a expiração é classificada como atrasada.
  • Pagamentos extras após a confirmação não alteram uma intenção confirmada; eles criam uma divergência de conciliação e um evento payment.review_required.
  • Cotações são imutáveis. Atualizar uma cotação substitui a antiga; nunca a edita.

O checkout hospedado, o painel e @feitpay/react exibem cada status com um rótulo de texto e um símbolo, em inglês, português (Brasil) e finlandês — nunca apenas com cor. Se você construir a sua própria interface, faça o mesmo.