🏦 Depósito em Euro via IBAN (Transferência Bancária)

Esta página explica como um usuário deposita euros por transferência bancária e recebe o valor em stablecoin (USDC ou USDT) na conta DEX.

Funciona assim: o usuário transfere euros do banco dele para uma conta IBAN da plataforma, informa o depósito no app com o comprovante, e a nossa equipe confirma a entrada do dinheiro. Confirmado, o valor é creditado na conta DEX pela cotação que ficou travada no momento em que o depósito foi informado.

Não há detecção automática da transferência. O crédito acontece depois que a equipe confere o extrato bancário, em horário comercial. Por isso o fluxo tem um passo de "informar o depósito" e um status de acompanhamento.

1. Quem Pode Usar

Requisito Como saber
Conta com verificação completa (KYC aprovado) GET /v1/profile → accountStatus: FULL
Depósito IBAN liberado para o seu grupo (participante) A plataforma habilita por participante. Sem isso, as chamadas devolvem 403 IBAN_DEPOSIT_DISABLED
Uma conta IBAN vinculada ao usuário A equipe da plataforma vincula. Sem vínculo, GET /v1/fiat/iban/account devolve 404 IBAN_DEPOSIT_NO_ACCOUNT_ASSIGNED

O usuário não escolhe a moeda em que recebe: ela é definida no vínculo (USDC ou USDT) e aparece em creditCurrency.

2. Credencial Necessária

Todas as chamadas desta página usam o token do próprio usuário: o JWT do app ou um token gerado com a credencial pessoal em POST /v1/auth/api-key (veja Autenticação).

A credencial de participante (client_id/client_secret da empresa) não informa depósitos em nome de usuários. Ela serve apenas para acompanhar os depósitos do seu grupo (seção 10).

3. O Fluxo em Cinco Passos

# O que o usuário faz Chamada
1 Vê a conta IBAN para onde transferir, a moeda de crédito e as regras GET /v1/fiat/iban/account
2 Simula quanto vai receber por um valor em euros GET /v1/fiat/iban/deposits/quote
3 Faz a transferência no banco dele, colocando o ID de usuário na referência fora da API
4 Informa o depósito: valor, comprovante e PIN POST /v1/fiat/iban/deposits
5 Acompanha até o crédito (ou cancela enquanto ninguém analisou) GET /v1/fiat/iban/deposits · POST …/{id}/cancel

4. Passo 1 — Conta para Depósito

curl https://api.dexkey.finance/v1/fiat/iban/account \
  -H "Authorization: Bearer $TOKEN"
{
  "ibanAccount": {
    "id": "3c3d54fb-2a1e-4b7c-9d8e-0f1a2b3c4d5e",
    "iban": "DE89370400440532013000",
    "bic": "COBADEFFXXX",
    "bankName": "Commerzbank AG",
    "bankAddress": "Kaiserplatz, 60311 Frankfurt am Main",
    "beneficiaryName": "Ether Global Assets Ltd",
    "beneficiaryAddress": null,
    "country": "DE",
    "currency": "EUR"
  },
  "creditCurrency": "USDC",
  "userDisplayId": "A1B2C3D4",
  "conciliation": {
    "document": "12345678901",
    "dexKey": "+5511999998888",
    "instruction": "Inclua seu ID de usuário ou CPF/CNPJ no campo \"Referência\" da transferência."
  },
  "rules": {
    "minAmountEurCents": "10000",
    "quoteTtlBusinessDays": 2,
    "proof": {
      "maxSizeBytes": 10485760,
      "allowedMimeTypes": ["application/pdf", "image/jpeg", "image/png"]
    },
    "limits": {
      "perTransactionEurCents": "860100",
      "dailyRemainingEurCents": "1720200",
      "monthlyRemainingEurCents": "4300500",
      "maxNowEurCents": "860100",
      "rateUsdPerEur": "1.16265000"
    }
  }
}
Campo O que é
ibanAccount Dados bancários completos para a transferência. O iban vem sem espaços; exiba em blocos de 4
creditCurrency Stablecoin em que o usuário vai receber (USDC ou USDT)
userDisplayId ID curto do usuário (8 caracteres). É o que ele deve escrever na referência da transferência
conciliation Dados do próprio usuário que ajudam a equipe a casar a transferência com a conta. document e dexKey são dele mesmo; mascare na tela
rules.minAmountEurCents Valor mínimo por depósito, em centavos de euro ("10000" = € 100,00)
rules.quoteTtlBusinessDays Por quantos dias úteis a cotação fica travada depois de informar o depósito
rules.proof Tamanho máximo e tipos de arquivo aceitos para o comprovante
rules.limits Quanto o usuário pode depositar agora, em centavos de euro. maxNowEurCents é o menor entre o teto por transação e o que ainda cabe no dia e no mês. Vem null se a conta não tem limite configurado ou o câmbio está indisponível

Mostre rules.limits.maxNowEurCents na tela de valor ("Você pode depositar até € 8.601,00") e valide o campo com ele. O teto muda com o câmbio e com o uso do dia e do mês, por isso vem calculado pelo servidor a cada chamada. Se mesmo assim o valor passar, o erro LIMIT_EXCEEDED (seção 12) traz a mesma informação.

Oriente o usuário a colocar o userDisplayId na referência (ou "descrição") da transferência bancária. Sem isso, a equipe precisa localizar a transferência por nome e valor, e a confirmação demora mais.

5. Passo 2 — Simular a Cotação

curl "https://api.dexkey.finance/v1/fiat/iban/deposits/quote?amountEurCents=50000" \
  -H "Authorization: Bearer $TOKEN"
{
  "amountEurCents": "50000",
  "creditCurrency": "USDC",
  "quoteRate": "1.073605000000000000",
  "quoteSource": "okx",
  "fee": {
    "platformEurCents": "500",
    "participantEurCents": "0",
    "totalEurCents": "500",
    "totalCreditUnits": "5368025",
    "effectivePercent": "1.00"
  },
  "grossCreditUnits": "536802500",
  "netCreditUnits": "531434475",
  "ttlBusinessDays": 2,
  "wouldExpireAt": "2026-09-08T02:59:59.999Z"
}
Campo O que é
amountEurCents Valor simulado, em centavos de euro
quoteRate Cotação que será travada: quantas unidades da stablecoin por 1 euro
fee Taxa do depósito, em euros e na stablecoin. effectivePercent é o percentual efetivo sobre o valor
grossCreditUnits Valor convertido antes da taxa, em unidades da stablecoin (6 casas: "536802500" = 536,802500 USDC)
netCreditUnits O que o usuário vai receber, já sem a taxa
wouldExpireAt Até quando a cotação valeria se o depósito fosse informado agora

A simulação não reserva cotação nem cria nada. A cotação só é travada no passo 4, e pode ser um pouco diferente da simulação se o câmbio se moveu nesse meio-tempo. A simulação também já verifica os limites da conta: valor acima do permitido devolve um erro LIMIT_*.

Valores em euros são sempre strings de centavos ("50000" = € 500,00). Valores em stablecoin são strings em unidades inteiras com 6 casas decimais. Isso evita erros de arredondamento; converta só na exibição.

6. Passo 3 — A Transferência no Banco

Fora da API. O usuário transfere, do banco dele para a conta do passo 1:

  • em euros, o valor exato que vai informar;
  • com o userDisplayId** na referência** da transferência;
  • de uma conta no nome dele. Transferência de terceiro pode ser recusada.

Transferências internacionais podem levar de horas a alguns dias úteis para entrar. O usuário pode informar o depósito assim que tiver o comprovante; a equipe só confirma quando o dinheiro aparece.

7. Passo 4 — Informar o Depósito

Uma única chamada multipart/form-data, com o comprovante junto.

curl -X POST https://api.dexkey.finance/v1/fiat/iban/deposits \
  -H "Authorization: Bearer $TOKEN" \
  -F "idempotencyKey=5f3a1c2e-8b7d-4e6f-9a0b-1c2d3e4f5a6b" \
  -F "declaredAmountEurCents=50000" \
  -F "pin=1234" \
  -F "userReference=Transferencia Commerzbank 05/09" \
  -F "proof=@comprovante.pdf;type=application/pdf"

Campos enviados

Campo Tipo Obrigatório Descrição
idempotencyKey UUID v4 ✅ Gere um por tentativa de depósito, antes de enviar. Se a conexão cair e você reenviar com a mesma chave, recebe 200 com a solicitação já criada, sem duplicar
declaredAmountEurCents string de centavos ✅ Valor que o usuário transferiu, em centavos de euro. Não pode ser menor que rules.minAmountEurCents
pin 4 dígitos ✅ PIN de segurança do usuário
proof arquivo ✅ Comprovante da transferência: PDF, JPG ou PNG, até o tamanho de rules.proof.maxSizeBytes
userReference string (máx. 140) opcional Texto livre do usuário para ele reconhecer o depósito depois (ex.: nome do banco e data)

O PIN é validado antes dos outros campos. Errar o PIN algumas vezes seguidas bloqueia o PIN temporariamente. Não faça tentativas automáticas de envio com PIN em lote, e valide o formulário no app antes de chamar a API.

Resposta (201 Created)

{
  "id": "9f1c2a3b-4d5e-4f60-8a7b-9c0d1e2f3a4b",
  "shortId": "9F1C2A3B",
  "status": "PROCESSING",
  "declaredAmountEurCents": "50000",
  "receivedAmountEurCents": null,
  "effectiveAmountEurCents": "50000",
  "userReference": "Transferencia Commerzbank 05/09",
  "creditCurrency": "USDC",
  "quote": {
    "quoteRate": "1.073605000000000000",
    "quoteSource": "okx",
    "quotedAt": "2026-09-05T13:12:00.000Z",
    "expiresAt": "2026-09-08T02:59:59.999Z",
    "isExpired": false,
    "requoteCount": 0
  },
  "fee": { "totalEurCents": "500", "totalCreditUnits": "5368025" },
  "grossCreditUnits": "536802500",
  "netCreditUnits": "531434475",
  "proof": { "fileName": "comprovante.pdf", "mimeType": "application/pdf", "sizeBytes": "184223" },
  "ibanAccount": { "ibanMasked": "DE89 **** **** **** 0130 00", "bankName": "Commerzbank AG", "bic": "COBADEFFXXX", "beneficiaryName": "Ether Global Assets Ltd", "country": "DE", "currency": "EUR" },
  "rejectionReason": null,
  "reopenReason": null,
  "canCancel": true,
  "ledgerTransactionId": null,
  "timeline": {
    "createdAt": "2026-09-05T13:12:00.000Z",
    "reviewStartedAt": null,
    "reviewedAt": null,
    "completedAt": null,
    "cancelledAt": null
  }
}

O que aconteceu: a cotação e a taxa ficaram travadas (quote.expiresAt diz até quando), a solicitação entrou na fila da equipe como PROCESSING e o usuário recebeu push e e-mail confirmando.

Mostre ao usuário o shortId (ex.: #9F1C2A3B). É o número que aparece nos e-mails e que a equipe usa para falar da solicitação.

Avise antes do PIN: pré-checagem do comprovante

Para não descobrir só depois do PIN que o comprovante já foi usado, calcule o SHA-256 do arquivo no próprio app assim que o usuário anexar e pergunte ao servidor:

curl "https://api.dexkey.finance/v1/fiat/iban/deposits/proof-check?sha256=9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" \
  -H "Authorization: Bearer $TOKEN"
{ "duplicate": true, "request": { "id": "9f1c2a3b-4d5e-4f60-8a7b-9c0d1e2f3a4b", "shortId": "9F1C2A3B", "status": "PROCESSING" } }

No navegador, o hash sai de crypto.subtle.digest("SHA-256", await file.arrayBuffer()), convertido para hexadecimal. Nada é enviado além do hash. duplicate: false significa que a submissão vai passar nessa regra; true traz a solicitação que já usa o arquivo, para o app mostrar "Este comprovante já foi usado na solicitação #9F1C2A3B".

Recusas mais comuns nesta chamada

Código HTTP O que fazer
IBAN_DEPOSIT_AMOUNT_BELOW_MINIMUM 400 Valor abaixo de rules.minAmountEurCents
IBAN_DEPOSIT_PROOF_REQUIRED 400 Faltou o arquivo proof
IBAN_DEPOSIT_PROOF_INVALID_MIME_TYPE 400 Arquivo não é PDF, JPG ou PNG. O tipo é verificado pelo conteúdo, não pela extensão
IBAN_DEPOSIT_PROOF_FILE_TOO_LARGE 400 Arquivo maior que rules.proof.maxSizeBytes
IBAN_DEPOSIT_PROOF_CONTENT_INVALID 400 Arquivo corrompido ou com conteúdo diferente do tipo declarado
IBAN_DEPOSIT_PROOF_DUPLICATE 409 Este mesmo comprovante já foi usado em outra solicitação do usuário (inclusive canceladas; só solicitações recusadas liberam o arquivo de novo). details.existingShortId diz qual; mostre um link para ela. Cada transferência precisa do próprio comprovante
IBAN_DEPOSIT_IDEMPOTENCY_CONFLICT 409 A idempotencyKey já foi usada com outros valores. Gere uma nova
IBAN_DEPOSIT_QUOTE_UNAVAILABLE 503 Câmbio indisponível no momento. Tente de novo em instantes
LIMIT_* 4xx O valor ultrapassa o limite da conta (por operação, dia ou mês)
erro de PIN 4xx PIN errado ou bloqueado; siga o fluxo padrão de PIN do app

8. Passo 5 — Acompanhar

Lista

curl "https://api.dexkey.finance/v1/fiat/iban/deposits?status=PROCESSING,UNDER_REVIEW&page=1&limit=20" \
  -H "Authorization: Bearer $TOKEN"

Devolve { "data": [...], "meta": { "total", "page", "limit" } }. Sem status, vêm todas. Cada item tem o mesmo formato da resposta do passo 4.

Detalhe

GET /v1/fiat/iban/deposits/{id} — mesma estrutura. Só o dono da solicitação consegue ver; outro usuário recebe 403.

O bloco ibanAccount é a conta receptora daquela solicitação, não a conta vinculada hoje ao usuário. Se o vínculo mudar depois, o detalhe continua mostrando para onde aquele depósito foi feito. Exiba banco, BIC, beneficiário e país; o IBAN vem mascarado.

Os status

status Em palavras O usuário pode cancelar?
PROCESSING Informado. Aguardando a equipe começar a conferir ✅ canCancel: true
UNDER_REVIEW A equipe está conferindo o extrato bancário ❌
REOPENED Havia sido recusado e voltou para análise (ex.: a transferência foi localizada depois) ❌
COMPLETED Creditado. netCreditUnits já está na conta DEX; ledgerTransactionId aponta a transação e ela aparece no extrato ❌
REJECTED Recusado. rejectionReason traz o motivo, escrito pela equipe ❌
CANCELLED Cancelado pelo próprio usuário ❌

Use timeline para mostrar as datas de cada etapa e canCancel para decidir se exibe o botão de cancelar.

O valor pode mudar até o crédito?

Pode, em dois casos, e a resposta mostra ambos:

  • Valor recebido diferente do declarado. Se entrou € 480 em vez de € 500, a equipe registra o recebido: receivedAmountEurCents: "48000", e o crédito é calculado sobre effectiveAmountEurCents, sempre com a mesma cotação travada.
  • Cotação vencida antes da confirmação. Se a análise só terminou depois de quote.expiresAt, a equipe atualiza a cotação (requoteCount aumenta e quote.quoteRate muda). É a única situação em que a cotação travada muda.

A taxa (fee) é congelada quando o depósito é informado e não muda.

9. Cancelar

curl -X POST https://api.dexkey.finance/v1/fiat/iban/deposits/{id}/cancel \
  -H "Authorization: Bearer $TOKEN"

Devolve 200 com a solicitação em CANCELLED. Só funciona enquanto o status é PROCESSING; depois que a equipe começa a análise, a resposta é 409 IBAN_DEPOSIT_CANCEL_NOT_ALLOWED.

Cancelar não desfaz a transferência bancária. Se o usuário já transferiu, oriente-o a falar com o suporte informando o shortId.

Baixar o comprovante enviado

GET /v1/fiat/iban/deposits/{id}/proof devolve { "url", "expiresAt" }. A URL funciona por 5 minutos; gere outra quando expirar.

10. Para Participantes: Acompanhar os Depósitos do Seu Grupo

Com a credencial de um administrador do participante, a fila da equipe fica disponível em modo leitura, já filtrada para os usuários do seu grupo:

curl "https://api.dexkey.finance/v1/admin/fiat/iban/deposits?status=COMPLETED&sort=createdAt:desc" \
  -H "Authorization: Bearer $TOKEN"
{
  "data": [
    {
      "id": "9f1c2a3b-4d5e-4f60-8a7b-9c0d1e2f3a4b",
      "shortId": "9F1C2A3B",
      "status": "COMPLETED",
      "user": { "name": "Maria Souza", "displayId": "A1B2C3D4" },
      "declaredAmountEurCents": "50000",
      "effectiveAmountEurCents": "50000",
      "creditCurrency": "USDC",
      "quoteRate": "1.073605000000000000",
      "netCreditUnits": "531434475",
      "participantCommissionCreditUnits": "1610407",
      "platformCommissionCreditUnits": "3757618",
      "createdAt": "2026-09-05T13:12:00.000Z",
      "completedAt": "2026-09-05T16:40:00.000Z"
    }
  ],
  "meta": { "total": 1, "page": 1, "limit": 20 },
  "summary": {
    "inProgressCount": 2,
    "completedCount30d": 12,
    "completedEurCents30d": "1250000",
    "participantCommissionCreditUnits30d": "40260175"
  }
}
Recurso Descrição
Filtros status (lista separada por vírgula; padrão: em andamento), userId, search (nome, displayId ou referência), from/to, sort (createdAt:asc padrão), page/limit
participantCommissionCreditUnits Sua comissão naquele depósito, na stablecoin. null em recusados e cancelados
summary Quantos estão em andamento, quantos concluíram em 30 dias, soma em euros e sua comissão acumulada no período
GET …/deposits/{id} Mesmo formato do item da lista

O usuário já está habilitado? A qual conta?

Com a mesma credencial, GET /v1/admin/fiat/iban/users/{userId}/account responde se um usuário do seu grupo tem vínculo ativo e com qual conta da plataforma:

{
  "hasAssignment": true,
  "account": { "ibanMasked": "DE89 **** **** **** 0130 00", "bankName": "Commerzbank AG", "country": "DE", "isActive": true },
  "creditCurrency": "USDC",
  "assignedAt": "2026-09-05T10:12:00.000Z"
}

hasAssignment: false (com os demais campos null) significa "este usuário ainda não foi habilitado pela plataforma". account.isActive: false significa que a conta vinculada está desativada e o usuário não consegue depositar até a plataforma trocar o vínculo ou reativar a conta. Usuário de outro grupo → 404.

A visão do participante é somente leitura e não inclui comprovante, justificativas internas, dados de contato do usuário, IBAN completo nem quem fez o vínculo. Qualquer tentativa de ação (aprovar, recusar etc.) devolve 403, e uma solicitação de outro grupo devolve 404.


11. O Que o Usuário Recebe de Aviso

Em cada mudança, o usuário recebe push no app e e-mail (em inglês, assinado com o nome do participante):

Momento Assunto do e-mail
Informou o depósito IBAN deposit request #9F1C2A3B received
Creditado IBAN deposit #9F1C2A3B credited
Recusado IBAN deposit #9F1C2A3B not approved (com o motivo)
Voltou para análise IBAN deposit #9F1C2A3B under review again
Cancelou IBAN deposit request #9F1C2A3B cancelled

Os e-mails nunca trazem o IBAN completo, documento ou telefone.

12. Erros Desta Área

Código HTTP Significa
IBAN_DEPOSIT_DISABLED 403 Depósito IBAN não está liberado para o grupo do usuário
IBAN_DEPOSIT_USER_NOT_FULL 403 A conta ainda não tem verificação completa
IBAN_DEPOSIT_NO_ACCOUNT_ASSIGNED 404 O usuário não tem conta IBAN vinculada. Peça o vínculo à plataforma
IBAN_DEPOSIT_ACCOUNT_INACTIVE 409 A conta vinculada foi desativada. Um novo vínculo é necessário
IBAN_DEPOSIT_AMOUNT_BELOW_MINIMUM 400 Valor abaixo do mínimo
IBAN_DEPOSIT_PROOF_* 400 / 409 Problema com o comprovante (seção 7)
IBAN_DEPOSIT_IDEMPOTENCY_CONFLICT 409 idempotencyKey reutilizada com valores diferentes
IBAN_DEPOSIT_QUOTE_UNAVAILABLE 503 Câmbio indisponível no momento
IBAN_DEPOSIT_REQUEST_NOT_FOUND 404 Solicitação não existe
IBAN_DEPOSIT_REQUEST_FORBIDDEN 403 A solicitação é de outro usuário
IBAN_DEPOSIT_CANCEL_NOT_ALLOWED 409 Só é possível cancelar em PROCESSING
LIMIT_EXCEEDED 402 Limite da conta ultrapassado (operação, dia ou mês). A mensagem vem em euros e details.remainingOriginalCents diz quanto ainda cabe, em centavos de euro
— 400 Campo faltando ou em formato errado (VALIDATION_ERROR)
— 429 Muitas requisições em pouco tempo

Todo erro segue o formato padrão: { "code", "message", "timestamp", "traceId", "requestId", "details" }. Trate pelo code, não pelo texto.

13. Detalhes de Contrato que Importam na Integração

Dinheiro é string. Euros em centavos ("50000"), stablecoin em unidades de 6 casas ("531434475"). Nunca use float; converta só para exibir.

Datas em UTC. Todas em ISO-8601 (2026-09-08T02:59:59.999Z). A validade da cotação termina no fim do dia útil no horário de Brasília, por isso o Z mostra 02:59:59.999.

Idempotência é sua responsabilidade. Gere o idempotencyKey no início do fluxo e guarde-o até receber resposta. Reenvio com a mesma chave é seguro.

Um comprovante, um depósito. O mesmo arquivo não pode ser reaproveitado pelo usuário, nem depois de cancelar.

Nada é creditado sozinho. Até COMPLETED, o saldo do usuário não muda. Não mostre o valor como disponível antes disso.

O extrato mostra o crédito. Em COMPLETED, a transação (ledgerTransactionId) aparece no extrato do usuário como depósito IBAN, com o valor líquido. O comprovante da transação (GET /ledger/transactions/{id}) traz originValue com as duas pontas: o valor recebido em euro (amount, amountFormatted, currency: "EUR") e o valor creditado na stablecoin (convertedAmount, convertedAmountFormatted, convertedCurrency). Mostre os dois no comprovante. Para o depósito IBAN, operationDetails traz ibanDepositRequestId (para abrir o detalhe da solicitação a partir do comprovante) e receivingAccount (ibanMasked, bic, bankName, beneficiaryName, country): a conta receptora como valia na aprovação. Mostre a conta no comprovante.

14. Limites do Recurso

Somente euros, por transferência bancária para a conta IBAN indicada. Não há outras moedas nem outros métodos nesta área.

Uma conta IBAN vinculada por usuário, definida pela plataforma.

A confirmação é feita por pessoas, em horário comercial. Não há previsão automática de prazo na API; use os status e a timeline.

O usuário não escolhe a stablecoin de crédito; ela vem do vínculo.