🏦 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 sobreeffectiveAmountEurCents, 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 (requoteCountaumenta equote.quoteRatemuda). É 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 devolve404.
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.

