🔒 Sub Usuário (Envio Restrito a uma Chave Fixa)
Esta página mostra como restringir um usuário da sua conta a enviar valor apenas para uma chave DEX fixa — normalmente a conta do titular do negócio — mantendo os recebimentos liberados.
O caso típico: uma loja com funcionários. Cada colaborador movimenta valores pelo DEX, mas tudo que ele envia vai obrigatoriamente para a conta central.
1. O Que Muda para o Usuário Restrito
| Operação | Sub Usuário |
|---|---|
| Envio DEX → DEX para a chave fixa | ✅ Liberado |
| Envio DEX → DEX para qualquer outro destino | ❌ Bloqueado |
| Recebimento DEX → DEX | ✅ Liberado |
| Recebimento de carteira externa | ✅ Liberado |
| Recebimento Pix | ✅ Liberado |
| SWAP entre moedas | ✅ Liberado |
| Link de cobrança | ✅ Liberado |
| Envio Pix | ❌ Bloqueado |
| Envio para carteira externa | ❌ Bloqueado |
| Envio para usuário sem carteira | ❌ Bloqueado |
| Cartão DEX (solicitar ou recarregar) | ❌ Bloqueado |
O SWAP fica liberado porque não move valor para fora — o usuário troca de moeda dentro da própria conta.
A restrição vale em qualquer canal: app, painel ou API. Um usuário restrito que use a própria credencial de API recebe a mesma recusa. Esconder o botão na sua interface é experiência, não controle — a recusa vem do servidor.
2. Credencial Necessária
A configuração exige a credencial pessoal de um usuário que administra sua conta de participante — gerada em Integrações → API, como qualquer credencial de usuário (veja Autenticação).
> Não use a credencial de participante (client_id/client_secret da empresa) aqui. Ela é de leitura sobre seus usuários e não configura restrições — a chamada será recusada.
curl -X POST https://api.dexkey.finance/v1/auth/api-key \
-H "Content-Type: application/json" \
-d '{ "clientId": "...", "clientSecret": "..." }'
Use o accessToken retornado nas chamadas abaixo.
3. Ativar a Restrição
curl -X PATCH https://api.dexkey.finance/v1/admin/users/{userId}/sub-user \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"fixedDestinationKey": "+595981234567",
"reason": "Funcionario da loja — centralizar movimentacao na conta do titular"
}'
Corpo enviado
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
fixedDestinationKey |
string (máx. 32) | ✅ | Chave DEX da conta que receberá os envios. Aceita telefone, e-mail ou account code — os mesmos formatos da transferência interna |
reason |
string (máx. 500) | ✅ | Motivo da restrição. Fica registrado para auditoria |
Resposta
{
"userId": "550e8400-e29b-41d4-a716-446655440000",
"subUserEnabled": true,
"fixedDestinationKey": "*********4567",
"fixedDestinationName": "Comercial Guarani LTDA",
"subUserEnabledAt": "2026-09-01T14:32:00.000Z"
}
> Confira o fixedDestinationName antes de dar a configuração por concluída. É a forma de perceber que a chave foi digitada errada antes de o dinheiro começar a ir para a conta errada. Se o seu fluxo é automatizado, compare o nome com o esperado e falhe alto quando divergir.
Números fora do Brasil
Chave estrangeira precisa do código do país. 981234567 não resolve; para um celular paraguaio use +595981234567.
É o erro mais comum na integração — se você aceita entrada de operador, valide o prefixo antes de enviar.
4. Trocar a Chave Fixa
O mesmo endpoint, com a chave nova.
O comportamento é idempotente: repetir com a mesma chave devolve 200 sem alterar nada nem gerar novo registro. Chave diferente é tratada como troca.
5. Remover a Restrição
curl -X DELETE https://api.dexkey.finance/v1/admin/users/{userId}/sub-user \
-H "Authorization: Bearer $TOKEN"
Devolve 200 com o mesmo formato da ativação, agora com subUserEnabled: false. O usuário volta a ter acesso total.
Também é idempotente — chamar sobre quem não está restrito devolve o estado atual, sem efeito.
6. Consultar Quem Está Restrito
GET /v1/admin/users e GET /v1/admin/users/{userId} trazem:
| Campo | Onde aparece | Descrição |
|---|---|---|
isSubUser |
lista e detalhe | Se o usuário está restrito |
subUserFixedDestinationUserId |
lista e detalhe | Conta de destino, como identificador |
subUser |
somente no detalhe | Bloco completo, com chave mascarada, nome do titular e data |
Na listagem, subUser vem sempre null — resolver o destino de cada linha custaria consultas extras por usuário. Para a listagem, use isSubUser.
7. O Que o App do Usuário Enxerga
GET /v1/profile/restrictions, com o token do próprio usuário, devolve tudo que restringe a conta dele:
{
"accountBlocked": false,
"operations": [
{ "operation": "SEND_INTERNAL", "allowed": true, "reason": "SUB_USER_FIXED_DESTINATION_ONLY" },
{ "operation": "SEND_PIX", "allowed": false, "reason": "SUB_USER_BLOCKED" },
{ "operation": "SEND_CRYPTO", "allowed": false, "reason": "SUB_USER_BLOCKED" },
{ "operation": "SEND_PENDING_TRANSFER", "allowed": false, "reason": "SUB_USER_BLOCKED" },
{ "operation": "CARD_LOAD", "allowed": false, "reason": "SUB_USER_BLOCKED" },
{ "operation": "RECEIVE_PIX", "allowed": true, "reason": null }
],
"subUser": {
"enabled": true,
"fixedDestinationKey": "*********4567",
"fixedDestinationName": "Comercial Guarani LTDA",
"fixedDestinationIdentifier": "USER_550e8400-e29b-41d4-a716-446655440000"
}
}
Use operations[] para montar menu e telas sem esperar o erro no meio do fluxo.
No envio DEX, mande subUser.fixedDestinationIdentifier como destinationIdentifier — é o account code, não o telefone. Ele continua válido mesmo se o titular do destino trocar de número.
SEND_INTERNAL vem com allowed: true e um reason. Não é contradição: o envio está liberado, com a ressalva de que só vai para a chave fixa. Trate reason presente com allowed: true como "liberado com restrição".
Motivos possíveis
reason |
Significa |
|---|---|
SUB_USER_BLOCKED |
Fechada pela restrição de Sub Usuário |
SUB_USER_FIXED_DESTINATION_ONLY |
Liberada apenas para a chave fixa |
KYC_REQUIRED |
Exige conta com verificação completa |
PIX_WITHDRAWALS_BLOCKED |
Saque Pix bloqueado nesta conta |
CRYPTO_WITHDRAWALS_BLOCKED |
Saque cripto bloqueado nesta conta |
ACCOUNT_BLOCKED |
Conta integralmente bloqueada |
8. Restrição e Verificação de Conta se Somam
São dimensões independentes. Uma conta sem verificação completa não recebe nem envia por Pix, mesmo sem restrição:
| Situação | Recebe Pix | Envia Pix |
|---|---|---|
| Conta básica + Sub Usuário | ❌ KYC_REQUIRED |
❌ SUB_USER_BLOCKED |
| Conta completa + Sub Usuário | ✅ | ❌ SUB_USER_BLOCKED |
| Conta básica sem restrição | ❌ KYC_REQUIRED |
❌ KYC_REQUIRED |
Ou seja: promover a conta a verificação completa libera o recebimento Pix de um Sub Usuário, e nunca o envio.
9. Erros da Configuração
> Rollout em andamento. Os códigos granulares abaixo estão sendo liberados. Enquanto isso, uma chave recusada pode retornar SUB_USER_FIXED_KEY_INVALID (422) cobrindo as três primeiras causas de uma vez. Programe seu tratamento pelos códigos granulares e mantenha um caminho padrão para o código genérico.
| Código | HTTP | O que fazer |
|---|---|---|
SUB_USER_FIXED_KEY_NOT_FOUND |
404 | A chave não corresponde a conta nenhuma. Confira o número — causa mais comum: falta o código do país |
SUB_USER_FIXED_KEY_INACTIVE |
422 | A conta existe, mas não está ativa. Resolva o status dela antes |
SUB_USER_FIXED_KEY_OTHER_PARTICIPANT |
422 | A chave é de um usuário fora do seu grupo. O destino precisa ser uma conta da sua própria base |
SUB_USER_FIXED_KEY_IS_SELF |
422 | A chave é a do próprio usuário que você está restringindo |
SUB_USER_PRIVILEGED_TARGET_FORBIDDEN |
403 | O usuário-alvo tem acesso administrativo, ou você está tentando restringir a si mesmo |
USER_OUT_OF_SCOPE |
403 | O usuário não pertence à sua base |
USER_NOT_FOUND |
404 | O userId do path não existe |
| — | 400 | fixedDestinationKey ou reason ausente, ou acima do tamanho |
| — | 429 | Limite de 10 requisições por minuto excedido |
10. Erros que o Usuário Restrito Recebe
Nas operações de envio, com o token do próprio usuário:
| Código | HTTP | Endpoint |
|---|---|---|
SUB_USER_DESTINATION_NOT_ALLOWED |
403 | POST /ledger/transfer para destino diferente da chave fixa |
SUB_USER_OPERATION_NOT_ALLOWED |
403 | POST /pix/withdraw, POST /pix/withdraw/qrcode, POST /crypto/withdraw, POST /transfers/pending, POST /cards/load/confirm |
Trate os dois como caminho de erro previsto, não como falha inesperada — mesmo que sua interface já esconda a operação.
11. Detalhes de Contrato que Importam na Integração
A chave é resolvida, não armazenada como texto. A configuração grava a conta que a chave aponta. Se o titular do destino trocar de telefone depois, os envios continuam chegando na mesma conta, e a consulta passa a exibir o número novo.
Nenhum campo é removido de respostas existentes. Os campos de Sub Usuário são adicionais em GET /admin/users e GET /admin/users/{userId}.
Dois valores novos podem aparecer em respostas de cartão, se você consome esses endpoints:
CardEligibilityBlockerpode virSUB_USER_RESTRICTED— emGET /cards/eligibilityCardFreezeOriginpode virSUB_USER_RESTRICTION— no detalhe e no resumo do cartão
Ambas as respostas já trazem o texto pronto para exibição. Se você mantém tabela própria de tradução por código, acrescente os dois.
O cartão acompanha a restrição. Ao restringir um usuário que já tem cartão ativo, ele é congelado; ao remover a restrição, volta ao ar. O titular não descongela pela tela enquanto a restrição existir.
12. Limites do Recurso
Uma chave fixa por usuário — não há múltiplos destinos.
A configuração é individual, um usuário por vez. Não há operação em lote.
Não é um sistema de permissões: é ligado ou desligado, sem granularidade por funcionalidade.
Um usuário só passa a ser Sub Usuário quando alguém o marca explicitamente. Contas existentes não são afetadas.

