Como verificar um pagamento pela API sem webhook
Verificação de faturas no servidor pela API: estados, polling limitado, erros, execução única do pedido e recuperação após um reinício.
Atualizado:
Pode verificar um pagamento sem webhook a partir do servidor da sua aplicação: consultar periodicamente a fatura através da API do Cryptanio, associá-la ao pedido e executar o pedido quando o estado atual for paid. Esta consulta periódica chama-se polling. Exige uma fila de verificações, tratamento de erros e proteção contra entregas duplicadas: uma resposta HTTP bem-sucedida não confirma, por si só, o pagamento.
Esta opção serve quando a aplicação consegue executar tarefas em segundo plano, mas ainda não é conveniente receber notificações de entrada. As alterações são detetadas na consulta seguinte; o polling não fornece uma notificação imediata.
O que é necessário
Guarde na sua base de dados a relação entre o pedido e a fatura: o respetivo id, o projeto, a sua reference, o preço combinado e o modo de funcionamento. Mantenha os identificadores como cadeias de caracteres. Verifique a fatura desse pedido concreto, não uma transação encontrada com um montante semelhante.
Prepare uma chave API no servidor com permissão de leitura de invoices, acesso ao serviço payments e ao projeto necessário. Um pedido real exige o modo de produção correspondente. Não coloque a chave no navegador, no link do comprador nem num registo público. O acesso só de leitura é suficiente para um processo de conciliação separado.
Passo 1. Obtenha o estado atual
O exemplo consulta uma única fatura. Defina CRYPTANIO_API_KEY e CRYPTANIO_RESOURCE_ID no servidor; o segundo valor é o id guardado da fatura, não o número do pedido nem o TXID.
#!/usr/bin/env bash
set -euo pipefail
: "${CRYPTANIO_RESOURCE_ID:?Set CRYPTANIO_RESOURCE_ID}"
: "${CRYPTANIO_API_KEY:?Set CRYPTANIO_API_KEY}"
urlencode() {
local LC_ALL=C text="$1" char index
for ((index=0; index<${#text}; index++)); do
char="${text:index:1}"
case "$char" in [a-zA-Z0-9.~_-]) printf '%s' "$char" ;; *) printf '%%%02X' "'$char" ;; esac
done
}
response_file="$(mktemp)"
trap 'rm -f "$response_file"' EXIT
transfer_status=0
http_status="$(curl \
--silent --show-error --max-time 30 --request GET \
--header "Authorization: Bearer $CRYPTANIO_API_KEY" \
--header 'Accept: application/json' \
"https://api.cryptanio.com/v1/invoices/$(urlencode "$CRYPTANIO_RESOURCE_ID")" \
--output "$response_file" --write-out '%{http_code}')" || transfer_status=$?
if [[ "$http_status" == 2?? ]]; then
cat "$response_file"
exit "$transfer_status"
fi
printf 'HTTP %s\n' "$http_status" >&2
cat "$response_file" >&2
exit 1
Após HTTP 200, interprete o JSON e confira id, project_id, reference e sandbox com os seus registos. Para um pedido real, espera-se sandbox=false. Se guardou um preço em invoice_currency e invoice_amount, verifique também esses campos. Uma fatura alheia ao pedido ou um registo de outro modo não devem alterar o pedido.
O link checkout_url de GET destina-se à consulta. Não substitua por ele o link interativo guardado da resposta de criação da fatura: consultar o estado não cria um novo pagamento nem fornece um novo checkout interativo.
Passo 2. Distinga a espera do pagamento concluído
Tome a decisão com base no status da fatura:
pending— aguarda-se o pagamento;seen— foi detetada uma transferência, mas o pagamento ainda não está concluído;partial— parte do montante está confirmada e a espera continua segundo as regras do pagamento;underpaid,overpaid,late— é necessária análise; tenha em contaneeds_decisione a decisão do vendedor;paid— a fatura está registada como paga; depois de confirmar a relação com o pedido, pode preparar a execução;expired,canceled— termine a espera ativa do comprador, mas conserve o registo para conciliação posterior.
O fim do prazo não exclui uma receção tardia. Uma decisão manual e uma reversão da transação também podem alterar o tratamento posterior. Não declare um estado definitivamente final nem elimine a relação entre pedido e fatura quando a página é fechada.
Uma transação confirmada e uma fatura paga são coisas diferentes. As confirmações não provam que o ativo, o montante e os dados de pagamento exigidos correspondem àquele pedido concreto. O guia de diagnóstico de um pedido por pagar explica estas diferenças.
Passo 3. Considere o montante e a tentativa de pagamento
Ao mudar o método de pagamento, uma fatura pode passar a ter várias tentativas. Para uma fatura paga, considere settled_attempt_id e settled_attempt. Ao analisar o histórico, verifique attempt_history.has_more e o cursor de continuação; utilize payment_history para as transferências da tentativa selecionada. A primeira página não contém necessariamente todo o histórico.
amount é o montante exato em criptomoeda a enviar. amount_raw e paid são cadeias com valores inteiros nas unidades mínimas do ativo; decimals define a escala. Não os compare como números de vírgula flutuante nem por ordem alfabética, como cadeias comuns. A sua própria verificação do montante não deve substituir o estado da fatura e as regras do projeto: um pagamento em excesso pode ser aceite ou enviado para análise. Também não deve somar pagamentos insuficientes sem verificar as condições.
Passo 4. Limite o polling e as repetições
Coloque as verificações numa fila do servidor com concorrência limitada. Vários separadores do comprador não devem criar ciclos de consulta independentes. Considere o tráfego conjunto da conta: as diferentes chaves API e os modos partilham a quota. Os limites atuais constam da referência da API.
Escolha os intervalos de espera de acordo com o seu processo, deixando margem para outros pedidos. Perante um erro de rede ou HTTP 500/503, utilize repetições limitadas com espera crescente e variação aleatória. Para HTTP 429, reduza o tráfego conjunto; se receber Retry-After, respeite a pausa indicada. A ausência desse cabeçalho não deve provocar uma repetição imediata. Cada pedido deve ter um tempo limite, e cada série de repetições, um limite após o qual a tarefa permaneça disponível para análise posterior.
HTTP 401/403 exigem a verificação da chave e das permissões. Para 404, confira o ID, o projeto e o modo: as restrições de acesso podem ocultar uma fatura. Estes erros não significam que o cliente não pagou nada.
Passo 5. Guarde a execução e a recuperação
Quando o estado for paid, guarde de forma coerente o estado do pedido e a tarefa de execução. Utilize uma chave única de pedido e proteção contra processamento simultâneo. Consultar paid novamente não deve entregar o acesso ou o produto uma segunda vez; uma falha após a entrega não deve gerar outra execução.
Conserve a última verificação bem-sucedida e a próxima tarefa num armazenamento persistente. Após um reinício, retome verificações e tarefas inacabadas em vez de iniciar o processo apenas quando a página é aberta. Limite a espera ativa pelos prazos do seu processo; uma conciliação separada em segundo plano deve considerar pagamentos tardios, decisões e reversões, incluindo pedidos anteriormente pagos. Antes de uma entrega ainda pendente, confirme novamente que continua autorizada; preveja a revisão de acessos já concedidos.
Com respostas preparadas, verifique a repetição de paid, um tempo limite excedido, um reinício e uma transição após uma reversão. O resultado é correto quando o pedido é executado uma vez e um pagamento incerto ou contestado permanece em análise. Mais tarde, pode complementar o polling com um webhook, mantendo a mesma proteção de execução.