ViraEntrar

Para desenvolvedores

API da Vira

Ligue a Vira à sua loja ou ao sistema que sua empresa já usa: ele cria a cobrança, mostra o Pix ao cliente e fica sabendo quando o pagamento entra. Sem mensalidade, você só paga a tarifa quando recebe.

Quem pode usar: contas de empresa (CNPJ) já aprovadas. Contas de pessoa física não têm chaves de API.

1. Criar sua chave

Entre no painel, abra Configurações → Integrações e clique em Nova chave. A chave aparece uma única vez: copie e guarde em local seguro (no servidor da sua loja, nunca no navegador ou em aplicativo). Se perder, revogue e crie outra. Só o dono ou um administrador da conta mexe nas chaves.

Toda chamada leva o cabeçalho Authorization: Bearer vira_sk_…. A empresa é identificada pela chave; você nunca informa o código da empresa.

2. Criar uma cobrança Pix

POST /api/v1/charges. O valor vai em centavos (R$ 129,90 = 12990; mínimo R$ 5,00). A referência é o número do pedido no seu sistema e não pode se repetir. O cabeçalho Idempotency-Key evita cobrança dobrada: se a chamada falhar no meio do caminho, repita com a mesma chave e você recebe a mesma cobrança.

curl -X POST https://virapagamento.com.br/api/v1/charges \
  -H "Authorization: Bearer vira_sk_SUA_CHAVE" \
  -H "Idempotency-Key: pedido-1042-tentativa-1" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "pedido-1042",
    "description": "Pedido 1042 - Camiseta azul",
    "amountCents": 12990,
    "method": "PIX",
    "dueDate": "2026-12-31",
    "customer": {
      "name": "Maria da Silva",
      "document": "12345678909",
      "email": "maria@exemplo.com.br",
      "phone": "11999998888"
    }
  }'

Resposta (201): mostre o QR Code ou o “copia e cola” em pix, ou mande o cliente para o paymentUrl, a fatura da Vira com Pix, cartão e boleto.

{
  "id": "0b6f4c1e-8d52-4e0c-9a57-2f3c7b8e1a10",
  "reference": "pedido-1042",
  "status": "PENDING",
  "amountCents": 12990,
  "dueDate": "2026-12-31",
  "paidAt": null,
  "pix": {
    "payload": "00020126...",
    "image": "iVBORw0KGgo...",
    "expiresAt": "2026-12-31T23:59:59.000Z"
  },
  "paymentUrl": "https://virapagamento.com.br/c/AbCdEf123456"
}

3. Consultar uma cobrança

GET /api/v1/charges/{id}. Enquanto a cobrança está em aberto, a Vira confere o pagamento direto no banco parceiro a cada chamada (no máximo uma vez a cada 5 segundos).

curl https://virapagamento.com.br/api/v1/charges/0b6f4c1e-8d52-4e0c-9a57-2f3c7b8e1a10 \
  -H "Authorization: Bearer vira_sk_SUA_CHAVE"

Situações possíveis no campo status:

Libere o pedido só quando o status for PAID. A Vira nunca marca como pago por conta própria: o status vem do banco parceiro.

4. Receber avisos (webhook)

Em vez de ficar perguntando, cadastre um endereço e a Vira avisa quando uma cobrança mudar. O endereço precisa ser HTTPS e público. A resposta traz o segredo de assinatura, que aparece uma única vez.

curl -X PUT https://virapagamento.com.br/api/v1/webhook-endpoint \
  -H "Authorization: Bearer vira_sk_SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://sualoja.com.br/avisos/vira" }'

Cada aviso é um POST com este corpo. Ele só diz qual cobrança mudou; para saber o estado, consulte-a (passo 3). Assim, um aviso falso ou repetido não muda nada sozinho. Responda com qualquer status 2xx em até 5 segundos.

Atenção: por enquanto cada aviso é enviado uma vez, sem reenvio automático. Se o seu servidor estiver fora do ar nessa hora, o aviso se perde; por isso, consulte também as cobranças em aberto de tempos em tempos (passo 3).

{
  "id": "5c0e1c7a-...",
  "type": "charge.updated",
  "chargeId": "0b6f4c1e-8d52-4e0c-9a57-2f3c7b8e1a10",
  "createdAt": "2026-10-22T14:03:11.000Z"
}

O cabeçalho X-Vira-Signature: t=<unix>,v1=<hex> traz a assinatura: v1 = HMAC-SHA256(segredo, "t.corpo"). Confira antes de usar o aviso:

// Node.js — confira a assinatura ANTES de confiar no aviso
import { createHmac, timingSafeEqual } from "node:crypto";

function assinaturaValida(segredo, cabecalho, corpoBruto) {
  const partes = Object.fromEntries(cabecalho.split(",").map((p) => p.split("=")));
  const t = partes.t;
  const esperado = createHmac("sha256", segredo).update(t + "." + corpoBruto).digest("hex");
  const a = Buffer.from(esperado);
  const b = Buffer.from(partes.v1 ?? "");
  const recente = Math.abs(Date.now() / 1000 - Number(t)) < 300; // 5 minutos
  return recente && a.length === b.length && timingSafeEqual(a, b);
}

5. Erros

Os erros voltam em JSON, no formato { "error": { "code", "message" } }.

Boas práticas

Dúvidas ou precisa de ajuda na integração? Fale com o suporte dentro do painel. Criar conta de empresa