Integrações

Botão de pagamento em cripto para sites

Como adicionar um botão «Pagar com cripto» a um site: por que o botão não pode chamar a API de pagamentos diretamente, o padrão de três passos, código funcional de front-end e servidor, e o que proteger.

Um botão «Pagar com cripto» é fácil de adicionar, mas não pode ser um trecho para copiar e colar: criar um pagamento exige sua chave de API secreta, que nunca deve chegar ao navegador. O botão precisa, portanto, falar com o seu próprio servidor, que cria o pagamento e devolve o endereço da página de pagamento. Este guia mostra esse padrão com código funcional e os pontos que o mantêm seguro.

Por que ainda não há um botão para copiar e colar

Muitos provedores de pagamento oferecem um botão ou widget incorporável. A Qvard ainda não tem botão sem código: os links de pagamento estão em desenvolvimento. O checkout incorporado já está pronto para o seu site. Os SDKs estão prontos. Hoje a integração é pela API, e a API se autentica com uma chave secreta no cabeçalho Authorization: Bearer.

Essa chave pode criar pagamentos do seu projeto, então deve ficar no seu servidor. Um botão que levasse a chave em código de front-end a entregaria a cada visitante. Não é uma limitação a contornar; é o motivo de o padrão abaixo ter uma etapa no servidor.

O padrão: botão, seu endpoint, página de pagamento

Três passos formam um botão que funciona:

  1. O botão envia uma requisição a um endpoint do seu servidor, dizendo o que o visitante quer comprar (um produto, um plano), não quanto custa.
  2. Seu endpoint busca o preço, cria seu próprio registro de pedido e chama a Qvard: um POST para https://api.qvard.com/api/v1/payment com a chave no cabeçalho Authorization: Bearer e um JSON com o número do pedido como id e o valor como price em dólares americanos. A resposta é 201 com um redirectUrl.
  3. O navegador é redirecionado para esse redirectUrl, a página de pagamento hospedada da Qvard, onde o visitante escolhe um ativo e uma rede e paga de uma carteira.

Nada secreto toca a página, e a própria página de pagamento é hospedada pela Qvard, então você não constrói um checkout cripto.

O front-end: um botão e um redirecionamento

O botão precisa de cerca de quinze linhas. Ele se desativa enquanto a requisição roda, envia o identificador do produto e, em caso de sucesso, leva o navegador ao endereço devolvido. Em caso de falha, volta a ficar ativo e mostra uma mensagem, para o visitante tentar de novo.

Tenha em mente uma regra: o navegador envia o que é comprado, nunca quanto. Se o valor viesse da página, qualquer um poderia abrir as ferramentas de desenvolvedor e transformar um plano de 49 dólares em um pagamento de um dólar.

HTML + JSpay-button.html
<button id="pay-crypto" data-product="pro-plan">Pay with crypto</button>

<script>
  document.getElementById('pay-crypto').addEventListener('click', async (event) => {
    const button = event.currentTarget;
    button.disabled = true;
    try {
      // Send only WHAT is being bought; the server decides the price.
      const res = await fetch('/api/crypto-checkout', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ product: button.dataset.product })
      });
      if (!res.ok) throw new Error('checkout failed');
      const { redirectUrl } = await res.json();
      window.location.assign(redirectUrl);   // the Qvard hosted payment page
    } catch (e) {
      button.disabled = false;
      alert('Could not start the payment. Please try again.');
    }
  });
</script>

O servidor: preço, pedido, pagamento

O endpoint do exemplo faz quatro coisas:

  • Busca o preço em uma tabela no servidor e rejeita produtos desconhecidos.
  • Cria o seu pedido e usa o número dele como id do pagamento. É assim que o webhook depois encontra o pedido.
  • Chama a Qvard e devolve ao navegador apenas o redirectUrl. Uma resposta 400 («Error validation», com uma mensagem por campo) significa que o corpo estava errado; um 401 significa que a chave está errada. Nenhum dos dois deve ser repetido sem mudança.
  • É seguro repetir. Enviar o mesmo id para o mesmo método de pagamento devolve o pagamento existente, então um visitante que clica duas vezes não cria dois.

Adicione limitação de taxa ao endpoint para que ninguém consiga criar milhares de pedidos sem pagar, e exija usuário logado ou captcha se o seu produto precisar.

Node.jscrypto-checkout.js
import express from 'express';
import crypto from 'node:crypto';

const app = express();
const PRICES_USD = { 'pro-plan': 49 };          // prices live on the server, never in the browser

app.post('/api/crypto-checkout', express.json(), async (req, res) => {
  const price = PRICES_USD[req.body.product];
  if (!price) return res.sendStatus(400);

  const orderId = await db.orders.create({ product: req.body.product, amountUsd: price }); // your own order number

  const response = await fetch('https://api.qvard.com/api/v1/payment', {
    method: 'POST',
    headers: { Authorization: 'Bearer ' + process.env.QVARD_API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ id: String(orderId), price })
  });
  if (response.status !== 201) return res.sendStatus(502);

  const { redirectUrl } = await response.json();
  res.json({ redirectUrl });
});

Depois do clique: o webhook decide

Redirecionar o visitante para a página de pagamento inicia o pagamento; não o conclui. Quando o pagamento é concluído, a Qvard chama a callback URL salva no seu projeto com o seu id e o estado completed. Só então conceda o acesso ou marque o pedido como pago. O endpoint deve responder exatamente HTTP 200 e ser seguro se executar duas vezes; veja como proteger webhooks de pagamentos em cripto.

Ainda não há URLs de retorno após o pagamento, então o visitante volta ao seu site por conta própria. Dê a ele uma página que mostre o estado real do pedido e se atualize enquanto espera, não uma página de agradecimento que presume sucesso.

Preços fixos, valores variáveis e o que vem a seguir

  • Preços fixos (planos, produtos) são o caso fácil: a tabela do servidor os guarda.
  • Valores variáveis (doações, recargas) precisam de validação no servidor: um mínimo, um máximo e uma checagem numérica. Um valor abaixo do mínimo do método de pagamento escolhido é rejeitado com um 400.
  • Vários botões compartilham o mesmo endpoint; só muda o identificador do produto.

O passo a passo completo está em como aceitar pagamentos em cripto em um site, e a API em API de pagamentos em cripto para desenvolvedores. Uma fatura de demonstração mostra a página para onde o botão leva; as condições comerciais estão na página de preços.

FAQ

Posso colocar a chave de API da Qvard no código do botão?

Não. A chave pode criar pagamentos do seu projeto e deve ficar no seu servidor. O botão deve chamar o seu próprio endpoint, que chama a Qvard.

Existe um widget incorporável ou um botão sem código?

Sim, o checkout incorporado já é um widget pronto para o seu site. Botão sem código ainda não há: os links de pagamento estão em desenvolvimento. Os SDKs estão prontos. Hoje a integração usa a API com um pequeno endpoint no servidor.

De onde deve vir o preço?

Do seu servidor, nunca do navegador. O botão envia apenas o que é comprado, e o servidor decide o preço em dólares americanos.

Como sei que o cliente pagou?

Pelo webhook que a Qvard envia quando o pagamento é concluído. O visitante voltar ao seu site não é prova de pagamento.

Artigos relacionados

Artigos relacionados