Segurança da Conta

Três controles que o titular da conta configura e que a API passa a aplicar em toda tentativa de saída de dinheiro: travas de cashout, PIN transacional e visibilidade de quem tem acesso compartilhado à conta.

Eles existem para o cenário em que a credencial e o token do integrador estão corretos — e é a sessão do correntista que foi tomada. Nada aqui é opt-out por requisição: o que o titular configurou vale mesmo para a credencial que o configurou.

Nada muda se você não usar

Toda conta começa sem trava e sem PIN, e o comportamento é o de hoje. Os controles só passam a valer depois de configurados.

Travas de cashout

account security locks são três limites independentes:

CampoEfeito
cashoutBlockedtrue recusa toda saída da conta
cashoutHoursSó permite saída dentro da janela (HH:MM, 24h, com timezone)
cashoutSourceIpsSó permite saída de IPs/CIDRs declarados

Ler

curl "https://tenant.api.corpx.com/v1/accounts/acc-123/security/locks" \
-H "Authorization: Bearer $TOKEN" -H "X-Tenant-Id: tenant-suaempresa"
{
"accountId": "acc-123",
"current": {
"cashoutBlocked": false,
"cashoutHours": { "start": "08:00", "end": "18:00", "timezone": "America/Sao_Paulo" },
"cashoutSourceIps": ["200.10.20.30/32"]
},
"updatedAt": "2026-09-19T12:00:00Z"
}

Escrever

PUT recebe o documento inteiro desejado (escopo security_locks.manage):

curl -X PUT "https://tenant.api.corpx.com/v1/accounts/acc-123/security/locks" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Tenant-Id: tenant-suaempresa" \
-H "X-Acting-Document: 12345678909" \
-H "X-Acting-Ip: 200.10.20.30" \
-H "Content-Type: application/json" \
-d '{
"cashoutBlocked": false,
"cashoutHours": { "start": "08:00", "end": "18:00", "timezone": "America/Sao_Paulo" },
"cashoutSourceIps": ["200.10.20.30/32"]
}'

Apertar vale já; afrouxar espera 6 horas

Esta é a parte que muda o seu fluxo, então vale ler com atenção: a decisão é campo por campo.

MudançaQuando vale
Ligar cashoutBlockedImediato
Desligar cashoutBlocked+6h
Estreitar cashoutHours, ou passar a ter janelaImediato
Ampliar ou remover cashoutHours+6h
Remover IP de cashoutSourceIpsImediato
Adicionar IP, ou remover a lista toda+6h

Quem liga o bloqueio e amplia o horário na mesma chamada tem o bloqueio agora e o horário depois. A resposta diz exatamente isso:

{
"accountId": "acc-123",
"current": { "cashoutBlocked": true, "cashoutHours": { "start": "08:00", "end": "18:00" } },
"pending": { "cashoutBlocked": true, "cashoutHours": { "start": "00:00", "end": "23:59" } },
"pendingEffectiveAt": "2026-09-19T18:00:00Z",
"pendingReason": "relaxing_security_requires_grace"
}

A assimetria é o desenho inteiro: quem tomou a conta quer desligar o bloqueio, ampliar o horário, adicionar o próprio IP — nunca apertar. Uma carência simétrica protegeria o atacante e puniria o titular que está reagindo a uma fraude em andamento.

Cancelar ou antecipar o afrouxamento

# Cancelar: descarta o pendente, o current continua valendo. Imediato.
curl -X DELETE ".../v1/accounts/acc-123/security/locks/pending" ...
# Antecipar: promove o pendente agora. EXIGE o PIN do operador.
curl -X POST ".../v1/accounts/acc-123/security/locks/pending/approve" \
-H "X-Acting-Document: 12345678909" \
-H "X-Transaction-Pin: 918273" ...

Antecipar é o único caminho que encurta a carência, e por isso ele custa a única coisa que quem invadiu a sessão não tem: o PIN. Sem esse endpoint, o titular legítimo que quer liberar o próprio cashout teria de esperar 6h sem alternativa.

X-Acting-Ip

Quando a chamada vem de um servidor seu em nome do correntista (o caso do internet banking), o IP da conexão é o do seu servidor, não o do usuário. cashoutSourceIps seria inútil. Informe o IP real do usuário em X-Acting-Ip — é ele que a trava avalia.

O header só é aceito de credenciais de integrador. Uma credencial delegada é usada direto pelo dono, então o IP da conexão já é o certo e X-Acting-Ip é ignorado.

Erros

CodeHTTPQuando
cashout_locked423cashoutBlocked: true
cashout_outside_hours403Fora de cashoutHours. A mensagem traz a janela
cashout_source_ip_not_allowed403IP de origem fora de cashoutSourceIps
invalid_cashout_hours422HH:MM inválido, start == end, ou timezone desconhecido
no_pending_change404DELETE/approve sem afrouxamento agendado

PIN transacional

O PIN é do operador (identificado pelo CPF em X-Acting-Document), não da conta. Uma conta com três pessoas autorizadas tem três PINs; travar o PIN de uma não afeta as outras.

Ele só é exigido quando a credencial do chamador está marcada para isso — na prática, a credencial do internet banking, onde uma única credencial atende muitos correntistas e o token, sozinho, não distingue quem está do outro lado da tela.

Cadastrar e trocar

curl -X PUT "https://tenant.api.corpx.com/v1/accounts/acc-123/security/pin" \
-H "Authorization: Bearer $TOKEN" -H "X-Tenant-Id: tenant-suaempresa" \
-H "Content-Type: application/json" \
-d '{ "actingDocument": "12345678909", "pin": "918273" }'
{ "accountId": "acc-123", "actingDocument": "123.***.***-09", "status": "created" }

Trocar um PIN existente exige o atual no mesmo corpo (currentPin). Sem isso, quem tomou a sessão trocaria o PIN e o PIN pararia de proteger qualquer coisa.

O escopo é pin.manage. O PIN nunca aparece em log ou resposta — é armazenado como hash argon2id e o valor em claro é descartado.

Regras do PIN

RegraValor
Tamanho6 a 12 dígitos
Só dígitosSim
RecusaDígitos todos iguais (111111), sequência inclusive com volta (123456, 654321, 890123), padrão de período curto (121212, 123123) e PIN contido na data de nascimento ou no documento do titular

PIN recusado devolve 422 weak_pin com a razão nomeada.

Usar

Nas rotas de saída (PIX out, TED, boleto, transferência interna), quando a credencial exige PIN:

curl -X POST ".../v1/accounts/acc-123/pix/payments" \
-H "X-Acting-Document: 12345678909" \
-H "X-Transaction-Pin: 918273" ...

Falta de qualquer um dos dois devolve 428 pin_required.

Bloqueio por tentativas

Tentativas erradasEfeito
3Bloqueio de 15 minutos (429 pin_temporarily_locked, com header Retry-After)
6Bloqueio até redefinição (423 pin_locked)

Um PIN correto zera o contador. Para destravar o caso de 6 tentativas, quem administra a conta invalida o PIN daquele operador e ele cadastra outro:

curl -X DELETE ".../v1/accounts/acc-123/security/pin/12345678909" ...

Verificar antes de montar o pagamento

curl -X POST ".../v1/accounts/acc-123/security/pin/verify" \
-H "Content-Type: application/json" \
-d '{ "actingDocument": "12345678909", "pin": "918273" }'

Existe para a tela confirmar o PIN antes do formulário de pagamento. Sem ele, o usuário descobriria o PIN errado no fim do fluxo — e cada erro queimaria uma das 3 tentativas. Tentativa errada aqui conta igual: o endpoint não é um oráculo grátis.

Estado dos operadores

curl ".../v1/accounts/acc-123/security/pin/status" ...
{
"accountId": "acc-123",
"items": [
{ "actingDocument": "123.***.***-09", "failedAttempts": 0, "locked": false,
"setAt": "2026-09-19T12:00:00Z", "updatedAt": "2026-09-19T12:00:00Z" },
{ "actingDocument": "987.***.***-21", "failedAttempts": 6, "locked": true,
"lockedUntil": null, "requiresReset": true,
"setAt": "2026-09-01T10:00:00Z", "updatedAt": "2026-09-19T14:22:00Z" }
],
"policy": { "minLength": 6, "maxLength": 12, "softLockAfter": 3,
"softLockMinutes": 15, "hardLockAfter": 6,
"digitsOnly": true, "rejectsSequential": true }
}

Documentos saem mascarados. lockedUntil: null com requiresReset: true é o bloqueio duro — a saída é redefinir, não esperar.

Erros

CodeHTTPQuando
pin_required428Rota de saída sem X-Acting-Document / X-Transaction-Pin
pin_invalid403PIN errado. A tentativa foi contada
pin_not_set403Aquele operador não tem PIN cadastrado nesta conta
pin_temporarily_locked4293 erros. Aguarde os 15 minutos
pin_locked4236 erros. Exige redefinição
weak_pin422PIN fora da política
pin_not_found404DELETE de um operador sem PIN

Acesso compartilhado

Uma mesma conta bancária pode ser acessada por mais de um tenant — o correntista contratou dois sistemas, ou migrou de um para outro e o antigo ainda tem acesso. O titular tem direito de ver isso:

curl ".../v1/accounts/acc-123/shared-access" \
-H "Authorization: Bearer $TOKEN" -H "X-Tenant-Id: tenant-suaempresa"
{
"accountId": "acc-123",
"items": [
{ "tenantId": "tenant-suaempresa", "displayName": "Sua Empresa",
"status": "active", "since": "2026-01-15T10:00:00Z", "isCurrent": true },
{ "tenantId": "tenant-outro", "displayName": "Outro Integrador",
"status": "suspended", "since": "2025-08-02T09:30:00Z", "isCurrent": false }
]
}

Só metadado público: nome de exibição, estado e desde quando. Nada de credencial, volume, saldo ou configuração dos outros tenants. status é o do acesso daquele tenant à conta, não o do tenant — uma linha suspended aparece justamente para o titular confirmar que a revogação pegou.

Escopo de leitura. Revogar acesso é operação de backoffice, não desta rota.

Ver também