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.

开始

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.

创建收款

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)

参数

字段必填说明
apiKeyYour secret key sk_vkxpay_...
amountAmount in fiat, as a string: '199.90'
orderIdOrder id in your system — comes back in the webhook
metadataFree-form object, stored with the charge
expiresInSecondsCharge validity (default 1800, between 120 and 86400)

接收确认

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.

收款状态

状态含义
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.

网络与币种

网络币种确认数
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).

REST 接口

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

方法路径作用
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"}'

其他语言

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);
}

API 密钥

密钥权限使用位置
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.

手机端面板

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.