Integrações

Pagamentos em cripto para backends próprios

Um passo a passo independente de stack para integrar a Qvard ao seu próprio servidor: o modelo de pedido, criar o pagamento, o webhook, a conciliação e uma lista de verificação para entrar no ar, com exemplos em Python.

Se sua loja, serviço ou plataforma roda no seu próprio backend, você não precisa de um plugin: a Qvard precisa de uma chamada que cria um pagamento e de um endpoint que recebe o resultado. Este guia percorre a integração de um modo que serve a qualquer linguagem e framework, com exemplos em Python, e cobre o que a torna confiável: o modelo de pedido, a idempotência, a conciliação e uma breve lista de verificação para entrar no ar.

O que você precisa

  • Uma conta Qvard com um projeto, uma chave de API e a callback URL do seu webhook salva no projeto.
  • Um endpoint HTTPS público no seu servidor para o webhook.
  • Uma tabela de pedidos (ou equivalente) em que um pagamento possa ser associado a um pedido pelo seu próprio identificador.

Ainda não há SDK nem sandbox: a integração é HTTP simples e os testes são feitos com pequenos valores reais. A referência dos formatos de requisição é API de pagamentos em cripto para desenvolvedores; este guia mostra como eles se encaixam.

Um modelo de pedido mínimo

Seus próprios dados definem o quão limpa é a integração. Um conjunto mínimo de campos de um pedido:

  • id: o número do seu pedido ou fatura. É o id que você envia à Qvard e a chave que volta no webhook.
  • amount_usd: o valor em dólares americanos, a unidade em que o pagamento é criado.
  • state: por exemplo awaiting_payment, paid, cancelled. Marque como pago somente a partir do webhook.
  • paid_at e, se quiser, o id do pagamento da Qvard vindo da resposta, para o suporte.

Evite colocar toda a lógica de pagamento na classe do pedido. Um módulo pequeno que cria o pagamento e um endpoint que aplica o webhook mantêm o código testável.

Criar o pagamento

Quando o cliente escolhe pagar, crie o pagamento a partir do seu backend com um único POST para https://api.qvard.com/api/v1/payment. Envie a chave no cabeçalho Authorization: Bearer e um JSON com o número do pedido como id (uma string), o valor como price em dólares americanos e, opcionalmente, um paymentSystemId para abrir a página de pagamento com um ativo e uma rede selecionados.

A resposta é 201 com redirectUrl, o endereço da página de pagamento hospedada. Redirecione o cliente para lá, ou coloque o link em um e-mail. Regras que valem a pena codificar no cliente:

  • Timeout e nova tentativa. Use um timeout e repita em caso de timeout ou 5xx. Enviar o mesmo id para o mesmo método de pagamento devolve o pagamento existente, então uma repetição não pode criar um segundo.
  • Não repita um 400 («Error validation», com uma mensagem por campo) nem um 401 (chave errada) sem mudar algo.
  • Valores em dólares. Se sua loja define preços em outra moeda, converta antes da chamada.
Pythonqvard_client.py
import os
import requests

QVARD_URL = "https://api.qvard.com/api/v1/payment"

def create_payment(order_id: str, amount_usd: float) -> str:
    """Create a Qvard payment for an order and return the hosted payment page URL."""
    response = requests.post(
        QVARD_URL,
        headers={"Authorization": "Bearer " + os.environ["QVARD_API_KEY"]},
        json={"id": order_id, "price": amount_usd},   # id as a string, price in US dollars
        timeout=15,
    )
    if response.status_code == 201:
        return response.json()["redirectUrl"]
    # 400 = "Error validation" with a per-field message, 401 = wrong API key
    raise RuntimeError(f"Qvard {response.status_code}: {response.text}")

Receber o webhook

Quando um pagamento é concluído, a Qvard envia um POST para a sua callback URL com o id e o status, assinado no cabeçalho X-Qvard-Signature. Seu endpoint deve:

  1. Verificar a assinatura: HMAC-SHA256 com a sua chave secreta sobre o timestamp e o corpo bruto, comparada em tempo constante; se não coincidir, responder 400.
  2. Agir somente no estado completed.
  3. Atualizar o pedido de forma condicional, «pago se ainda aguarda pagamento», para que repetições não façam nada.
  4. Enfileirar o trabalho lento e responder exatamente HTTP 200.

A Qvard repete qualquer outra resposta, um timeout ou um redirecionamento, cinco tentativas em cerca de seis minutos, então entregas repetidas são normais. Os detalhes das novas tentativas estão em estratégia de novas tentativas de webhooks em sistemas de pagamento, e as regras de segurança em como proteger webhooks de pagamentos em cripto.

Pythonwebhook.py
import os
from fastapi import FastAPI, Request, Response
from qvard import Qvard

app = FastAPI()
qvard = Qvard(os.environ["QVARD_API_KEY"])

@app.post("/webhooks/qvard")
async def qvard_webhook(request: Request):
    try:
        body = qvard.webhooks.construct_event(await request.body(), request.headers.get("X-Qvard-Signature"), os.environ["QVARD_API_KEY"])
    except ValueError:
        return Response(status_code=401)

    if body.get("status") == "completed":
        # Only changes an order that is not paid yet, so repeated deliveries are harmless.
        changed = await db.execute(
            "UPDATE orders SET state = 'paid', paid_at = now() WHERE id = :id AND state = 'awaiting_payment'",
            {"id": body.get("id")},
        )
        if changed:
            await queue.enqueue("fulfil_order", body["id"])

    return Response(status_code=200)

Pagamentos parciais, falhas e a visão do cliente

Decida o que cada estado do pagamento significa para um pedido:

  • wait: aguardando pagamento.
  • partial: chegou menos que o valor total; nenhum webhook de conclusão é enviado. Mantenha o pedido aberto, diga ao cliente quanto falta, ou cancele e reembolse.
  • completed: chegou o valor total; marque o pedido como pago.
  • rejected: ofereça outra forma de pagar.

Ainda não há URLs de retorno após o pagamento, então o cliente volta por conta própria: dê a ele uma página de pedido que mostre o estado real e se atualize enquanto espera. Um reembolso é uma transferência que você mesmo envia, porque um pagamento em cripto não pode ser revertido.

Conciliação e lista de verificação para entrar no ar

Adicione uma conferência diária que compare os pedidos que você considera pagos ou não com os pagamentos e o saldo no painel da Qvard; um pagamento mostrado como concluído enquanto seu pedido está sem pagar é uma notificação perdida, que você pode reenviar pelo painel.

Antes de entrar no ar:

  • a chave de API está em uma variável de ambiente ou em um gerenciador de segredos, nunca no repositório;
  • a callback URL está salva, é pública, usa HTTPS e é acessível de fora da sua rede;
  • o endpoint responde exatamente 200, rápido, e é seguro se executar duas vezes;
  • você pagou um pequeno valor real e viu o pedido ficar pago;
  • você fez o endpoint falhar uma vez e viu a Qvard repetir sem um duplo cumprimento;
  • você sacou um pequeno valor para a sua carteira. O saque custa apenas a taxa de rede; o saque para conta bancária em moeda fiduciária não está disponível.

As condições comerciais estão na página de preços, e uma fatura de demonstração mostra o que seu cliente vê.

FAQ

Existe um SDK para a minha linguagem?

Não. A integração é HTTP simples: um POST para criar um pagamento e um webhook para receber o resultado. Os exemplos deste guia mostram o padrão em Python, e ele se transfere para qualquer linguagem.

Como associo um pagamento a um pedido?

Envie o número do seu próprio pedido como id ao criar o pagamento. O mesmo id volta no webhook.

Existe sandbox para testar?

Ainda não. Use pequenos valores reais e uma fatura de demonstração para ver a página de pagamento.

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

A Qvard repete cinco vezes em cerca de seis minutos. Depois disso, reenvie a notificação do pagamento pelo painel; um tratador idempotente torna isso seguro.

Artigos relacionados

Artigos relacionados