# Da sua chave ao primeiro dado.

Guia completo do RPG Connecta: chaves API, sandbox, consentimento bancário, dados, webhooks e produção. Documentação pública para pessoas e agentes.

API: https://www.rpgcapital.com.br/api/connecta/v1
Console: https://www.rpgcapital.com.br/developers
OpenAPI: https://www.rpgcapital.com.br/developers/connecta-openapi.json

## Da conta à primeira resposta

Entre com Google no console. Escolha Sandbox, crie uma chave com nome e guarde o valor completo imediatamente: ele aparece uma única vez. Não precisa cadastrar aplicativo, informar URL de site ou ter conta na Malvo.

Salve a chave como RPG_API_KEY no backend. Crie uma conexão fictícia, guarde data.id como RPG_CONNECTION_ID e consulte contas e transações. Os exemplos abaixo executam fora do console; as consultas no console usam sua sessão autenticada.

- 1. Crie sua chave RPG de sandbox.
- 2. Execute o quickstart e guarde o ID da conexão.
- 3. Explore o JSON, altere cenários e acompanhe eventos.

```bash
# Requires bash, curl and jq. Store your sandbox key in RPG_API_KEY.
set -euo pipefail
: "${RPG_API_KEY:?Set RPG_API_KEY in your shell}"
BASE='https://www.rpgcapital.com.br/api/connecta/v1'
CONNECTION_ID=$(curl --fail-with-body -sS "$BASE/connections" \
  -H "Authorization: Bearer $RPG_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"provider":"rpg_simulator","scenario":"success"}' | jq -er '.data.id')
curl --fail-with-body -sS "$BASE/connections/$CONNECTION_ID/accounts" \
  -H "Authorization: Bearer $RPG_API_KEY"
curl --fail-with-body -sS "$BASE/connections/$CONNECTION_ID/transactions?offset=0" \
  -H "Authorization: Bearer $RPG_API_KEY"
```

## Chaves, permissões e ambientes

Envie Authorization: Bearer seguido da chave RPG em toda chamada. rpg_test_ identifica sandbox; rpg_live_ identifica produção. O cabeçalho opcional X-RPG-Environment deve corresponder à chave. A credencial acessa somente conexões do seu titular e ambiente.

Guarde segredos em variáveis do servidor ou gerenciador de segredos. Nunca em código do navegador, prompts públicos, logs ou Git. Renomeie pelo console; para rotacionar, crie uma substituta, atualize o backend e revogue a antiga. A revogação é imediata.

- Limite: 10 chaves ativas por usuário e ambiente.
- Limite: 60 requisições por minuto por chave. Respeite Retry-After no HTTP 429.
- Limite: 20 conexões ativas por usuário e ambiente.

## Um sandbox completo dentro do painel

O simulador RPG mantém contas e transações fictícias por conexão. Use provider=rpg_simulator e depois POST /connections/{id}/simulate com um cenário. Não conecta banco, não exige cartão e não faz pagamento real.

success gera uma base completa; pending aguarda autorização; expired pede renovação; unavailable simula indisponibilidade; partial expõe dados incompletos. Dados válidos anteriores podem continuar visíveis em indisponibilidade ou pendência: consulte status e last_synced_at.

O sandbox Malvo dedicado é outro adaptador e depende de credenciais próprias configuradas pela RPG. Sua disponibilidade aparece nas opções avançadas. A prévia anônima /developers/sandbox/data é uma base pequena separada, não seu workspace persistente.

- Use success após outro cenário para restaurar a base fictícia completa.
- Reutilize IDs nas execuções e desconecte bases que não usa mais.

## Produção e consentimento bancário

Ative Produção explicitamente no console, crie uma chave desse ambiente e envie POST /connections com {"provider":"malvo"}. A RPG autentica no servidor com a própria conta Malvo. A resposta traz connect_url temporária para o titular autorizar acesso bancário. Não registre nem deixe agentes abrirem ou pré-visualizarem esse link automaticamente.

A conexão pertence à conta RPG do desenvolvedor. Em integrações para clientes finais, seu backend deve associá-la ao cliente autenticado e verificar essa associação antes de devolver dados. Nunca entregue a chave RPG ao navegador do cliente.

Após a autorização, seu backend envia POST /connections/{id}/complete com {"item_id":"ID retornado"}. A RPG verifica a titularidade no provedor. O retorno /developers/connect conclui o fluxo de um desenvolvedor logado; a jornada de cliente final exige conclusão pelo seu próprio backend autenticado.

Consulte GET /connections/{id} para acompanhar o estado. POST /sync lê os dados disponíveis no provedor, sem garantir nova atualização bancária. POST /reconnect gera novo link de consentimento. DELETE /connections/{id} desconecta e remove o snapshot local.

- Produção utiliza dados reais e exige consentimento do titular.
- O gateway de cobrança não está habilitado; ativar produção não cobra cartão.
- Cobertura e disponibilidade bancárias dependem do provedor e da instituição.

## Um contrato de dados previsível

As respostas são JSON. Listas têm data, pagination e meta. Valores monetários usam inteiros na menor unidade: 185000 BRL significa R$ 1.850,00. Preserve a moeda ao exibir ou somar valores. Transações positivas representam entradas; negativas representam saídas.

IDs identificam registros da origem: guarde-os para conciliação. Categoria pode ser texto, objeto do provedor ou null. Etiquetas podem não existir na origem; classificação ausente não significa ausência de atividade. Trate datas e campos ausentes explicitamente.

A resposta abaixo é ilustrativa. IDs, datas, categorias, registros e saldos reais podem variar. Os recursos publicados hoje são contas e transações; investimentos, relatórios de crédito, cartões e pagamentos não são recursos adicionais desta API.



```json
{
  "data": [{
    "id": "CONNECTION_ID_tx_1",
    "account_id": "CONNECTION_ID_checking",
    "date": "2026-10-31",
    "description": "Recebimento de cliente",
    "amount_minor": 185000,
    "currency": "BRL",
    "category": "Receitas",
    "tags": ["synthetic", "sandbox"]
  }],
  "pagination": {"offset": 0, "limit": 100, "total": 1, "next_offset": null},
  "meta": {"environment":"sandbox", "provider":"rpg_simulator", "synthetic":true, "status":"connected", "last_synced_at":"2026-10-31T12:00:00Z", "partial":false, "note":null}
}
```

## Paginação, dados parciais e atualização

Contas e transações aceitam offset inteiro não negativo. Cada página tem até 100 registros. Siga pagination.next_offset até null; transações também aceitam account_id. A primeira página pode não conter todo o histórico.

meta.partial e meta.status descrevem o snapshot. Mostre last_synced_at e um indicador de incompletude no produto. HTTP de sucesso pode trazer dados antigos ou parciais. O saldo não tem garantia de atualização em tempo real.

A coleta do provedor tem limites; históricos grandes podem ficar parciais. Repetir sync não remove esses limites. Eventos e requisições expõem os últimos 100 registros; o console mostra um histórico recente menor. Persista o histórico necessário para seu produto.



## Exemplos completos para executar

Use Node.js 18+ ou Python 3 com biblioteca padrão; não precisa instalar SDK. Exporte RPG_API_KEY no terminal com sua chave de sandbox. Salve o exemplo no arquivo indicado no primeiro comentário e execute.

Defina RPG_CONNECTION_ID para reutilizar a base nas próximas execuções. Os exemplos criam uma conexão fictícia somente quando essa variável não existe, consultam contas e percorrem as páginas de transações. Falhas incluem os detalhes retornados pelo servidor.



```javascript
// Node.js 18+. Save as quickstart.mjs; run: node quickstart.mjs
const base = 'https://www.rpgcapital.com.br/api/connecta/v1';
const key = process.env.RPG_API_KEY;
if (!key?.startsWith('rpg_test_')) throw new Error('Use a sandbox RPG_API_KEY');
async function api(path, body) {
  const response = await fetch(base + path, {
    method: body ? 'POST' : 'GET',
    signal: AbortSignal.timeout(30000),
    headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json' },
    ...(body ? { body: JSON.stringify(body) } : {})
  });
  const payload = await response.json();
  if (!response.ok) throw new Error(`${response.status} ${payload.error?.code}: ${payload.error?.message} [${payload.request_id}]`);
  return payload;
}
// Reuse RPG_CONNECTION_ID on subsequent runs to avoid creating duplicate fixtures.
const id = process.env.RPG_CONNECTION_ID || (await api('/connections', {
  provider: 'rpg_simulator', scenario: 'success'
})).data.id;
console.log('Connection:', id);
console.log('Accounts:', (await api(`/connections/${id}/accounts`)).data);
const transactions = [];
let offset = 0;
do {
  const page = await api(`/connections/${id}/transactions?offset=${offset}`);
  transactions.push(...page.data);
  offset = page.pagination.next_offset;
} while (offset !== null);
console.log('Transactions:', transactions);
```

```python
# Python 3, standard library only. Save as quickstart.py.
import json, os, urllib.request, urllib.error
BASE = 'https://www.rpgcapital.com.br/api/connecta/v1'
KEY = os.environ.get('RPG_API_KEY', '')
if not KEY.startswith('rpg_test_'):
    raise RuntimeError('Use a sandbox RPG_API_KEY')
def api(path, body=None):
    request = urllib.request.Request(BASE + path,
        data=json.dumps(body).encode() if body is not None else None,
        headers={'Authorization': 'Bearer ' + KEY, 'Content-Type': 'application/json'})
    try:
        with urllib.request.urlopen(request, timeout=30) as response:
            return json.load(response)
    except urllib.error.HTTPError as error:
        details = json.load(error)
        raise RuntimeError(f'{error.code}: {details}') from error
connection_id = os.environ.get('RPG_CONNECTION_ID') or api('/connections',
    {'provider': 'rpg_simulator', 'scenario': 'success'})['data']['id']
print('Connection:', connection_id)
print('Accounts:', api(f'/connections/{connection_id}/accounts')['data'])
transactions, offset = [], 0
while offset is not None:
    page = api(f'/connections/{connection_id}/transactions?offset={offset}')
    transactions.extend(page['data'])
    offset = page['pagination']['next_offset']
print('Transactions:', transactions)
```

## Webhooks assinados e processamento seguro

Configure um endpoint HTTPS público por ambiente no console. Copie o segredo de assinatura quando aparecer. RPG-Signature contém t=<timestamp Unix>,v1=<HMAC hexadecimal>. Calcule HMAC-SHA256(segredo, timestamp + "." + corpo bruto). Valide antes de interpretar ou processar os dados e rejeite diferenças de horário superiores a cinco minutos.

Use o ID do evento como chave única persistente. Grave o recebimento e enfileire o trabalho de negócio atomicamente; reentregas não podem repetir efeitos financeiros. O exemplo valida assinaturas e não executa operação de negócio: adicione persistência antes de processar eventos em produção.

O console mostra a entrega e permite reenvio manual. Não há retentativas automáticas. Eventos automáticos de entrada da Malvo também exigem configuração de segredo pela RPG; na ausência, use conclusão e sync explícito. Trate o evento como sinal para consultar o estado canônico da conexão.



```javascript
// Node.js 18+, no framework. Terminate HTTPS at your public hosting provider.
import http from 'node:http';
import { createHmac, timingSafeEqual } from 'node:crypto';
const secret = process.env.RPG_WEBHOOK_SECRET;
if (!secret) throw new Error('Set RPG_WEBHOOK_SECRET');
http.createServer(async (req, res) => {
  if (req.method !== 'POST' || req.url !== '/webhooks/rpg') { res.writeHead(404).end(); return; }
  const chunks = []; let size = 0;
  for await (const chunk of req) {
    size += chunk.length;
    if (size > 1_000_000) { res.writeHead(413).end(); return; }
    chunks.push(chunk);
  }
  const raw = Buffer.concat(chunks);
  const parts = String(req.headers['rpg-signature'] || '').split(',');
  const t = parts.find(p => p.startsWith('t='))?.slice(2) || '';
  if (!/^\d+$/.test(t) || Math.abs(Date.now()/1000 - Number(t)) > 300) { res.writeHead(401).end(); return; }
  const expected = createHmac('sha256', secret).update(t + '.').update(raw).digest();
  const valid = parts.filter(p => p.startsWith('v1=')).some(p => {
    const hex = p.slice(3); if (!/^[a-f0-9]{64}$/.test(hex)) return false;
    return timingSafeEqual(Buffer.from(hex, 'hex'), expected);
  });
  if (!valid) { res.writeHead(401).end(); return; }
  try {
    const event = JSON.parse(raw.toString('utf8'));
    // REQUIRED: persist event.id with a UNIQUE constraint in your database,
    // and enqueue the business effect in the same transaction (outbox pattern).
    // Duplicate event IDs must become a no-op, including after restarts.
    // This signature example intentionally performs no business effect.
    res.writeHead(200, {'Content-Type':'application/json'}).end(JSON.stringify({received:true,id:event.id}));
  } catch { res.writeHead(400).end(); }
}).listen(Number(process.env.PORT || 3000));
```

## Erros com uma próxima ação clara

Erros têm error.code, error.message e request_id; X-Request-ID também é retornado. Ao pedir suporte, envie o request ID, nunca a chave nem conteúdo financeiro.

Em falhas transitórias, use retentativas limitadas com espera exponencial e variação aleatória. Respeite Retry-After. Não repita POST /connections cegamente após timeout ambíguo: liste as conexões para evitar duplicação. Não existe contrato publicado de chave de idempotência.



```json
{
  "error": {
    "code": "environment_mismatch",
    "message": "Esta chave pertence a outro ambiente."
  },
  "request_id": "uuid"
}
```

## Monte um dashboard útil

Comece por uma rota no servidor que consulte a conexão associada ao cliente autenticado. Percorra páginas de contas e transações, preserve IDs e exiba saldos por moeda. Separe entradas e saídas; agrupe por mês e categoria mantendo categorias desconhecidas visíveis.

Mostre estado, última sincronização, dados parciais e ação de reconexão junto aos dados. HTTP 401 deve oferecer nova autenticação ou correção da credencial. Em falha bancária, preserve o último snapshot válido com data. Teste os cinco estados do sandbox antes de produção.



## Instruções para agentes de programação

Leia este guia e o OpenAPI antes de gerar código. Use o Markdown em inglês como entrada compacta. Mantenha placeholders para credenciais; oriente a pessoa a criar a chave no console e guardá-la nos segredos do backend.

Gere integração no servidor, associação de titularidade, paginação, validação de assinatura e erros com request IDs. Comece pelo sandbox. Não invente endpoints MCP, skills instaláveis, pacotes SDK, cobertura bancária, preços ou recursos de pagamento.

O agente pode criar código e explicar a autorização. Login Google, consentimento bancário e ativação devem permanecer visíveis à pessoa e respeitar ferramentas de autenticação e permissões disponíveis no ambiente do agente.



## Preparação para produção e limites atuais

Antes de lançar: rotacione credenciais de desenvolvimento, isole segredos por ambiente, confira titularidade dos clientes, teste consentimento expirado e dados parciais, valide assinaturas sobre corpo bruto e deduplicação persistente, e confirme monitoramento e suporte.

Disponível: login Google, chaves RPG, simulador persistente, adaptador Malvo de produção, contas, transações, eventos, diagnóstico de requisições e webhooks assinados com reenvio manual. Sandbox Malvo dedicado e eventos automáticos dependem da configuração do servidor.

Ainda não há servidor MCP publicado, SDK empacotado, retentativas automáticas ou gateway de cobrança. A API legada de lojas em /api/public/v1 e /developers/docs tem outro contrato e não usa chaves Connecta. Contato: comercial@rpgcapital.com.br.



## Endpoint

- GET /connections: Listar suas conexões
- POST /connections: Criar conexão fictícia ou de consentimento bancário
- GET /connections/{id}: Consultar estado da conexão
- GET /connections/{id}/accounts: Consultar contas e saldos; paginação por offset
- GET /connections/{id}/transactions: Consultar transações; filtros offset e account_id
- POST /connections/{id}/simulate: Alterar cenário do simulador RPG
- POST /connections/{id}/sync: Ler o snapshot mais recente do provedor
- POST /connections/{id}/complete: Verificar e vincular o item autorizado
- POST /connections/{id}/reconnect: Gerar novo link de consentimento bancário
- DELETE /connections/{id}: Desconectar e apagar o snapshot local
- GET /events: Consultar os últimos 100 eventos
- GET /requests: Consultar as últimas 100 requisições

## Dicionário de dados

- id: Identificador estável na origem; preserve para conciliação
- account_id: Conta associada à transação
- name / type: Nome de exibição e tipo da conta
- balance_minor: Saldo inteiro na menor unidade monetária
- amount_minor: Valor inteiro com sinal na menor unidade monetária
- currency: Código explícito da moeda; não misture moedas
- date: Data da transação na origem; trate ausências
- description: Descrição original da transação
- category: Texto, objeto ou null; trate todos os formatos
- tags: Classificação; cobertura depende da origem
- pagination.next_offset: Próximo offset, ou null quando acabar
- meta.synthetic / provider: Indica dado fictício e o provedor de origem
- meta.status / partial: Estado da conexão e indicação de incompletude
- meta.last_synced_at: Horário do snapshot; exiba na interface

## Status

- 401 invalid_api_key: Chave ausente, inválida ou revogada. Substitua a credencial do servidor; cookie de sessão não é chave API.
- 403 environment_mismatch: Cabeçalho e chave de ambientes diferentes. Use o ambiente correto ou remova o cabeçalho opcional.
- 403 production_inactive: Produção ainda não ativada. Ative explicitamente no console.
- 404 not_found: Conexão não encontrada para conta e ambiente. Confira ID, titular e ambiente da chave.
- 409 authorization_pending: Autorização bancária incompleta. Conclua o consentimento antes de sincronizar.
- 409 connection_limit / key_limit: Limite de recursos ativos atingido. Revogue chave ou desconecte conexão sem uso.
- 429 rate_limited: Limite de chamadas por chave atingido. Espere Retry-After e reduza consultas periódicas.
- 502 provider_error / provider_auth_error: Falha ou autenticação rejeitada no provedor. Repita falhas transitórias; se persistir, contate a RPG.
- 503 provider_not_configured: Credenciais do provedor indisponíveis. Use o simulador RPG ou contate o suporte.
- 400 invalid_scenario / invalid_offset: Parâmetro inválido. Use cenário válido e offset inteiro não negativo.
