Início rápido

Do internet banking até o primeiro saldo. Reserve uns minutos e um servidor com relógio sincronizado (NTP): a assinatura recusa um desvio maior que 5 minutos.

Antes de começar

  1. Guarde clientId, clientSecret, X-Tenant-Id e accountId em variáveis de ambiente — não em repositório.
  2. A chave privada fica só no servidor que vai assinar. A pública já está cadastrada; anote o kid.
  3. O IP de saída desse servidor precisa estar na allowlist da credencial.
  4. Espere o activeFrom (18 horas após a emissão). Antes disso, qualquer chamada responde 403 credential_not_yet_active. Isso é proteção, não um defeito.

Se a credencial ainda não existe, peça ao titular para emití-la no internet banking do banco. Esta documentação não cobre as telas do banco.

1. Pedir o token

O token vale 5 minutos. Guarde-o e reutilize até perto de expirar — um token por request esgota o emissor e pode ser recusado.

curl -X POST "https://auth.api.corpx.com/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET"
{
"access_token": "eyJraWQiOiJ…",
"expires_in": 300,
"token_type": "Bearer"
}

2. Conferir a assinatura sem mover dinheiro

Toda chamada a https://client.api.corpx.com/v1/** leva, além do token e do X-Tenant-Id:

HeaderValor
X-Request-TimestampUnix em segundos (o mesmo da string canônica)
X-Content-SHA256SHA-256 do corpo em hex minúsculo. Corpo vazio = hash do vazio
X-Request-SignatureJWS detached — veja Assinatura

Antes do primeiro saldo, use POST /v1/security/signature/verify. Ele devolve a string canônica que nós montamos e valid: true|false, sem criar nada. Quando valid é false, compare canonicalString caractere a caractere com a sua: o problema quase sempre é CRLF, path sem query ou timestamp em milissegundos.

Há um vetor de teste com chave pública, string canônica e JWS prontos para validar a implementação offline.

3. Primeiro saldo

Com a assinatura conferida:

curl -X GET "https://client.api.corpx.com/v1/accounts/$ACCOUNT_ID/balance" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Tenant-Id: $TENANT_ID" \
-H "X-Request-Timestamp: $TS" \
-H "X-Content-SHA256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" \
-H "X-Request-Signature: $SIG"

GET não tem corpo: o hash é sempre o do vazio, acima.

{
"accountId": "6ff57bc1-e4a9-403b-be62-42378b8aafd7",
"total": 18254.17,
"locked": 500.00,
"available": 17754.17,
"currency": "BRL",
"updatedAt": "2026-02-05T22:00:00Z"
}

Valores monetários são BRL com no máximo 2 casas decimais.

Se você apontar esta credencial para https://tenant.api.corpx.com, a resposta é 403 signed_host_required. O host antigo não verifica assinatura por request.

4. Confirmar quem você é

GET /v1/me (também no host assinado) devolve clientId, scopes e os contextos em que o token vale. Use para conferir que o X-Tenant-Id que você vai enviar está na lista.

Checklist do primeiro dia

  • Token reutilizado até expires_in
  • POST /v1/security/signature/verify com valid: true
  • GET /v1/accounts/{accountId}/balance no host client.api.corpx.com
  • Relógio do servidor com NTP
  • Chave privada fora do repositório e de logs

Depois

Contrato: Referência da API. Filtre operações com x-audience contendo ib.