VKX Technologies Docs

VKX Pay

You price in fiat; the payer picks the crypto. The merchant amount and the VKX fee move in the same on-chain transaction — either both happen or neither does. No custody at any point.

Empezar

Before any code: create the account at /pay/painel with your Google account and register one wallet address per network. That is the only setup there is.

npm install @vkx/pay
If you would rather not write code, stop here: the dashboard generates payment links and QR codes on its own.

Crear el cobro

On your server — the secret key never reaches the browser.

const { createPaymentIntent } = require('@vkx/pay');

const payment = await createPaymentIntent({
  apiKey: process.env.VKX_PAY_SECRET_KEY,   // sk_vkxpay_...
  amount: '199.90',                          // reais, string
  orderId: pedido.id,                        // o id no SEU sistema
});

// payment.checkoutUrl → mande o pagador para cá
// (botão no site, link no WhatsApp, QR no balcão)

Parámetros

CampoObligatorioDescripción
apiKeyYour secret key sk_vkxpay_...
amountAmount in fiat, as a string: '199.90'
orderIdnoOrder id in your system — comes back in the webhook
metadatanoFree-form object, stored with the charge
expiresInSecondsnoCharge validity (default 1800, between 120 and 86400)

Recibir la confirmación

When the blockchain confirms, VKX calls your URL. Use the raw request body — before any JSON.parse from your framework.

const { constructWebhookEvent } = require('@vkx/pay');

app.post('/webhooks/vkx', express.raw({ type: 'application/json' }), (req, res) => {
  const event = constructWebhookEvent({
    secret: process.env.VKX_PAY_WEBHOOK_SECRET,   // whsec_...
    body: req.body,
    signature: req.headers['x-vkx-signature'],
  });

  if (event.event === 'payment.completed') {
    liberarPedido(event.data.orderId);
  }
  res.sendStatus(200);
});

The signature arrives as t=<unix>,v1=<hmac>, an HMAC-SHA256 of "<t>.<body>". The SDK rejects tampered bodies, wrong secrets and stale requests (older than 5 minutes).

Event body

{
  "event": "payment.completed",
  "createdAt": "2026-08-15T18:30:44.603Z",
  "data": {
    "paymentIntentId": "pay_c-M_7otXmizP",
    "orderId": "PEDIDO-123",
    "amount": "199.90",
    "currency": "BRL",
    "network": "bsc",
    "txHash": "0x…",
    "payer": "0x…",
    "confirmedAt": "2026-08-15T18:31:02.114Z"
  }
}

Events: payment.completed and payment.expired. Reply 2xx; VKX retries with increasing backoff (1min, 5min, 30min, 2h, 6h, 12h, 24h) before giving up.

Estados de un cobro

EstadoSignifica
OPENCreated, waiting for payment
PENDINGTransaction seen on-chain, awaiting confirmations
PAIDConfirmed — the webhook was fired
EXPIREDExpired with no payment
CANCELEDCancelled by you before payment
REFUNDED_EXTERNALRefunded outside and recorded in the history
Refunds executed from the dashboard are in development. Today you refund from your own wallet and record it.

Redes y monedas

RedMonedasConfirmaciones
BNB ChainUSDT, USDC, USD1, BNB3
PolygonUSDT, USDC, POL30
BaseUSDC, ETH12
SolanaUSDC, SOLfinalized

Native coins are optional — you enable them in the dashboard. The fiat quote is frozen during checkout (about 5 minutes for stablecoins, less for native coins, which move more).

Endpoints REST

If you do not use Node.js, talk straight to the API. Base: https://api.vkxtech.com.br

MétodoRutaQué hace
POST/pay/v1/payment-intentsCreates the charge
GET/pay/v1/payment-intents/:idReads status and payments
POST/pay/v1/payment-intents/:id/cancelCancels before payment
POST/pay/v1/payment-intents/:id/refunded-externalRecords a refund made outside
PUT/pay/v1/walletsSets where to receive on each network
POST/pay/v1/webhook-endpointsRegisters the webhook URL
GET/pay/v1/meSales summary (accepts the read key)
curl -X POST https://api.vkxtech.com.br/pay/v1/payment-intents \
  -H "Authorization: Bearer sk_vkxpay_..." \
  -H "Content-Type: application/json" \
  -d '{"amount":"199.90","orderId":"PEDIDO-123"}'

Otros lenguajes

The npm package is convenience, not a requirement. VKX Pay is a REST API with JSON: any language that makes an HTTP request integrates — PHP, Python, Ruby, Go, Java, C#, Elixir, whatever you use.

There are only two operations: create the charge (one authenticated request) and validate the webhook (an HMAC-SHA256, which every language has in its standard library).

Python

import requests, hmac, hashlib, time

# criar a cobrança
r = requests.post(
    "https://api.vkxtech.com.br/pay/v1/payment-intents",
    headers={"Authorization": f"Bearer {VKX_PAY_SECRET_KEY}"},
    json={"amount": "199.90", "orderId": pedido_id},
).json()
checkout_url = r["checkoutUrl"]

# validar o webhook
def valido(corpo_cru: bytes, header: str, segredo: str) -> bool:
    partes = dict(p.split("=", 1) for p in header.split(","))
    t = int(partes["t"])
    if abs(time.time() - t) > 300:
        return False
    esperado = hmac.new(segredo.encode(),
                        f"{t}.".encode() + corpo_cru,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperado, partes["v1"])

Go

body, _ := json.Marshal(map[string]string{"amount": "199.90", "orderId": pedidoID})
req, _ := http.NewRequest("POST", apiBase+"/pay/v1/payment-intents", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("VKX_PAY_SECRET_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)

Anything that runs cURL

curl -X POST https://api.vkxtech.com.br/pay/v1/payment-intents \
  -H "Authorization: Bearer $VKX_PAY_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":"199.90","orderId":"PEDIDO-123"}'
No server at all? Generate the charge in the dashboard and use the link or QR code. Works for static landing pages, Instagram, WhatsApp and a physical counter.

WordPress

WordPress is PHP, so the integration uses wp_remote_post — no plugin and no external dependency. Paste into your theme's functions.php (or your own plugin):

<?php
function vkx_criar_cobranca($valor, $pedido_id) {
    $resposta = wp_remote_post('https://api.vkxtech.com.br/pay/v1/payment-intents', [
        'headers' => [
            'Authorization' => 'Bearer ' . VKX_PAY_SECRET_KEY,
            'Content-Type'  => 'application/json',
        ],
        'body' => wp_json_encode([
            'amount'  => $valor,        // '199.90'
            'orderId' => $pedido_id,
        ]),
        'timeout' => 20,
    ]);

    if (is_wp_error($resposta)) return null;
    $dados = json_decode(wp_remote_retrieve_body($resposta), true);
    return $dados['checkoutUrl'] ?? null;   // redirecione o comprador para cá
}

// Webhook: registre uma rota REST e valide a assinatura
add_action('rest_api_init', function () {
    register_rest_route('vkx/v1', '/webhook', [
        'methods'  => 'POST',
        'permission_callback' => '__return_true',
        'callback' => function (WP_REST_Request $req) {
            $corpo  = $req->get_body();                       // corpo CRU
            $header = $req->get_header('x-vkx-signature');
            parse_str(str_replace(',', '&', $header), $p);   // t=...,v1=...

            if (abs(time() - (int) $p['t']) > 300) return new WP_REST_Response('velho', 400);
            $esperado = hash_hmac('sha256', $p['t'] . '.' . $corpo, VKX_PAY_WEBHOOK_SECRET);
            if (!hash_equals($esperado, $p['v1'])) return new WP_REST_Response('invalido', 400);

            $evento = json_decode($corpo, true);
            if ($evento['event'] === 'payment.completed') {
                // marque o pedido como pago: $evento['data']['orderId']
            }
            return new WP_REST_Response('ok', 200);
        },
    ]);
});

In WooCommerce, call vkx_criar_cobranca() in your gateway and redirect to checkoutUrl; in the webhook, use $order->payment_complete().

An official WooCommerce plugin is in development. Until then, the snippet above is the complete integration.

React / Next.js

The secret key never reaches the browser. Create the charge on the server and return only the checkout URL.

// app/api/pagar/route.ts  (Next.js App Router)
import { createPaymentIntent } from '@vkx/pay';

export async function POST(req: Request) {
  const { orderId, total } = await req.json();
  const payment = await createPaymentIntent({
    apiKey: process.env.VKX_PAY_SECRET_KEY!,
    amount: total,
    orderId,
  });
  return Response.json({ checkoutUrl: payment.checkoutUrl });
}
// client component
async function pagar() {
  const r = await fetch('/api/pagar', {
    method: 'POST',
    body: JSON.stringify({ orderId: pedido.id, total: '199.90' }),
  }).then((r) => r.json());
  window.location.assign(r.checkoutUrl);
}

Claves de API

ClavePuedeDónde usar
sk_vkxpay_…Create charges, configure the accountServer only
rk_vkxpay_…Read-only: query salesDashboards and apps
whsec_…Validate the webhook signatureServer only

Each key is shown once when created — we store only a hash. Lost it? Generate another and revoke the previous one in the dashboard.

Panel en el móvil

Generate an rk_ key in the dashboard and use it in the VKX Wallet app to follow sales from your phone. Being read-only, it cannot create a charge or move funds, even if the phone is lost.

curl https://api.vkxtech.com.br/pay/v1/me \
  -H "Authorization: Bearer rk_vkxpay_..."

The response carries volume today, total volume, number of sales, average ticket, movement per network and the latest charges.