Integrações

Pagamentos em cripto no WooCommerce

Como adicionar cripto como meio de pagamento do WooCommerce: uma classe de gateway própria, criar o pagamento da Qvard, o webhook que conclui o pedido e as armadilhas específicas do WooCommerce.

O WooCommerce tem um ponto de extensão limpo para meios de pagamento, e a Qvard precisa de apenas duas coisas dele: uma chamada que cria um pagamento quando o cliente paga e um endpoint que conclui o pedido quando o pagamento termina. Ainda não há um plugin da Qvard pronto, então este guia mostra o código próprio, peça por peça, e os detalhes do WooCommerce que costumam dar errado.

Antes de começar

Você precisa de uma conta Qvard com um projeto, uma chave de API e uma callback URL salva no projeto. Do lado do WooCommerce, precisa de um jeito de adicionar código, de preferência um pequeno plugin próprio ou um plugin de trechos de código, e não um arquivo do tema que some na próxima atualização.

Duas decisões de antemão:

  • Moeda. A Qvard define os pagamentos em dólares americanos. O gateway deste guia aceita pedidos em USD e recusa outras moedas, o que é o padrão seguro. Se sua loja vende em outra moeda, converta o total do pedido para dólares antes de criar o pagamento e avise isso no checkout.
  • Onde fica a chave. Defina a chave de API como constante em wp-config.php (define( 'QVARD_API_KEY', '...' );), não nas configurações do banco de dados, de onde exportações e outros plugins podem lê-la.

Se você só precisa da ideia básica sem a classe do WooCommerce, comece por pagamentos em cripto no WordPress.

As peças e como um pedido avança

Três peças formam a integração:

  1. Uma classe de gateway de pagamento que aparece no checkout do WooCommerce como «Pagar com cripto».
  2. Uma chamada à Qvard dentro do gateway, que cria um pagamento para o pedido e devolve o endereço da página de pagamento hospedada.
  3. Um endpoint de webhook que a Qvard chama quando o pagamento é concluído.

Um pedido avança assim: o cliente escolhe o método e clica em pagar; o gateway cria o pagamento da Qvard, coloca o pedido em espera e redireciona o cliente para a página de pagamento; o cliente paga de uma carteira; a Qvard chama seu endpoint; o endpoint conclui o pedido e o WooCommerce envia seus e-mails habituais e o faz avançar. O id do pagamento que você envia à Qvard é o número do pedido do WooCommerce, e é assim que o webhook reencontra o pedido.

A classe do gateway

A classe estende WC_Payment_Gateway. O construtor define o id e o título do método e carrega as configurações, e process_payment faz o trabalho. Ela recusa pedidos que não estejam em USD e então envia um POST para https://api.qvard.com/api/v1/payment com sua chave no cabeçalho Authorization: Bearer e um JSON: id (o número do pedido como string) e price (o total em dólares americanos). Uma resposta 201 traz um redirectUrl.

Em caso de sucesso, o gateway guarda no pedido o id do pagamento da Qvard, define o estado como on-hold («aguardando pagamento»), esvazia o carrinho e devolve o redirectUrl como redirecionamento. Em caso de falha, adiciona um aviso de erro e devolve failure, de modo que o cliente permanece no checkout e pode escolher outro método.

Enviar o mesmo id para o mesmo método de pagamento devolve o pagamento existente, então um cliente que clica no botão duas vezes não cria dois pagamentos.

PHPqvard-gateway.php
<?php
// A minimal WooCommerce payment method that sends the customer to the Qvard payment page.
add_filter( 'woocommerce_payment_gateways', function ( $gateways ) {
    $gateways[] = 'WC_Gateway_Qvard';
    return $gateways;
} );

add_action( 'plugins_loaded', function () {
    if ( ! class_exists( 'WC_Payment_Gateway' ) ) {
        return;
    }

    class WC_Gateway_Qvard extends WC_Payment_Gateway {
        public function __construct() {
            $this->id                 = 'qvard';
            $this->method_title       = 'Qvard (crypto)';
            $this->method_description = 'Accept USDT and other crypto through Qvard.';
            $this->has_fields         = false;

            $this->init_form_fields();
            $this->init_settings();
            $this->title = $this->get_option( 'title', 'Pay with crypto' );

            add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
        }

        public function init_form_fields() {
            $this->form_fields = array(
                'enabled' => array( 'title' => 'Enable', 'type' => 'checkbox', 'default' => 'no' ),
                'title'   => array( 'title' => 'Title', 'type' => 'text', 'default' => 'Pay with crypto' ),
            );
        }

        public function process_payment( $order_id ) {
            $order = wc_get_order( $order_id );

            // Qvard prices payments in US dollars: refuse other shop currencies instead of charging a wrong amount.
            if ( 'USD' !== $order->get_currency() ) {
                wc_add_notice( 'Crypto payment is available for orders in USD only.', 'error' );
                return array( 'result' => 'failure' );
            }

            $response = wp_remote_post( 'https://api.qvard.com/api/v1/payment', array(
                'timeout' => 15,
                'headers' => array( 'Authorization' => 'Bearer ' . QVARD_API_KEY, 'Content-Type' => 'application/json' ),
                'body'    => wp_json_encode( array( 'id' => (string) $order->get_id(), 'price' => (float) $order->get_total() ) ),
            ) );

            if ( is_wp_error( $response ) || 201 !== wp_remote_retrieve_response_code( $response ) ) {
                wc_add_notice( 'Could not start the payment. Please try again.', 'error' );
                return array( 'result' => 'failure' );
            }

            $data = json_decode( wp_remote_retrieve_body( $response ), true );
            if ( empty( $data['redirectUrl'] ) ) {
                wc_add_notice( 'Could not start the payment. Please try again.', 'error' );
                return array( 'result' => 'failure' );
            }

            $order->update_meta_data( '_qvard_payment_id', sanitize_text_field( $data['id'] ?? '' ) );
            $order->update_status( 'on-hold', 'Waiting for the crypto payment.' );
            WC()->cart->empty_cart();

            return array( 'result' => 'success', 'redirect' => $data['redirectUrl'] );
        }
    }
} );

O webhook que conclui o pedido

Registre uma rota REST e salve o endereço dela no seu projeto da Qvard como callback URL. Quando um pagamento é concluído, a Qvard envia um POST com o id e o status, assinado no cabeçalho X-Qvard-Signature. O tratador do exemplo:

  • verifica a assinatura (HMAC-SHA256 com a sua chave secreta) com o SDK da Qvard e responde 401 se não coincidir;
  • encontra o pedido pelo id e ignora pedidos que não existem ou que não foram pagos com este gateway, ainda respondendo 200 para que a Qvard pare de repetir;
  • chama payment_complete() somente no estado completed e somente se o pedido ainda não estiver pago, o que o torna seguro se executar duas vezes;
  • responde exatamente HTTP 200. Qualquer outro status, um timeout ou um redirecionamento conta como entrega falha e é repetido, cinco tentativas em cerca de seis minutos.

Libere a rota em qualquer plugin de segurança ou firewall e garanta que o cache não toque em /wp-json/. As regras gerais estão em como proteger webhooks de pagamentos em cripto.

PHPqvard-webhook.php
<?php
// Callback URL to save in the Qvard project: https://your-shop.com/wp-json/qvard/v1/webhook
add_action( 'rest_api_init', function () {
    register_rest_route( 'qvard/v1', '/webhook', array(
        'methods'             => 'POST',
        'permission_callback' => '__return_true', // authenticated below by the X-Qvard-Signature header
        'callback'            => function ( WP_REST_Request $request ) {
            try {
                $payload = ( new Qvard\Qvard( QVARD_API_KEY ) )->webhooks->constructEvent( $request->get_body(), $request->get_header( 'x-qvard-signature' ), QVARD_API_KEY );
            } catch ( \Exception $e ) {
                return new WP_REST_Response( null, 401 );
            }
            $order   = wc_get_order( (int) ( $payload['id'] ?? 0 ) );

            // Unknown order or not ours: nothing to retry, answer 200.
            if ( ! $order || 'qvard' !== $order->get_payment_method() ) {
                return new WP_REST_Response( null, 200 );
            }

            if ( 'completed' === ( $payload['status'] ?? '' ) && ! $order->is_paid() ) {
                $order->payment_complete( (string) $order->get_meta( '_qvard_payment_id' ) );
                $order->add_order_note( 'Qvard: payment completed.' );
            }

            return new WP_REST_Response( null, 200 ); // must be exactly 200
        },
    ) );
} );

Detalhes do WooCommerce que mordem

  • Estoque. O WooCommerce reduz o estoque quando um pedido vai para processando ou em espera, então pedidos em cripto não pagos podem reter estoque. Cancele pedidos em espera vencidos após um prazo que você escolher, com uma tarefa agendada própria (a configuração de retenção de estoque do WooCommerce vale para pedidos pendentes de pagamento, não para os em espera); senão, o estoque fica reservado.
  • Pagamentos parciais. Se chegar menos que o valor total, o estado do pagamento é partial e nenhum webhook de conclusão é enviado. O pedido continua em espera; adicione uma nota, peça o restante ao cliente ou cancele e reembolse.
  • Reembolsos. Um pagamento em cripto não pode ser puxado de volta. Crie o registro de reembolso no WooCommerce para a sua contabilidade, mas envie o dinheiro você mesmo para um endereço que o cliente informar.
  • E-mails do pedido. O e-mail de «em espera» sai quando o pedido é feito; garanta que o texto diga ao cliente que o pagamento está pendente e onde pagar.
  • A volta ao site. Ainda não há URLs de retorno após o pagamento, então o cliente volta à sua loja por conta própria. A página de pedido padrão mostra o estado real, o que é correto.
  • Checkout em blocos. O checkout baseado em blocos do WooCommerce precisa também de um gateway registrado para blocos; teste o método no checkout que você realmente usa.

Teste antes de entrar no ar

  1. Abra uma fatura de demonstração para ver a página de pagamento que seu cliente receberá.
  2. Faça um pedido de teste com o método cripto e confira se você é redirecionado para a página de pagamento e se o pedido fica em espera.
  3. Pague um pequeno valor real e confirme que o webhook chega e que o pedido passa para processando.
  4. Faça o endpoint falhar uma vez, confirme que a Qvard tenta de novo e que o pedido não é concluído duas vezes.
  5. Saque um pequeno valor do seu saldo para a sua carteira para saber que todo o caminho funciona.

Ainda não há um sandbox separado, então use pequenos valores reais.

Quanto custa e o que está pronto

Não há mensalidade pelo gateway. A comissão é individual para o seu projeto e, segundo a página de preços, começa em 1% e pode chegar a 0,1%. Os fundos ficam no seu saldo da Qvard e você os saca para a sua própria carteira pela taxa de rede; o saque para conta bancária em moeda fiduciária não está disponível.

A Qvard funciona pela API, então a integração exige um desenvolvedor e testes; não há um plugin de WooCommerce pronto, e links de pagamento e um sandbox separado estão em desenvolvimento. A API é descrita em API de pagamentos em cripto para desenvolvedores e o lado da loja em pagamentos em cripto para e-commerce.

FAQ

Existe um plugin da Qvard para WooCommerce?

Ainda não. A integração é pela API: uma classe de gateway que cria o pagamento e um webhook que conclui o pedido. O código deste guia é um ponto de partida para um desenvolvedor.

Minha loja usa euros. Os clientes ainda podem pagar em cripto?

A Qvard define os pagamentos em dólares americanos. Converta o total do pedido para dólares antes de criar o pagamento e informe ao cliente o valor em dólares no checkout; o gateway do exemplo recusa pedidos que não estejam em USD como padrão seguro.

Quando o pedido passa a pago?

Quando o webhook chega com o estado completed. O cliente voltar à loja não é prova de pagamento, e o estado partial significa que chegou menos que o necessário.

E se meu site estava fora do ar quando o pagamento foi concluído?

A notificação é repetida cinco vezes em cerca de seis minutos. Depois disso, reenvie-a para o pagamento pelo painel da Qvard; o tratador é seguro se executar duas vezes.

Artigos relacionados

Artigos relacionados