Aceitar pagamentos cripto

Como aceitar pagamentos cripto em um site

Passo a passo: crie um pagamento no seu servidor, envie o cliente à página de pagamento, trate o webhook e teste. Com código Node.js funcional.

Para aceitar cripto em um site, você precisa de duas coisas no servidor: uma chamada que cria um pagamento para um pedido e um endpoint que recebe o resultado. Este guia percorre as duas com código funcional e depois trata de testes, casos atípicos e dos erros que custam dinheiro aos lojistas.

O que você precisa antes de começar

Você não precisa rodar um nó de blockchain nem guardar carteiras de clientes. Você precisa de:

  • uma conta no gateway com um projeto, uma chave de API e, se quiser definir o método de pagamento, o ID desse método no seu projeto;
  • um endpoint HTTPS público no seu servidor para o webhook, salvo no projeto como callback URL;
  • um lugar no seu sistema de pedidos para guardar o estado do pagamento, associado pelo seu próprio número de pedido.

Decida uma coisa logo: se o cliente escolhe o ativo e a rede na página de pagamento ou se você os pré-seleciona. Deixar o cliente escolher é mais simples e serve à maioria das lojas. Se você passar um método de pagamento, a página abre com ele já selecionado.

Como todo o fluxo se encaixa

Este é o caminho de um pedido, do seu checkout até o status de pago:

  1. O cliente escolhe «Pagar com cripto» no checkout e o seu servidor cria um pagamento para esse pedido.
  2. O gateway devolve um link para a sua página de pagamento hospedada.
  3. Você redireciona o cliente para essa página. Ele escolhe um ativo e uma rede e envia o valor exato da sua própria carteira.
  4. O gateway observa a blockchain e, quando o pagamento é definitivo, chama o seu webhook.
  5. O seu webhook marca o pedido como pago e inicia o envio do pedido.

Repare no que nunca acontece do seu lado: você não gera endereços, não varre blocos nem compara valores. O seu código faz duas tarefas pequenas: criar o pagamento e reagir ao status final.

Passo 1: crie o pagamento no seu servidor

Chame o gateway a partir do seu backend, nunca do navegador, porque a requisição leva a sua chave de API secreta. Na Qvard é um único POST para https://api.qvard.com/api/v1/payment com a sua chave no cabeçalho x-api-key e um corpo JSON:

  • id: o seu próprio número de pedido, como string. Ele volta para você depois no webhook, então use algo que você consiga localizar.
  • price: o valor em dólares americanos. O cliente paga o equivalente no ativo que escolher.
  • paymentSystemId (opcional): o ID de um método de pagamento do seu projeto, para pré-selecionar ativo e rede.

Em caso de sucesso, a resposta é 201 com um id de pagamento e um redirectUrl. Enviar o mesmo id de novo para o mesmo método de pagamento devolve o pagamento existente em vez de criar um duplicado, então é seguro tentar de novo após um timeout.

Se a requisição estiver errada, você recebe 400 com o texto Error validation e uma mensagem por campo; um valor abaixo do mínimo do método escolhido é rejeitado da mesma forma. Uma chave ausente ou errada retorna 401.

Node.jscreate-payment.js
// Called from your checkout handler when the customer chooses "Pay with crypto".
async function createQvardPayment(order) {
  const res = await fetch('https://api.qvard.com/api/v1/payment', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.QVARD_API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      id: String(order.id),        // your order number, also used to match the webhook
      price: order.totalUsd        // amount in US dollars
    })
  });

  if (!res.ok) throw new Error('Qvard ' + res.status + ' ' + (await res.text()));

  const { redirectUrl } = await res.json();
  return redirectUrl;              // send the customer to this page
}

Passo 2: envie o cliente à página de pagamento

Redirecione o cliente para o redirectUrl, que tem a forma https://my.qvard.com/pay/<id do pagamento>. Nessa página ele escolhe o ativo e a rede, vê o valor exato e o endereço e paga da sua carteira. A taxa de câmbio fica fixada por uma hora, então o valor não muda enquanto ele paga.

Duas coisas para planejar:

  • A volta. As URLs de retorno após o pagamento ainda não estão disponíveis, então o cliente volta ao seu site por conta própria. Dê a ele uma página de pedido que mostre o status atual e que se atualize quando o seu webhook chegar.
  • Não trate a volta como pagamento. Um cliente que voltou ao seu site não necessariamente pagou. Só o webhook diz que o dinheiro chegou.

Passo 3: receba o webhook

Quando um pagamento é concluído, a Qvard envia um POST para a callback URL do seu projeto com um JSON pequeno: o id que você enviou e o status do pagamento. A requisição leva a sua chave de API no cabeçalho x-api-key. É um cabeçalho de autenticação, não uma assinatura criptográfica, então compare-o com a sua chave e rejeite todo o resto.

O modo como a entrega funciona importa para o seu manipulador:

  • A Qvard considera o webhook entregue apenas quando o seu endpoint responde exatamente HTTP 200. Qualquer outro status ou um timeout conta como falha.
  • Uma entrega que falhou é reenviada: cinco tentativas no total, em cerca de seis minutos.
  • Redirecionamentos não são seguidos, então uma resposta 3xx também é falha.
  • Você também pode reenviar a notificação de um pagamento pelo painel.

Por causa das novas tentativas, o seu manipulador precisa ser idempotente: ver o mesmo evento duas vezes não pode enviar o pedido duas vezes. O exemplo abaixo verifica a chave, encontra o pedido pelo seu id e o marca como pago apenas se ainda não estiver pago.

Node.jswebhook.js
import crypto from 'node:crypto';
import express from 'express';

const app = express();

app.post('/webhooks/qvard', express.json(), async (req, res) => {
  // Qvard sends your API key in the x-api-key header: compare it with yours.
  const received = Buffer.from(String(req.get('x-api-key') || ''));
  const expected = Buffer.from(process.env.QVARD_API_KEY);
  const valid = received.length === expected.length && crypto.timingSafeEqual(received, expected);
  if (!valid) return res.sendStatus(401);

  const { id, status } = req.body;          // id is the order number you sent
  const order = await db.orders.findById(id);
  if (!order) return res.sendStatus(200);   // unknown order: nothing to retry

  if (status === 'completed' && order.state !== 'paid') {
    await markOrderPaid(order);             // safe to run twice: the check above skips repeats
  }

  return res.sendStatus(200);               // must be exactly 200, otherwise Qvard retries
});

Trate os pagamentos fora do padrão

Um pagamento tem um de quatro status:

  • wait: criado, aguardando o cliente.
  • partial: o cliente enviou menos do que o necessário.
  • completed: o valor total chegou; é o que dispara o webhook.
  • rejected: o pagamento foi rejeitado.

Decida com antecedência o que a sua loja faz em cada caso. Para partial, a escolha usual é manter o pedido aberto e pedir ao cliente que envie o restante, ou reembolsá-lo. Mantenha a lógica simples: marque um pedido como pago apenas com completed e mostre ao cliente uma mensagem clara nos demais estados.

Teste antes de ir ao ar

Um plano de testes curto que pega a maioria dos problemas:

  1. Abra uma fatura de demonstração para ver a página de pagamento como o seu cliente a verá.
  2. Crie um pagamento no seu servidor e confirme que recebe um redirectUrl.
  3. Pague um valor real pequeno e confirme que o webhook chega e que o pedido fica pago.
  4. Faça o seu endpoint retornar um erro uma vez, confirme que a Qvard tenta de novo e que o seu manipulador não processa o pedido duas vezes.
  5. Saque um valor pequeno do seu saldo para a sua carteira para saber que todo o caminho funciona.

A Qvard ainda não tem um sandbox separado; um sandbox está no roteiro, então use valores reais pequenos nos passos 3 a 5.

Lista de segurança

  • Guarde a chave de API apenas no servidor. Nunca a coloque em código de front-end ou em um repositório público.
  • Compare o cabeçalho x-api-key em cada webhook e rejeite divergências, usando uma comparação em tempo constante.
  • Sirva o endpoint por HTTPS e mantenha-o rápido; faça o trabalho lento depois de responder.
  • Associe pagamentos a pedidos pelo seu próprio id e ignore eventos de pedidos que você não conhece.
  • Registre cada webhook com o seu status, para poder resolver disputas depois.

Mais sobre o tema em como proteger webhooks de pagamentos cripto.

E o WooCommerce, a Shopify ou outra plataforma?

Valem as mesmas duas chamadas: o código da sua plataforma cria o pagamento e recebe o webhook. A Qvard ainda não tem um plugin pronto, então em uma plataforma como o WooCommerce a integração é um pequeno trecho de código próprio ou uma hora de um desenvolvedor, não uma instalação com um clique. Veja integrações para saber em que pé está, e a página para desenvolvedores para a referência da API. Se você quer primeiro o panorama geral, comece por o que é um gateway de pagamento cripto.

FAQ

Preciso saber desenvolver para blockchain?

Não. Você faz uma requisição HTTP para criar um pagamento e trata um webhook. Endereços, monitoramento da rede e confirmações ficam por conta do gateway.

Posso aceitar cripto sem escrever código?

Ainda não com a Qvard. Links de pagamento e outras formas sem código de receber estão em desenvolvimento; hoje a integração é pela API, que exige um desenvolvedor.

E se o meu servidor estiver fora do ar quando o pagamento for concluído?

A notificação é reenviada cinco vezes em cerca de seis minutos. Se o seu servidor ficou fora do ar por mais tempo, reenvie a notificação desse pagamento pelo painel e concilie a partir daí.

Em qual moeda defino o preço?

Em dólares americanos. O cliente paga o equivalente no ativo e na rede que escolher na página de pagamento, a uma taxa fixada por uma hora.

Artigos relacionados

Artigos relacionados