Guia de integração · API v1

Documentação TrackPag

Tudo para integrar seu sistema: autenticação, depósitos PIX, saques, saldo, disputas MED e webhooks assinados — com exemplos prontos em cURL, Node e Python.

https://api.trackpag.com/v1 Minhas credenciais

Introdução

Bem-vindo à documentação oficial da API TrackPag — infraestrutura de pagamentos PIX para integrações server-to-server, cobrindo depósitos (cash-in), saques (cash-out), saldo, disputas MED e webhooks assinados.

Nesta referência você encontra:

  • o fluxo completo de autenticação e cache de tokens;
  • cada endpoint com request, response e explicação campo a campo;
  • tabela consolidada de códigos de erro e como remediar cada um;
  • o formato dos webhooks e como verificar a assinatura em Node e Python;
  • nuances operacionais: idempotência, allowlist de IPs, prazos de MED e retentativas.

Visão geral

A TrackPag fica entre o seu sistema e os trilhos de pagamento. Você integra uma única API com schema uniforme — a gente cuida da liquidação, consolida os webhooks e expõe seu ledger em três buckets.

CenárioEndpointTempo típico
Cliente paga via PIX (QR ou Copia e Cola)POST /v1/charges< 1s para gerar o QR
Confirmação do pagamentowebhook deposit.confirmedsegundos após o pagamento
Você envia PIX (saque)POST /v1/withdrawalsaté 1 dia útil
Consulta de saldoGET /v1/balancetempo real
Contestação do pagador (MED)webhook med.openedprazo de defesa: 7 dias

URL base

Base URL
https://api.trackpag.com/v1

Todas as requisições usam Content-Type: application/json e TLS. Chamadas em HTTP puro são recusadas.

Formato das respostas

  • Valores monetários são inteiros em centavos — 28490 significa R$ 284,90.
  • Datas em ISO 8601, sempre UTC — 2026-07-06T13:32:00Z.
  • Sucesso retorna o recurso direto no corpo, sem envelope.
  • Erro retorna { "error": { "code", "message" } } — veja Códigos de erro.
  • IDs têm prefixo por tipo: ch_ (cobrança), wd_ (saque), dp_ (disputa), evt_ (evento).

Ordem recomendada de leitura

  1. 01Autenticação — obtenha e cacheie seu token;
  2. 02Depósitos PIX — crie a primeira cobrança;
  3. 03Webhooks + Assinatura — receba confirmações com segurança;
  4. 04Saques PIX — automatize o cash-out;
  5. 05Códigos de erro — trate as falhas com elegância.

Suporte

Dúvidas de integração: suporte@trackpag.com.br · Central de ajuda. Inclua o id do recurso e o horário (UTC) da chamada — acelera muito o diagnóstico.

Autenticação

A TrackPag usa o par Client ID + Client Secret — os dois estão em Configurações → Credenciais. Troque-os por um access token e envie o token como Bearer nas demais chamadas.

Obter o token

POST /v1/auth/token
curl -X POST https://api.trackpag.com/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "seunome_A1B2C3D4",
    "client_secret": "sk_live_9f2c4a7d..."
  }'

# 200 OK
{
  "access_token": "tpat_kX91mval...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Cache do token

O token vale expires_in segundos (1 hora). Não gere um token por requisição — cacheie em memória e renove só quando faltar menos de 5 minutos para expirar, ou quando receber 401.

Padrão de cache em Node
let cached = { token: null, expiresAt: 0 };

async function getToken() {
  if (cached.token && Date.now() < cached.expiresAt - 300_000) {
    return cached.token; // ainda válido por > 5 min
  }
  const { access_token, expires_in } = await fetchToken();
  cached = { token: access_token, expiresAt: Date.now() + expires_in * 1000 };
  return access_token;
}

Erros de autenticação

RespostaCausaO que fazer
401 unauthorizedclient_id/secret incorretos ou token expiradoConfira as credenciais; renove o token e repita uma vez
403 ip_not_allowedIP fora da allowlistAdicione o IP do servidor em Credenciais → IPs
429 rate_limitedGerando tokens em excessoImplemente o cache acima; respeite o Retry-After
O Client Secret nunca vai no front-end, em apps mobile ou em repositórios. Se vazar, gere um novo no painel — o antigo é invalidado na hora.

IPs permitidos

Em Credenciais → IPs permitidos você restringe de quais endereços a API aceita chamadas da sua conta (até 20 IPs). Lista vazia = qualquer origem — recomendamos travar nos IPs de saída dos seus servidores em produção.

Chamada de IP fora da lista → 403 ip_not_allowed. O IP recusado vem na mensagem do erro para facilitar o diagnóstico.

Idempotência

Envie o header Idempotency-Key em todo POST que cria recurso. Se a rede cair e você repetir a chamada com a mesma chave, recebe a mesma resposta — sem cobrança nem saque duplicado. Use um valor único por operação (o ID do pedido no seu sistema). Chaves valem por 24 horas.

Exemplo
curl -X POST https://api.trackpag.com/v1/charges \
  -H "Authorization: Bearer tpat_..." \
  -H "Idempotency-Key: pedido-4128" \
  -d '{ ... }'

Mesma chave + corpo diferente409 idempotency_conflict.

Códigos de erro

Erros sempre voltam neste formato:

Formato do erro
{
  "error": {
    "code": "insufficient_funds",
    "message": "Saldo disponível insuficiente para este saque."
  }
}
StatusCódigoCausaComo remediar
400invalid_requestCorpo malformado ou campo obrigatório ausenteConfira o campo apontado na message
401unauthorizedToken ausente, inválido ou expiradoRenove o token e repita uma vez
403ip_not_allowedIP de origem fora da allowlistAdicione o IP em Credenciais → IPs
404not_foundRecurso não existe ou pertence a outra contaConfira o ID e o ambiente
409idempotency_conflictMesma Idempotency-Key com corpo diferenteGere uma chave nova para operações novas
422insufficient_fundsSaldo disponível não cobre a operaçãoConsulte GET /v1/balance antes de sacar
422charge_expiredCobrança expirou antes do pagamentoCrie uma nova cobrança
429rate_limitedLimite de requisições excedidoAguarde o Retry-After; use backoff exponencial
5xxserver_errorFalha nossaRepita com a mesma Idempotency-Key — é seguro

Depósitos PIX

Crie uma cobrança, mostre o QR (ou o Copia e Cola) ao pagador e receba deposit.confirmed no seu webhook — normalmente segundos após o pagamento.

Criar cobrança

POST /v1/charges
curl -X POST https://api.trackpag.com/v1/charges \
  -H "Authorization: Bearer tpat_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-4128" \
  -d '{
    "amount": 28490,
    "method": "pix",
    "customer": { "name": "Ana Souza", "email": "ana@studio-fio.com.br", "document": "12345678901" },
    "reference": "pedido#4128",
    "expires_in": 3600
  }'

# 201 Created
{
  "id": "ch_2n4kQ8Zr",
  "status": "pending",
  "amount": 28490,
  "method": "pix",
  "reference": "pedido#4128",
  "qr_code": "00020126580014br.gov.bcb.pix...",
  "qr_code_base64": "iVBORw0KGgo...",
  "expires_at": "2026-07-06T14:32:00Z",
  "created_at": "2026-07-06T13:32:00Z"
}
CampoTipoDescrição
amountint · obrigatórioCentavos — mínimo 100 (R$ 1,00)
methodstring · obrigatórioPor enquanto, sempre "pix"
customer.namestring · opcionalNome do pagador, para conciliação
customer.emailstring · opcionalE-mail do pagador
customer.documentstring · opcionalCPF/CNPJ (só dígitos). Se inválido, a cobrança é criada sem trava de pagador
referencestring · opcionalSeu identificador interno — ecoado nos webhooks
expires_inint · opcionalSegundos até expirar (padrão 3600, máx. 86400)

Ciclo de vida

StatusSignificado
pendingAguardando pagamento — QR ativo
paidPago e liquidado — valor no bucket receivable → available
expiredExpirou sem pagamento — QR morto, crie outra
refundedDevolvido ao pagador (voluntário ou por MED perdido)

Depois de criada, a cobrança é imutável — valor e expiração não mudam. Para corrigir, deixe expirar (ou ignore) e crie outra.

QR e Copia e Cola

  • qr_code é o payload EMV completo — o mesmo texto do "PIX Copia e Cola". Mostre num botão de copiar.
  • qr_code_base64 é um PNG pronto: <img src="data:image/png;base64,{...}" />.
  • O pagador pode pagar quantas vezes tentar, mas só a primeira liquidação conta — as demais são devolvidas automaticamente.

Consultas

Webhook é o caminho primário de confirmação — consultas servem para conciliação e para recuperar estado depois de indisponibilidade do seu lado.

Consultar por ID

Consultar cobrança
GET /v1/charges/{id}
curl https://api.trackpag.com/v1/charges/ch_2n4kQ8Zr \
  -H "Authorization: Bearer tpat_..."

# 200 OK — mesmo formato da criação, com "status" atual
# e "paid_at" quando status = "paid"

Listagem e paginação

Listar cobranças
GET /v1/charges
curl "https://api.trackpag.com/v1/charges?status=paid&limit=50" \
  -H "Authorization: Bearer tpat_..."

# 200 OK
{
  "data": [ { "id": "tp...", "amount": 28490, "status": "paid", ... } ],
  "has_more": true
}
ParâmetroDescrição
statusFiltra: pending · paid · expired · refunded
limit1 a 100 (padrão 25)
created_beforeCursor: created_at (ISO 8601) do último item da página anterior

A ordenação é sempre da mais recente para a mais antiga. Enquanto has_more for true, repita passando created_before = created_at do último item recebido. Saques saem em GET /v1/withdrawals.

Saldo

Consultar saldo
GET /v1/balance
curl https://api.trackpag.com/v1/balance \
  -H "Authorization: Bearer tpat_..."

# 200 OK
{
  "available_cents": 1284900,
  "blocked_cents": 0,
  "receivable_cents": 45200
}
BucketSignificado
available_centsLivre para saque agora
blocked_centsTravado — saque em processamento ou bloqueio cautelar (MED)
receivable_centsA liquidar — vira available no prazo do rail
O saldo é derivado de um ledger imutável de dupla entrada — cada centavo tem trilha de auditoria. O extrato completo está no painel, em Relatórios → Extrato.

Saques PIX

Transfira o saldo disponível para qualquer chave PIX. O valor sai de available, fica em blocked durante o processamento e você recebe withdrawal.paid ou withdrawal.rejected no webhook.

Solicitar saque

POST /v1/withdrawals
curl -X POST https://api.trackpag.com/v1/withdrawals \
  -H "Authorization: Bearer tpat_..." \
  -H "Idempotency-Key: saque-2026-07-06-01" \
  -d '{
    "amount": 500000,
    "pix_key": "13999998888",
    "pix_key_type": "phone"
  }'

# 201 Created
{ "id": "wd_8xK2mQ", "status": "requested", "amount": 500000 }
CampoTipoDescrição
amountint · obrigatórioCentavos — mínimo 1000 (R$ 10,00)
pix_keystring · obrigatórioChave PIX de destino
pix_key_typestring · obrigatóriocpf · cnpj · email · phone · random

Pagar um QR de terceiros (Copia e Cola)

Além de sacar para uma chave, você pode pagar um código PIX (QR ou Copia e Cola de um fornecedor, por exemplo) direto do seu saldo. Envie o payload EMV no campo qr_code — ele substitui pix_key/pix_key_type e os dois modos são mutuamente exclusivos.

Pagar Copia e Cola
POST /v1/withdrawals
curl -X POST https://api.trackpag.com/v1/withdrawals \
  -H "Authorization: Bearer tpat_..." \
  -H "Idempotency-Key: pgto-fornecedor-889" \
  -d '{
    "qr_code": "00020126580014br.gov.bcb.pix..."
  }'

# 201 Created — o valor vem do próprio código
{ "id": "wd_3fT9zL", "status": "requested", "amount": 152000 }
  • O valor é lido do próprio código — se o QR tiver valor aberto, envie também "amount" em centavos;
  • Códigos expirados ou já pagos retornam 422 com o motivo;
  • O fluxo de status e webhooks é o mesmo do saque por chave.

Ciclo de vida

StatusSignificado
requestedRecebido — valor reservado em blocked
paidPIX enviado — webhook withdrawal.paid
rejectedRecusado — valor devolvido a available, motivo em notes

Prazo: até 1 dia útil. Se a chave PIX estiver errada ou a conta de destino recusar, o saque volta como rejected com o motivo — nada se perde.

Disputas (MED)

O MED (Mecanismo Especial de Devolução) é o processo do Banco Central para o pagador contestar um PIX. Quando um MED chega contra uma transação sua, a TrackPag abre uma disputa e te avisa.

Como funciona

  1. 01Chega o MED → o valor contestado entra em bloqueio cautelar (blocked) e você recebe med.opened;
  2. 02Você tem 7 dias para enviar a defesa com evidências (entrega, comunicação com o cliente, etc.);
  3. 03A resolução chega via med.resolved — a favor libera o valor, contra devolve ao pagador.
Hoje as disputas são acompanhadas e respondidas no painel → Disputas: lá você vê o motivo, o prazo e anexa a defesa. Os webhooks med.opened e med.resolved já avisam seu servidor em tempo real. Os endpoints REST de disputa (GET /v1/disputes e envio de defesa) entram em breve.

Enviar defesa

  • Responda pelo painel enquanto o REST não sai — uma defesa por disputa, capriche na primeira;
  • Enviada após o prazo, a defesa é recusada e a disputa tende a ser perdida;
  • Quanto mais evidência objetiva (rastreio, logs, comunicação), maior a chance de ganhar.

Resolução

ResultadoEfeito no saldoWebhook
won (a favor)Valor sai de blocked e volta para availablemed.resolved · outcome: won
lost (contra)Valor sai de blocked e é devolvido ao pagadormed.resolved · outcome: lost

Webhooks · Eventos

Configure as duas URLs em Credenciais → Webhooks: uma para eventos de depósitos, outra para saques. Todo evento é um POST JSON assinado.

Tabela de eventos

EventoURLDisparo
deposit.confirmedDepósitosCobrança PIX paga e liquidada
deposit.refundedDepósitosDevolução ao pagador processada
med.openedDepósitosMED aberto — valor em bloqueio cautelar
med.resolvedDepósitosMED resolvido (won ou lost)
withdrawal.paidSaquesSaque pago via PIX
withdrawal.rejectedSaquesSaque recusado — valor devolvido

Payload

Exemplo · deposit.confirmed
{
  "id": "evt_5Qm2xL9c",
  "type": "deposit.confirmed",
  "created_at": "2026-07-06T13:32:41Z",
  "data": {
    "charge_id": "ch_2n4kQ8Zr",
    "amount": 28490,
    "reference": "pedido#4128",
    "customer": { "name": "Ana Souza", "email": "ana@studio-fio.com.br" }
  }
}

Boas práticas

  • Responda 2xx em até 5 segundos — enfileire e processe de forma assíncrona;
  • Deduplique pelo id do evento — entregas podem repetir e chegar fora de ordem;
  • Nunca confie só no webhook para valores: confirme com GET /v1/charges/{id} antes de liberar mercadoria de alto valor;
  • Verifique a assinatura de TODA entrega — requisição sem assinatura válida é forjada.

Verificando a assinatura dos webhooks

O header

Cada entrega leva X-TrackPag-Signature, gerado com a chave whsec_… das suas credenciais:

Header
X-TrackPag-Signature: t=1751808761,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

# v1 = HMAC-SHA256( t + "." + corpo_bruto , webhook_signature )

Verificar em Node

Node (Express)
import crypto from "node:crypto";
import express from "express";

const app = express();

// IMPORTANTE: raw body — parse depois da verificação
app.post("/webhooks/trackpag", express.raw({ type: "*/*" }), (req, res) => {
  const header = req.header("X-TrackPag-Signature") ?? "";
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));

  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.sendStatus(400);

  const expected = crypto
    .createHmac("sha256", process.env.TP_WEBHOOK_SECRET)
    .update(`${t}.${req.body}`)
    .digest("hex");

  if (!crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) {
    return res.sendStatus(400);
  }

  const event = JSON.parse(req.body);
  // enfileire e processe async...
  res.sendStatus(200);
});

Verificar em Python

Python (Flask)
import hmac, hashlib, time, os
from flask import Flask, request, abort

app = Flask(__name__)

@app.post("/webhooks/trackpag")
def trackpag_webhook():
    header = dict(p.split("=") for p in request.headers.get("X-TrackPag-Signature", "").split(","))
    t, v1 = header.get("t", "0"), header.get("v1", "")

    if abs(time.time() - int(t)) > 300:
        abort(400)

    expected = hmac.new(
        os.environ["TP_WEBHOOK_SECRET"].encode(),
        f"{t}.".encode() + request.get_data(),  # corpo bruto!
        hashlib.sha256,
    ).hexdigest()

    if not hmac.compare_digest(v1, expected):
        abort(400)

    event = request.get_json()
    # enfileire e processe async...
    return "", 200
Valide sempre sobre o corpo bruto da requisição, antes de qualquer parse — re-serializar o JSON muda os bytes e invalida a assinatura.

Retentativas

Se seu endpoint não responder 2xx em 5 segundos, a entrega entra na fila de retentativa com backoff:

TentativaEspera após a falha
1ª retentativa1 minuto
10 minutos
1 hora
6 horas
5ª (última)24 horas

Depois da última falha o evento fica disponível para reenvio manual pelo suporte. Como entregas podem repetir, deduplique pelo id do evento.

Travou em algum passo? Escreva para suporte@trackpag.com.br com o id do recurso — a gente responde rápido.