Source: https://cryptanio.com/pt/wiki/confirmar-pagamento-de-pedido-por-webhook/
Language: pt

# Como confirmar automaticamente o pagamento de um pedido por webhook

Vincule a fatura ao pedido\, verifique a assinatura do webhook e proteja a entrega contra repetições\, pagamentos insuficientes e reversões\.

Atualizado: 2026-11-14

Para que o site marque um pedido como pago automaticamente\, crie uma [fatura](<https://cryptanio.com/pt/wiki/o-que-e-uma-fatura/>) para ele no Cryptanio e configure um [webhook](<https://cryptanio.com/pt/wiki/o-que-e-um-webhook/>)\: uma notificação que o serviço envia ao seu servidor quando o estado do pagamento muda\. O servidor verifica a autenticidade da mensagem\, encontra o pedido e confere o estado da fatura\. Depois disso\, pode liberar o acesso comprado ou encaminhar o pedido para execução\.

Vamos usar o exemplo de uma loja que cria uma fatura em dólares americanos como unidade de cálculo\, enquanto o comprador escolhe a criptomoeda e a rede disponíveis na página de pagamento\. Os fundos chegam aos endereços da loja\. Os pedidos e a entrega do produto continuam no aplicativo da loja\, enquanto o Cryptanio associa a fatura à transferência e informa seu estado\. Para essa integração\, será necessário um desenvolvedor ou a possibilidade de alterar a parte do site executada no servidor\.

## Prepare o projeto e os endereços para pagamento {#prepare-o-projeto-e-os-endere-os-para-pagamento}

No painel do Cryptanio\, escolha um projeto e adicione endereços de recebimento que pertençam a você\. Conecte\-os ao serviço Payments\: apenas monitorar um endereço não é suficiente para emitir faturas\. Certifique\-se de que os endereços estejam ativos e correspondam à rede escolhida\. Para pagamentos reais\, são necessários endereços do modo de produção\, live\.

Prepare vários endereços se os clientes puderem pagar pedidos ao mesmo tempo\. Um endereço pode estar ocupado por uma fatura aberta ou ficar temporariamente indisponível após o encerramento dela\. A integração deve mostrar um erro claro quando não houver endereço livre e permitir uma nova tentativa mais tarde\.

Crie uma chave de API e salve\-a no servidor da loja\. Ela será necessária para as chamadas a ` https://api.cryptanio.com/v1 `\. A chave não pode ser colocada no JavaScript da página\, em um aplicativo móvel nem em um repositório público\.

## Configure o endereço de recebimento das notificações {#configure-o-endere-o-de-recebimento-das-notifica-es}

Abra as “Notificações” do projeto escolhido\. Se “Usar configurações de notificação de conta” estiver habilitado\, configure Webhook em “Configurações da conta”\, ou desative a herança e defina o endereço próprio do projeto\.

No cartão Webhook\, informe o endereço HTTPS do receptor em “URL do ponto final” e clique em “Salvar”\. O receptor deve aceitar solicitações POST diretamente\: não é utilizado redirecionamento para outra URL\. Obtenha o “Segredo de assinatura” no mesmo cartão e guarde\-o no servidor\, separado da chave de API\.

Confirme que Webhook não está pausado\. Trate ` payment.confirmed ` e ` payment.rolled_back ` no receptor e use ` payment.pending ` para um estado intermediário\, se necessário\. Antes de executar o pedido\, confira o modo real e as demais condições abaixo\. Não é preciso ativar um canal Webhook separado para o endereço da fatura\.

## Crie uma fatura para um pedido específico {#crie-uma-fatura-para-um-pedido-espec-fico}

Primeiro\, salve o pedido no banco de dados da loja\. Em seguida\, o servidor cria uma fatura por ` POST /v1/invoices `\. Em ` reference `\, envie seu identificador do pedido\. Neste exemplo\, o preço do pedido é 12\.50 USD\: ` invoice_currency ` e ` invoice_amount ` definem o preço\, enquanto o comprador escolhe a rede e o ativo disponíveis na página de pagamento\. Por isso\, ` chain `\, ` asset `\, ` amount `\, ` address ` e ` tolerance ` não são enviados nessa solicitação\. Informar USD não significa receber dinheiro fiduciário nem converter a criptomoeda recebida em dólares\.

```bash
#!/usr/bin/env bash
set -euo pipefail
: "${CRYPTANIO_API_KEY:?Set CRYPTANIO_API_KEY}"
: "${CRYPTANIO_OPERATION_ID:?Set CRYPTANIO_OPERATION_ID}"
: "${CRYPTANIO_PROJECT_ID:?Set CRYPTANIO_PROJECT_ID}"
json_string() {
  local text="$1" char code index output='"'
  for ((index=0; index<${#text}; index++)); do
    char="${text:index:1}"
    case "$char" in
      '"'|'\') output+="\\$char" ;;
      *) printf -v code '%d' "'$char"
         if ((code < 32)); then printf -v char '\\u%04x' "$code"; fi
         output+="$char" ;;
    esac
  done
  printf '%s"' "$output"
}
response_file="$(mktemp)"
trap 'rm -f "$response_file"' EXIT
transfer_status=0
http_status="$(curl \
  --silent --show-error --max-time 30 --request POST \
  --header "Authorization: Bearer $CRYPTANIO_API_KEY" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header "Idempotency-Key: $CRYPTANIO_OPERATION_ID" \
  --data-binary '{"project":'"$(json_string "$CRYPTANIO_PROJECT_ID")"',"invoice_currency":"USD","invoice_amount":"12.50","reference":"order-42"}' \
  "https://api.cryptanio.com/v1/invoices" \
  --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
```

[Transferir exemplo](</wiki/examples/ace23bd7c3cba0e47dafdcd6075a506ddb2ec8d6581c6129af815c1558f5a8fc.sh>)

Antes de executar\, defina no servidor ` CRYPTANIO_API_KEY `\, ` CRYPTANIO_PROJECT_ID ` e ` CRYPTANIO_OPERATION_ID `\. Use uma chave de API de produção com permissão para criar faturas\; ` CRYPTANIO_PROJECT_ID ` deve apontar para o projeto Payments preparado\. ` CRYPTANIO_OPERATION_ID ` é o identificador salvo da operação de criação para esse pedido\: de 16 a 80 letras latinas ASCII\, números\, hífens ou sublinhados\. O exemplo o envia no cabeçalho ` Idempotency-Key `\, não em um campo JSON\. Para um novo pedido\, crie outro valor\; para repetir a mesma solicitação\, mantenha o anterior\.

Se a criação for bem\-sucedida\, a API retorna HTTP 201\. Salve o ` id ` da fatura e a ` checkout_url ` recebida junto ao pedido e encaminhe o comprador para esse link\. Enquanto a forma de pagamento não for escolhida\, a rede\, o endereço e o valor em criptomoeda ainda não estarão definidos\. Na página de pagamento\, o comprador escolhe uma opção disponível e recebe os dados atualizados e o prazo para pagar\. Se você exibir os dados de pagamento na própria interface\, use os dados da tentativa específica\, o valor exato de ` amount ` e o prazo ` expires_at `\; não arredonde o valor nem o substitua por ` asked `\. Os links de consultas GET posteriores e da lista de faturas são destinados à visualização\; guarde separadamente o link interativo recebido na resposta de criação e compartilhe\-o apenas com o comprador correspondente\.

Se a conexão cair após o envio da solicitação\, reenvie o mesmo corpo com a mesma ` Idempotency-Key `\. Uma repetição bem\-sucedida retorna HTTP 201 e o mesmo ` id `\. Alterar os parâmetros com uma chave já utilizada causa HTTP 409\. ` reference ` associa a fatura ao pedido\, mas não substitui a chave de criação única\. Não altere a chave apenas por causa de um tempo limite excedido\.

## Verifique a autenticidade do webhook recebido {#verifique-a-autenticidade-do-webhook-recebido}

O Cryptanio envia ` X-Timestamp `\, ` X-Signature `\, ` X-Event-Id `\, ` X-Event-Type ` e ` X-Attempt `\. A assinatura é calculada assim\:

```text
hex(HMAC-SHA256(secret, timestamp + "." + raw_body))
```

` raw_body ` são os bytes originais da solicitação\. Obtenha\-os antes de interpretar o JSON\: serializá\-lo novamente pode alterar os espaços ou a ordem dos campos e invalidar a verificação\. Limite o tamanho permitido para o corpo e rejeite solicitações sem uma assinatura válida\.

O exemplo abaixo usa uma janela de validade de cinco minutos\. Essa é uma configuração do seu receptor\; para funcionar corretamente\, o relógio do servidor precisa estar sincronizado\.

```python
import hashlib
import hmac
import re
import time

def verify_signature(secret, timestamp, raw_body, signature):
    if not secret or not timestamp or not re.fullmatch(r"[0-9]{1,12}", timestamp):
        return False
    if not signature or not re.fullmatch(r"[0-9a-f]{64}", signature):
        return False
    if abs(time.time() - int(timestamp)) > 300:
        return False
    signed = timestamp.encode("ascii") + b"." + raw_body
    expected = hmac.new(secret.encode("utf-8"), signed,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)
```

A função verifica a assinatura e o horário da solicitação\. Depois de uma verificação bem\-sucedida\, interprete o JSON e confirme ` schema_version="v1" `\, a ` project_id ` esperada\, ` mode="live" ` e ` sandbox=false `\.

Para tomar decisões\, use ` event_id ` e ` event_type ` do corpo assinado\. Os cabeçalhos com os mesmos nomes podem ser comparados a esses valores\; esses cabeçalhos\, por si só\, não são protegidos pela assinatura\. Execute a lógica de pagamento apenas para o objeto ` payment ` esperado\, com a direção ` in `\.

## Separe a confirmação da transferência do pagamento do pedido {#separe-a-confirma-o-da-transfer-ncia-do-pagamento-do-pedido}

Os principais eventos para a loja são\:

- ` payment.pending ` — a transferência foi detectada e ainda aguarda confirmação\;
- ` payment.confirmed ` — a transferência atingiu as confirmações necessárias\;
- ` payment.rolled_back ` — uma transferência detectada anteriormente foi revertida devido a uma mudança na blockchain\.

O evento ` payment.confirmed ` ainda não significa que um pedido específico foi totalmente pago\. Verifique o objeto ` invoice ` e compare ` invoice.id ` e ` invoice.reference ` com o pedido salvo\. Uma mensagem sem uma fatura vinculada não pode ser atribuída automaticamente a uma compra apenas por ter um valor semelhante\.

Antes da entrega\, consulte o estado atual por ` GET /v1/invoices/{id} `\. Confira ` id `\, ` project_id `\, ` reference `\, o preço do pedido em ` invoice_currency ` e ` invoice_amount `\, além de ` sandbox=false `\. Verifique a rede\, o ativo\, o endereço e a tentativa de pagamento escolhida\; se houver várias tentativas\, considere ` settled_attempt_id ` e ` settled_attempt `\. Um pagamento bem\-sucedido corresponde ao status de fatura ` paid `\; ` pending `\, ` seen ` e ` partial ` ainda não autorizam a entrega\. O retorno do comprador ao site ou a abertura do link de pagamento não confirmam o pagamento\.

Para pagamentos inferiores ao valor devido\, existe ` underpaid `\; para um pagamento parcial com espera pelo restante\, ` partial `\; para entradas atrasadas\, ` late `\. Em caso de pagamento excedente\, a política do projeto pode manter a fatura em ` paid ` ou definir ` overpaid ` com ` needs_decision=true `\. Os estados ` underpaid `\, ` overpaid ` e ` late ` exigem uma decisão separada antes da entrega do pedido\. Os campos ` amount_raw ` e ` paid ` chegam como strings\. Para a comparação\, interprete\-os como valores inteiros exatos nas unidades mínimas do ativo\; ` decimals ` define a escala\. Não compare as strings lexicograficamente nem use ponto flutuante binário\. Defina previamente as regras para tratar a diferença\; isso não implica uma devolução automática dos fundos\.

## Trate repetições e reversões {#trate-repeti-es-e-revers-es}

A entrega admite mensagens repetidas\. Salve o evento verificado em armazenamento persistente e use ` event_id ` como chave única\. Uma repetição de um evento já aceito deve receber uma resposta de sucesso sem provocar outra entrega do produto\.

Apenas o identificador da transação não basta para descartar todas as mensagens posteriores\: a transferência passa por estados diferentes\. Para a combinação de ` chain `\, ` tx_id `\, ` index `\, ` address ` e a identidade do ativo\, mantenha a última ` payment.revision ` aplicada\. Aplique a transição somente se a revision for maior que a já processada\.

Registre a alteração do pedido e a criação da tarefa de entrega de forma consistente\, com proteção contra processamento paralelo\. A tarefa deve ter uma chave única do pedido\. Imediatamente antes da execução\, verifique se a entrega do pedido ainda está autorizada\. Se chegar uma reversão\, atualize o estado e interrompa a entrega ainda não executada\; para um acesso já liberado\, preveja uma revisão ou suspensão\.

## Verifique todo o fluxo {#verifique-todo-o-fluxo}

Antes de um pagamento real\, teste a leitura do corpo\, a assinatura e a proteção contra duplicatas com dados preparados\. Um evento de serviço ` webhook.test ` não confirma uma compra nem substitui a verificação do fluxo completo\.

Depois\, confira todo o processo com um pedido de controle próprio\: criação da fatura\, transferência\, confirmação e atualização do pedido\. Teste separadamente a repetição de um evento\, um pagamento inferior ao devido e uma reversão com dados preparados\. Retorne HTTP 2xx depois de salvar de forma confiável a mensagem aceita\; se houver uma impossibilidade temporária de salvá\-la\, use um erro de servidor para permitir uma nova tentativa de entrega\.

No painel\, compare o evento e o registro de entrega com o registro no seu aplicativo\. A verificação termina quando o pedido confirmado é executado uma única vez e um evento intermediário\, alheio ao pedido ou repetido não provoca uma entrega indevida\.

Referência\: [faturas da API v1](<https://cryptanio.com/ru/docs.html#invoices>)\, [verificação da assinatura do webhook](<https://cryptanio.com/ru/docs.html#verify>)\.

Etiquetas: [Pagamentos](https://cryptanio.com/pt/wiki/tag/payments/), [Webhooks](https://cryptanio.com/pt/wiki/tag/webhooks/)

## Artigos relacionados

- [O que é uma fatura de pagamento](https://cryptanio.com/pt/wiki/o-que-e-uma-fatura/)
- [O que é um webhook](https://cryptanio.com/pt/wiki/o-que-e-um-webhook/)
- [Como receber pagamentos em criptomoedas em um bot do Telegram](https://cryptanio.com/pt/wiki/receber-pagamentos-cripto-bot-telegram/)
