Skip to content

Autenticação ​

Visão geral ​

A API BaaS usa o OAuth 2.0 Client Credentials Flow para autenticação server-to-server. Todos os endpoints (exceto /v1/authentication/oauth/access-token) exigem um Bearer token válido no header Authorization.

Pontos-chave:

  • Os tokens são baseados em JWT, com validade padrão de 1 hora
  • A renovação do token é automática quando ele está perto de expirar
  • O que o seu client pode chamar é controlado por tenant, pelas famílias de produto habilitadas (BANKING, CRYPTO, KYC, …) — veja Permissões e produtos

Nota: Os endpoints de token (access-token, introspect, revoke) não têm rate limit de billing por tenant. O único rate limiter do gateway se aplica às rotas de antifraude/financeiras (padrão ~200 requisições/minuto por IP de client, configurável via ANTIFRAUD_RATE_LIMIT).


Setup — obtendo as credenciais de client ​

Para integrar com a API BaaS, você precisa de Client_ID e Client_Secret.

Solicitando as credenciais ​

  1. Contate o suporte: envie um e-mail para [email protected] com os detalhes da sua integração:

    • Nome da empresa
    • Objetivo da integração (ex.: "Plataforma de Folha de Pagamento", "Integração Contábil")
    • Volume de transações esperado
    • Lista dos produtos necessários (veja Permissões e produtos)
  2. Setup pela Axia: o nosso time vai:

    • Criar as credenciais no BackOffice
    • Entregá-las por link seguro (válido por 24 horas)
    • Documentar os produtos habilitados
  3. Armazene com segurança: guarde as credenciais em variáveis de ambiente ou em um vault:

bash
# .env (never commit this file)
BAAS_CLIENT_ID=axia_prod_abc123xyz
BAAS_CLIENT_SECRET=sk_live_super_secret_never_commit
bash
# Or use a vault (recommended for production)
vault kv put secret/baas \
  client_id=axia_prod_abc123xyz \
  client_secret=sk_live_super_secret_never_commit

⚠️ Lembrete de segurança: nunca compartilhe nem commite o Client_Secret. Cada integrador tem credenciais únicas, atreladas ao contexto do seu tenant.


Tenant ID — um identificador, vários nomes ​

O seu Tenant ID é o mesmo valor do Client_ID do OAuth — o identificador que a Axia atribuiu à sua organização no setup (tipicamente um UUID, ex.: 27c0767f-0abe-40ce-81d9-c168a71354b5). Não existe um "tenant id" separado a ser solicitado: o Client_ID é o tenant id.

O mesmo identificador aparece com nomes diferentes ao longo da API. Todos são o mesmo valor:

Onde apareceNome usadoDireção
Credenciais OAuth (auth Basic nos endpoints de token)Client_IDvocê → API
Header HTTP nas chamadas de APIx-client-idvocê → API
Body do POST /v1/bank-accounts/createapplicationvocê → API
Respostas de checkOnboarding / de contaclientCodeAPI → você
Payloads de cripto/OTC/webhookclientIdAPI → você

Quando enviá-lo — e por que às vezes você recebe MISSING_CLIENT_ID ​

Toda rota /v1/* exceto /v1/authentication/* passa pela validação de tenant do gateway. O gateway precisa resolver o seu tenant em toda requisição; quando não consegue, a requisição falha com:

json
{
  "error": "MISSING_CLIENT_ID",
  "message": "Client ID (x-client-id) is required"
}

(HTTP 400)

Importante: o Bearer token sozinho não basta — a validação de tenant roda antes de o client do token ser resolvido. O gateway procura o seu tenant id nesta ordem:

  1. Campo application no body da requisição — presente apenas se você o incluir explicitamente no seu payload JSON (como fazem os exemplos de criação de conta)
  2. Header client_id
  3. Header x-client-id

Regra prática: sempre envie o header x-client-id: <seu Client_ID> em toda chamada de API (exceto nos endpoints de token /v1/authentication/*, que usam auth Basic). Não dependa apenas do campo application no body — requisições GET não têm body, e esquecer o campo em um POST resulta no mesmo 400.

bash
curl "https://baas-gtw.axiadigitalsolutions.com/v1/bank-accounts/balance?accountId=30054029183&documentNumber=48059890093" \
  -H "Authorization: Bearer $TOKEN" \
  -H "x-client-id: 27c0767f-0abe-40ce-81d9-c168a71354b5"

Outros erros de tenant vindos da mesma validação ​

HTTPerrorSignificado
400MISSING_CLIENT_IDTenant id não encontrado no body/headers — adicione o x-client-id
402ACCOUNT_SUSPENDED / ACCOUNT_RESTRICTEDO status de billing do tenant bloqueia a operação
403PRODUCT_NOT_ENABLEDFamília de produto (BANKING / CRYPTO / KYC / …) não habilitada para o seu tenant
403OPERATION_NOT_ALLOWEDTenant restrito a um subconjunto de operações (ex.: apenas PIX)

Consulte Tratamento de Erros para o catálogo completo.


POST /v1/authentication/oauth/access-token ​

Solicita um Bearer token de acesso à API usando Client Credentials.

Descrição ​

Este endpoint troca o seu Client_ID e Client_Secret por um token JWT assinado, válido por 1 hora. O token dá acesso às operações de API das famílias de produto habilitadas para o seu tenant (veja Permissões e produtos).

Headers ​

HeaderValor
AuthorizationBasic <Base64(Client_ID:Client_Secret)>
Content-Typeapplication/json

Request ​

Não requer body.

Exemplo ​

Passo 1: codifique as credenciais em Base64

bash
CREDS=$(echo -n "$BAAS_CLIENT_ID:$BAAS_CLIENT_SECRET" | base64)
echo $CREDS
# Output: YXhpYV9wcm9kX2FiYzEyM3h5ejo6c2tfbGl2ZV9zdXBlcl9zZWNyZXQ=

Passo 2: solicite o token

bash
curl -X POST https://baas-gtw.axiadigitalsolutions.com/v1/authentication/oauth/access-token \
  -H "Authorization: Basic $CREDS" \
  -H "Content-Type: application/json"

Response 201 Created ​

json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im9hdXRoMjAyNDAzMTUifQ.eyJzdWIiOiJheGlhX3Byb2RfYWJjMTIzeHl6IiwiY2xpZW50X2lkIjoiYXhpYV9wcm9kX2FiYzEyM3h5eiIsImV4cCI6MTcxMDc4NjQwMCwiaWF0IjoxNzEwNzgyODAwLCJzY29wZSI6ImFjY291bnRzOnJlYWQgYWNjb3VudHM6d3JpdGUgcGl4OnNlbmQgd2ViaG9va3M6bWFuYWdlIn0.xyz...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "issued_at": "2024-03-15T10:00:00Z",
  "scope": "accounts:read accounts:write pix:send webhooks:manage"
}

Erros ​

Se o header Authorization estiver ausente, a requisição falha com a mensagem You must send an Authorization header. Se ele estiver presente mas não for um token Basic, falha com Expected a Basic token. Quando as credenciais são rejeitadas pelo identity provider, a falha é retornada pelo conversor de erro padrão como um status não-2xx, com um body JSON contendo um campo message.


Renovação e cache de token ​

Quando renovar ​

Os tokens expiram após 1 hora. Para evitar interrupções, renove 5 minutos antes da expiração em vez de esperar pelos erros de expiração.

Estratégia: renovação preventiva ​

Verifique o campo expires_in e agende uma renovação quando:

  • Horário atual + 5 minutos >= horário de expiração do token

Exemplo em Node.js / TypeScript ​

typescript
class BaaSClient {
  private token: string | null = null;
  private expiresAt: number = 0;
  private readonly clientId: string;
  private readonly clientSecret: string;
  private readonly baseUrl: string = 
    'https://baas-gtw.axiadigitalsolutions.com';

  constructor(clientId: string, clientSecret: string) {
    this.clientId = clientId;
    this.clientSecret = clientSecret;
  }

  private getBasicAuth(): string {
    const creds = `${this.clientId}:${this.clientSecret}`;
    return Buffer.from(creds).toString('base64');
  }

  async getToken(): Promise<string> {
    // Retorna o token em cache se ainda for válido (com margem de 5 min)
    const bufferMs = 5 * 60 * 1000;
    if (this.token && Date.now() < this.expiresAt - bufferMs) {
      return this.token;
    }

    // Solicita um novo token
    const response = await fetch(
      `${this.baseUrl}/v1/authentication/oauth/access-token`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Basic ${this.getBasicAuth()}`,
          'Content-Type': 'application/json',
        },
      }
    );

    if (!response.ok) {
      throw new Error(
        `Token request failed: ${response.status} ${response.statusText}`
      );
    }

    const data = await response.json();
    this.token = data.access_token;
    // Calcula o timestamp absoluto de expiração
    this.expiresAt = Date.now() + data.expires_in * 1000;

    return this.token;
  }

  async makeRequest<T>(
    method: string,
    path: string,
    body?: unknown
  ): Promise<T> {
    const token = await this.getToken();
    const response = await fetch(`${this.baseUrl}${path}`, {
      method,
      headers: {
        'Authorization': `Bearer ${token}`,
        // Tenant id — mesmo valor do Client_ID do OAuth. Obrigatório em toda
        // chamada de API; sem ele o gateway retorna 400 MISSING_CLIENT_ID.
        'x-client-id': this.clientId,
        'Content-Type': 'application/json',
      },
      body: body ? JSON.stringify(body) : undefined,
    });

    if (!response.ok) {
      throw new Error(
        `API request failed: ${response.status} ${response.statusText}`
      );
    }

    return response.json() as Promise<T>;
  }
}

// Uso
const client = new BaaSClient(
  process.env.BAAS_CLIENT_ID!,
  process.env.BAAS_CLIENT_SECRET!
);

// A primeira chamada busca o token
const balance = await client.makeRequest<Balance>(
  'GET',
  '/v1/bank-accounts/balance?accountId=30054029183&documentNumber=48059890093'
);

// A segunda chamada reaproveita o token (ainda válido)
const onboarding = await client.makeRequest<Onboarding>(
  'GET',
  '/v1/bank-accounts/checkOnboarding?onBoardingId=48059890093'
);

// Após 55 minutos, a próxima chamada renova automaticamente

Exemplo em Python ​

python
import os
import base64
import time
import requests
from datetime import datetime

class BaaSClient:
    def __init__(self, client_id: str, client_secret: str):
        self.client_id = client_id
        self.client_secret = client_secret
        self.base_url = "https://baas-gtw.axiadigitalsolutions.com"
        self.token = None
        self.expires_at = 0

    def get_basic_auth(self) -> str:
        creds = f"{self.client_id}:{self.client_secret}"
        encoded = base64.b64encode(creds.encode()).decode()
        return encoded

    def get_token(self) -> str:
        # Verifica se o token em cache ainda é válido (margem de 5 min)
        buffer_seconds = 5 * 60
        if self.token and time.time() < self.expires_at - buffer_seconds:
            return self.token

        # Solicita um novo token
        response = requests.post(
            f"{self.base_url}/v1/authentication/oauth/access-token",
            headers={
                "Authorization": f"Basic {self.get_basic_auth()}",
                "Content-Type": "application/json",
            },
        )
        response.raise_for_status()

        data = response.json()
        self.token = data["access_token"]
        self.expires_at = time.time() + data["expires_in"]

        return self.token

    def request(self, method: str, path: str, json=None):
        token = self.get_token()
        response = requests.request(
            method,
            f"{self.base_url}{path}",
            headers={
                "Authorization": f"Bearer {token}",
                # Tenant id — mesmo valor do Client_ID do OAuth; obrigatório em
                # toda chamada de API (caso contrário, 400 MISSING_CLIENT_ID)
                "x-client-id": self.client_id,
                "Content-Type": "application/json",
            },
            json=json,
        )
        response.raise_for_status()
        return response.json()

# Uso
client = BaaSClient(
    os.getenv("BAAS_CLIENT_ID"),
    os.getenv("BAAS_CLIENT_SECRET"),
)

balance = client.request(
    "GET",
    "/v1/bank-accounts/balance?accountId=30054029183&documentNumber=48059890093",
)
print(balance)

POST /v1/authentication/oauth/introspect ​

Valida um token e retorna os seus metadados (status ativo, expiração, scopes).

Descrição ​

Use este endpoint para verificar se um token ainda está ativo antes de fazer chamadas de API. Útil para debug ou para validar o estado do token em logs de auditoria.

Headers ​

HeaderValor
AuthorizationBasic <Base64(Client_ID:Client_Secret)>
tokenValor do Bearer token a inspecionar

O token a inspecionar é lido do header token da requisição, não de um query param. Enviá-lo como ?token= falha com You must send the bearer token on header.

Exemplo ​

bash
CREDS=$(echo -n "$BAAS_CLIENT_ID:$BAAS_CLIENT_SECRET" | base64)
TOKEN="eyJhbGciOiJSUzI1NiIs..."

curl -X POST "https://baas-gtw.axiadigitalsolutions.com/v1/authentication/oauth/introspect" \
  -H "Authorization: Basic $CREDS" \
  -H "token: $TOKEN" \
  -H "Content-Type: application/json"

Response 201 Created (token ativo) ​

json
{
  "active": true,
  "client_id": "axia_prod_abc123xyz",
  "token_type": "Bearer",
  "exp": 1710786400,
  "iat": 1710782800,
  "issued_at": "2024-03-15T10:00:00Z",
  "expires_at": "2024-03-15T11:00:00Z",
  "scope": "accounts:read accounts:write pix:send webhooks:manage"
}

Response 201 Created (token expirado) ​

json
{
  "active": false,
  "reason": "Token expired on 2024-03-15T11:00:00Z"
}

Response 201 Created (token revogado) ​

json
{
  "active": false,
  "reason": "Token was revoked"
}

POST /v1/authentication/oauth/revoke ​

Revoga um token e invalida imediatamente todos os grants associados.

Descrição ​

Use este endpoint para deslogar um client ou rotacionar credenciais. Tokens revogados não podem ser reutilizados, e a próxima chamada de API vai exigir um token novo.

Headers ​

HeaderValor
AuthorizationBasic <Base64(Client_ID:Client_Secret)>
tokenValor do Bearer token a revogar

O token a revogar é lido do header token da requisição, não de um query param. Enviá-lo como ?token= falha com You must send the bearer token on header.

Exemplo ​

bash
CREDS=$(echo -n "$BAAS_CLIENT_ID:$BAAS_CLIENT_SECRET" | base64)
TOKEN="eyJhbGciOiJSUzI1NiIs..."

curl -X POST "https://baas-gtw.axiadigitalsolutions.com/v1/authentication/oauth/revoke" \
  -H "Authorization: Basic $CREDS" \
  -H "token: $TOKEN" \
  -H "Content-Type: application/json"

Response 200 OK ​

Em caso de sucesso, o endpoint retorna um envelope JSON confirmando a revogação:

json
{
  "body": "Token revoked",
  "when": 1710786400000
}

Erros ​

Se o header Authorization estiver ausente, a requisição falha com You must send an Authorization header. Se o header token estiver ausente, falha com You must send the bearer token on header. Qualquer falha do identity provider é retornada pelo conversor de erro padrão como um status não-2xx, com um body JSON contendo um campo message.


Permissões e produtos ​

O controle de acesso é por tenant, configurado pela Axia no setup — não há negociação de scope em runtime na requisição de token. Dois mecanismos se aplicam em toda chamada:

1. Famílias de produto (enabledProducts): cada área da API pertence a uma família de produto que precisa estar habilitada para o seu tenant. Chamar uma rota de uma família desabilitada retorna 403 PRODUCT_NOT_ENABLED.

Família de produtoÁreas da API
BANKINGContas bancárias, PIX, boletos, transferências
CRYPTOCarteiras cripto, trades de OTC
CRYPTO_BRIDGEBridge cross-chain
KYCAPI standalone de verificação KYC
SALARY_ADVANCEAntecipação de salário (consignado)

2. Restrições de operação (allowedOperations): um tenant pode, adicionalmente, ser restrito a um subconjunto de operações (ex.: apenas PIX). Chamadas bloqueadas retornam 403 OPERATION_NOT_ALLOWED.

Nota: ambos são atribuídos por tenant e não podem ser alterados em runtime. Contate o suporte para habilitar produtos adicionais ou remover restrições. A string scope que pode aparecer na resposta do token é informativa — o enforcement acontece pelos gates de produto/operação acima.


Tratamento de erros ​

Comportamento ​

Os endpoints de autenticação não emitem códigos de erro de aplicação estruturados. A validação dos headers da requisição lança um erro simples com uma mensagem descritiva, e as falhas do identity provider são repassadas pelo conversor de erro padrão do gateway.

SituaçãoMensagem
Header Authorization ausenteYou must send an Authorization header
Authorization presente mas não é BasicExpected a Basic token
Header token ausente (introspect / revoke)You must send the bearer token on header
Credenciais/token rejeitados pelo identity providerRepassado pelo conversor de erro padrão (status não-2xx com um campo message)

Exemplo de resposta de erro ​

json
{
  "message": "Expected a Basic token"
}

Boas práticas ​

Faça ✅ ​

  • Mantenha os tokens em cache em memória entre requisições (reduz carga e latência)
  • Renove os tokens proativamente (5 minutos antes da expiração)
  • Use variáveis de ambiente ou um vault para armazenar as credenciais
  • Logue os erros de autenticação (401, 403) para debug
  • Implemente exponential backoff nos retries (erros 500, 504)
  • Armazene o timestamp de expiração do token e verifique antes de cada chamada de API
  • Rotacione as credenciais periodicamente (ex.: trimestralmente) por segurança

Não faça ❌ ​

  • Nunca logue nem imprima tokens no console ou em arquivos
  • Nunca commite credenciais no controle de versão (use .gitignore)
  • Nunca compartilhe o Client_Secret entre times ou ambientes
  • Nunca deixe credenciais hardcoded no código da aplicação
  • Nunca confie no conteúdo do token sem validar a assinatura (use o introspect)
  • Nunca faça retry imediato em erros 401 (provavelmente é um problema permanente de credencial)
  • Nunca armazene tokens no localStorage ou em storage client-side (somente backend)

Arquitetura recomendada ​

┌─────────────────────┐
│  Sua aplicação      │
│   (server-side)     │
└──────────┬──────────┘
           │
      ┌────▼─────────────────┐
      │  BaaS Client Library  │
      │  (cache de token +    │
      │   refresh + retries)  │
      └────┬──────────────────┘
           │
      ┌────▼─────────────────┐
      │  BaaS API Gateway    │
      │  (validação +        │
      │   check de scope)    │
      └─────────────────────┘
  • Mantenha as credenciais em um vault seguro (HashiCorp Vault, AWS Secrets Manager, etc.)
  • Use uma client library (exemplo em Node.js acima) para tratar a renovação do token automaticamente
  • Nunca exponha credenciais em logs ou mensagens de erro
  • Use somente HTTPS em todas as comunicações com a API