💳 DexCard — Cartão Pré-pago em Dólar

Esta página explica como um usuário pede, recebe e usa um cartão pré-pago denominado em dólar, recarregado com o saldo que ele já tem na conta DEX.

Funciona assim: o usuário verifica se pode pedir, envia três documentos, aceita os termos e solicita. A solicitação passa por duas análises — a nossa e a do emissor — e, aprovada, o cartão nasce ativo. A partir daí ele recarrega a partir de BRT, USDC ou USDT, gasta em dólar, resgata o que sobrou de volta para a conta, congela e descongela quando quiser, e acompanha tudo pelo extrato.

> Liberado caso a caso. O DexCard é habilitado por participante — a empresa parceira à qual a conta do usuário pertence. Sem essa liberação, todas as chamadas desta página devolvem 403 CARD_CONFIG_MODULE_DISABLED; fale com seu gerente de conta.

1. As Seis Fases

Fase O que acontece Endpoints
1. Elegibilidade Descobrir se a pessoa pode pedir, e quanto custa emitir GET /cards/eligibility · GET /cards/issuance-fee/preview
2. Documentos Enviar os três documentos do titular GET /cards/documents/requirements · POST /cards/documents/upload · GET /cards/documents
3. Solicitação Aceitar os termos e pedir o cartão POST /cards/request
4. Análise Acompanhar: nossa análise → análise do emissor → cartão emitido GET /cards/application-status
5. Cartão ativo Ver dados, saldo, limites e credenciais GET /cards/my-cards · GET /cards/{id} · GET /cards/{id}/balance · GET /cards/{id}/limits · GET /cards/{id}/secure-credentials
6. Movimentação Recarregar, resgatar, congelar, extrato …/load/* · …/redeem/* · …/freeze · …/transactions

As fases 1 a 4 acontecem uma vez. A fase 6 é o dia a dia.

2. Quem Pode Usar

Requisito Como saber
Conta com verificação completa (KYC aprovado) GET /v1/profile → accountStatus: FULL
Telefone e e-mail confirmados Confirmação pelo app/onboarding
Data de nascimento e endereço no cadastro GET /v1/profile · GET /v1/profile/address
PIN de 4 dígitos cadastrado Exigido para recarregar e resgatar (seção 3)
Não ser Sub Usuário Sub Usuário não tem cartão (veja Sub Usuário)
Cota de emissão disponível Cada participante contrata um número de cartões. Esgotada a cota, ninguém mais emite até ela aumentar

Tudo isso é conferido de uma vez em GET /cards/eligibility — não é preciso checar item a item.

3. 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 dele em POST /v1/auth/api-key.

A credencial de participante (client_id/client_secret da empresa) não opera cartão de usuário. Ela nem sequer resolve para um usuário — a chamada falha. O que o participante faz sozinho está na página DexCard para o Participante.

> Recarga e resgate exigem o PIN de 4 dígitos da conta no corpo da requisição. Isso é deliberado: são as duas operações que movem dinheiro do usuário. Na prática significa que quem integra precisa de uma tela onde a pessoa digita o PIN na hora — não há como recarregar um cartão de forma inteiramente server-to-server. PIN errado devolve 401 CARD_INVALID_PIN.

4. Unidades: o Erro Mais Caro desta API

Ele nunca aparece como erro. Aparece como valor errado que passa.

Sufixo do campo Unidade USD 20,00 / 100,00 USDT fica
…UsdCents centavos de dólar, inteiro em string "2000"
…SourceAmount / …TargetAmount centésimos da moeda citada ao lado, inteiro em string "10000"
exchangeRate decimal em string "5.49800000"

"Centésimos" é o valor multiplicado por cem, sem casa decimal — a mesma ideia de centavos, valendo para qualquer moeda:

O usuário digita Você envia
100,00 USDT "10000"
1,00 USDT "100"
12,34 USDC "1234"
250,00 BRT "25000"

> Valor com casa decimal não é recusado — é reinterpretado. Enviar "100.00" achando que são cem USDT passa na validação e é entendido como 100 centésimos, ou seja, 1,00 USDT: a recarga acontece, cem vezes menor, e ninguém recebe erro nenhum. Cem USDT se escreve "10000".

O servidor devolve os dois lados de cada cálculo (moeda de origem e dólar) justamente para a sua tela não precisar converter nada.

5. Fase 1 — Elegibilidade e Custo

5.1 Pode pedir?

curl https://api.dexkey.finance/v1/cards/eligibility \
  -H "Authorization: Bearer $TOKEN"
{
  "canRequest": false,
  "hasCard": false,
  "blockers": [
    {
      "code": "ACCOUNT_NOT_FULL",
      "message": "Conclua a verificação de identidade da sua conta para solicitar o cartão",
      "isResolvableByHolder": true
    },
    {
      "code": "ADDRESS_MISSING",
      "message": "Cadastre seu endereço para solicitar o cartão",
      "isResolvableByHolder": true
    }
  ]
}
Campo O que é
canRequest true só quando blockers está vazio
hasCard A pessoa já tem cartão. Só ofereça o DexCard na tela quando vier hasCard: false e canRequest: true
blockers[].code Código estável — trate por ele, não pelo texto
blockers[].message Texto pronto para exibir ao usuário
blockers[].isResolvableByHolder true = leve a pessoa à tela que resolve. false = não há o que ela faça

Os bloqueadores possíveis: MODULE_DISABLED, SUB_USER_RESTRICTED, PROFILE_MISSING, ACCOUNT_NOT_FULL, PHONE_NOT_VERIFIED, EMAIL_NOT_VERIFIED, BIRTH_DATE_MISSING, ADDRESS_MISSING, PREVIOUSLY_REJECTED, QUOTA_EXHAUSTED, ALREADY_HAS_CARD, DUPLICATE_PHONE.

Os impedimentos vêm todos de uma vez, de propósito: assim a pessoa resolve tudo numa passada, em vez de corrigir um, tentar de novo e descobrir o seguinte.

5.2 Quanto custa emitir

curl https://api.dexkey.finance/v1/cards/issuance-fee/preview \
  -H "Authorization: Bearer $TOKEN"
{
  "hasFee": true,
  "totalUsdCents": "1500",
  "totalFormatted": "US$ 15.00",
  "canAfford": true,
  "missingUsdCents": "0",
  "slices": [
    { "currency": "USDT", "nativeAmount": "12500000", "usdCents": "1250" },
    { "currency": "BRT", "nativeAmount": "1375", "usdCents": "250" }
  ],
  "canRequest": true,
  "blockers": []
}
Campo O que é
hasFee false significa emissão gratuita, não erro de configuração a investigar
totalUsdCents Preço em centavos de dólar. O preço é sempre em dólar
slices De quais moedas o valor sairia e quanto de cada uma, na ordem em que serão consumidas. O usuário não precisa trocar de moeda antes: o sistema junta o valor sozinho
canAfford false = a emissão seria recusada por saldo; missingUsdCents diz quanto falta

> A tarifa é cobrada quando a pessoa pede o cartão (POST /cards/request), e não quando ele é aprovado. Quem é recusado pelo emissor recebe o dinheiro de volta — exatamente o valor que pagou, mesmo que a tarifa tenha mudado nesse meio-tempo.

Esta consulta é uma simulação: o saldo é lido no instante da pergunta, e o valor que vale é o conferido de novo na hora da cobrança.

6. Fase 2 — Documentos

São três, e todos obrigatórios:

documentType O que o titular envia
IDENTITY_FRONT Foto da frente do documento físico, tirada na horizontal
IDENTITY_BACK Foto do verso do documento físico, tirada na horizontal
SELFIE_WITH_DOCUMENT Uma selfie do rosto. Apesar do nome do campo, o titular não precisa segurar o documento

> Tem que ser foto tirada do documento físico. Documento digital não é aceito — CNH digital, e-Título, carteirinha em aplicativo, print de tela, foto da tela de outro aparelho e PDF são recusados na análise. A pessoa precisa estar com o documento em mãos e fotografá-lo.

> A foto do documento é na horizontal (paisagem). O documento ocupa a largura do enquadramento, inteiro, sem cortar cantos. Foto na vertical costuma sair com o documento pequeno e as bordas fora, e é a causa mais comum de devolução.

SELFIE_WITH_DOCUMENT** é só o rosto.** O nome do campo vem do emissor e engana: peça uma selfie comum, com o rosto enquadrado e bem iluminado, sem documento na mão. Instruir a pessoa a segurar o documento não invalida o envio, mas atrapalha o enquadramento do rosto.

> Apenas JPG e PNG, até 5 MB. PDF e HEIC são recusados pela API — o emissor não os aceita. Foto de iPhone costuma sair em HEIC: nos ajustes da câmera, "Mais compatível", ou converta antes de enviar.

Quem usa CNH como identidade fotografa a CNH física e envia em IDENTITY_FRONT e IDENTITY_BACK — a versão digital do aplicativo não serve. Comprovante de residência é documento do cadastro (KYC), não do cartão.

Frente e verso são envios separados porque cada um é analisado por conta própria: se o verso sair ilegível, a pessoa reenvia só o verso.

Estas regras são de análise, não de validação automática: um documento digital ou uma foto na vertical sobe com 201 e só volta como rejected na análise, com o motivo em rejectionReason. Mostrá-las na tela de captura é o que evita o ciclo de envio e devolução.

6.1 Situação documental

curl https://api.dexkey.finance/v1/cards/documents/requirements \
  -H "Authorization: Bearer $TOKEN"
{
  "requirements": [
    {
      "documentType": "IDENTITY_FRONT",
      "status": "approved",
      "rejectionReason": null,
      "documentId": "fe84c527-d719-4372-b1c2-7ab1df757923",
      "previewUrl": "https://s3.amazonaws.com/…?X-Amz-Signature=…",
      "fileName": "rg-frente.jpg",
      "submittedAt": "2026-09-01T12:11:26.285Z"
    },
    {
      "documentType": "IDENTITY_BACK",
      "status": "rejected",
      "rejectionReason": "A foto corta o canto inferior direito do documento",
      "documentId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "previewUrl": "https://s3.amazonaws.com/…?X-Amz-Signature=…",
      "fileName": "rg-verso.jpg",
      "submittedAt": "2026-09-01T12:12:03.117Z"
    },
    {
      "documentType": "SELFIE_WITH_DOCUMENT",
      "status": "missing",
      "rejectionReason": null,
      "documentId": null,
      "previewUrl": null,
      "fileName": null,
      "submittedAt": null
    }
  ],
  "hasPendingAdjustment": true
}
Campo O que é
status missing → pending → approved ou rejected
rejectionReason Motivo da recusa, escrito por quem analisou. É o texto que diz ao usuário o que corrigir
previewUrl Link temporário (vale 1 hora) para a pessoa rever a foto que mandou. Pode vir null mesmo com documento enviado — nesse caso mostre a situação sem a miniatura, em vez de esconder o item
hasPendingAdjustment Há documento recusado esperando reenvio

6.2 Enviar um documento

Uma chamada só: o arquivo vai para a API, que confere o conteúdo, guarda o arquivo e registra o envio para análise.

curl -X POST https://api.dexkey.finance/v1/cards/documents/upload \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@rg-frente.jpg" \
  -F "documentType=IDENTITY_FRONT" \
  -F "userComment=Reenvio com a foto centralizada"
{
  "id": "fe84c527-d719-4372-b1c2-7ab1df757923",
  "documentType": "IDENTITY_FRONT",
  "status": "pending",
  "fileName": "rg-frente.jpg",
  "userComment": "Reenvio com a foto centralizada",
  "rejectionReason": null,
  "createdAt": "2026-09-01T12:11:26.285Z",
  "reviewedAt": null
}

O conteúdo é validado antes de subir: arquivo vazio, danificado por conversão, ou cujos bytes não batem com o tipo declarado (HEIC enviado como image/jpeg) é recusado com 400 CARD_DOCUMENT_CONTENT_INVALID e orientação de correção em message.

Um envio do mesmo tipo substitui o anterior, que passa a constar como superseded em vez de sumir.

6.3 Histórico

GET /cards/documents devolve todos os envios, incluindo os substituídos e os recusados.

7. Fase 3 — Solicitar o Cartão

curl -X POST https://api.dexkey.finance/v1/cards/request \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "holderDocumentType": "CPF",
    "holderDocumentNumber": "12345678900",
    "holderNationality": "BRA",
    "termsVersion": "v1.0",
    "termsSignatureHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
  }'
{
  "message": "Solicitação de cartão criada com sucesso. Status 202 Accepted.",
  "cardId": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
  "status": "pending"
}
Campo Regras
holderDocumentType CPF, CNPJ, PASSPORT ou NATIONAL_ID
holderDocumentNumber Só dígitos, sem pontuação
holderNationality ISO 3166-1 alpha-3 (BRA, USA). Omitido, assume BRA
termsVersion Versão dos termos apresentada ao usuário
termsSignatureHash Hash do aceite. Gravado na auditoria junto com IP e user agent

O que essa chamada faz, em ordem: confere os bloqueadores da fase 1 → exige os três documentos presentes → cobra a tarifa de emissão → abre a solicitação em análise → consome uma unidade da cota do participante → grava o aceite dos termos.

> Repetir é seguro. Enquanto houver solicitação em curso, a chamada devolve exatamente a mesma resposta da primeira, sem abrir uma segunda e sem cobrar de novo.

Recusas possíveis: 400 (telefone ou e-mail não confirmado, dados incompletos), 403 (cota esgotada, DexCard não liberado, recusa anterior definitiva), 422 (falta documento — CARD_DOCUMENTS_INCOMPLETE; saldo não cobre a tarifa — CARD_ISSUANCE_FEE_INSUFFICIENT_BALANCE).

8. Fase 4 — Acompanhar a Análise

curl https://api.dexkey.finance/v1/cards/application-status \
  -H "Authorization: Bearer $TOKEN"
{
  "steps": [
    { "step": "DOCUMENTS",         "label": "Envio de documentos", "state": "DONE" },
    { "step": "COMPLIANCE_REVIEW", "label": "Análise documental",  "state": "CURRENT" },
    { "step": "ISSUER_REVIEW",     "label": "Análise do emissor",  "state": "PENDING" },
    { "step": "CARD_ISSUED",       "label": "Cartão emitido",      "state": "PENDING" }
  ],
  "currentStep": "COMPLIANCE_REVIEW",
  "currentState": "CURRENT",
  "reason": null,
  "canReapply": false
}

Sem solicitação em curso, a resposta é 204 No Content, sem corpo. Não é erro.

state Significa
DONE Etapa concluída
CURRENT Onde a solicitação está agora
PENDING Ainda não chegou
ACTION_REQUIRED Documento devolvido. É a única situação em que o usuário precisa agir — leve-o à fase 2
FAILED A solicitação parou definitivamente. reason traz o motivo

O acompanhamento volta uma etapa quando um documento é devolvido: currentStep retorna para DOCUMENTS, porque a próxima coisa a acontecer é o reenvio. É o comportamento correto — não trate como inconsistência nem trave a tela na etapa anterior.

canReapply diz se, após uma recusa, o usuário pode tentar de novo. Recusa por fraude é definitiva.

Não existe aviso automático (webhook) de eventos de cartão. O andamento é descoberto consultando este endpoint: a cada poucos minutos enquanto a tela estiver aberta, e sempre que a pessoa voltar ao aplicativo. A emissão leva de algumas horas a alguns dias úteis.

9. Fase 5 — Cartão Ativo

9.1 Listar e detalhar

curl https://api.dexkey.finance/v1/cards/my-cards -H "Authorization: Bearer $TOKEN"
curl https://api.dexkey.finance/v1/cards/{id}     -H "Authorization: Bearer $TOKEN"
{
  "id": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
  "status": "active",
  "lastFour": "4821",
  "expirationDate": "07/29",
  "balanceUsdCents": "23450",
  "pendingHoldUsdCents": "1200",
  "termsAccepted": true,
  "termsAcceptedAt": "2026-09-01T12:20:00.000Z",
  "activatedAt": "2026-09-03T09:14:00.000Z",
  "cancelledAt": null,
  "createdAt": "2026-09-01T12:20:00.000Z",
  "frozenBy": null,
  "frozenAt": null,
  "freezeReason": null,
  "canUnfreeze": false
}
status Significa
pending · activating Emissão em curso
active Pronto para uso e recarga
frozen Congelado — pelo titular ou pela equipe (veja frozenBy)
blocked Bloqueado permanentemente
cancelled Cancelado
rejected Titular recusado pelo emissor; cartão nenhum chegou a existir

9.2 Saldo

curl "https://api.dexkey.finance/v1/cards/{id}/balance?displayCurrency=BRL" \
  -H "Authorization: Bearer $TOKEN"
{
  "availableUsdCents": "23450",
  "pendingHoldUsdCents": "1200",
  "approximateValue": { "currency": "BRL", "amount": "128975", "exchangeRate": "5.49800000" }
}

displayCurrency aceita BRL ou EUR, e é opcional — sem ele vem só o dólar.

> availableUsdCents** já é o saldo que a pessoa pode gastar.** As compras aprovadas e ainda não cobradas pelo estabelecimento já foram descontadas dele. pendingHoldUsdCents mostra quanto está nessa situação, apenas como informação — não subtraia um do outro, ou a tela mostrará um saldo menor que o real.

O valor aproximado é apoio visual e nunca base de operação: quem decide quanto sai é sempre o valor em dólar.

9.3 Limites

curl https://api.dexkey.finance/v1/cards/{id}/limits -H "Authorization: Bearer $TOKEN"
{
  "perTransactionUsdCents": "500000",
  "dailyUsdCents": "1000000",
  "monthlyUsdCents": "5000000",
  "maxVelocityPerMinute": 5
}

Hoje apenas maxVelocityPerMinute é verificado antes de uma operação. Os três valores monetários são configuração exibida: nenhuma operação é recusada por causa deles. Exiba-os como informação, não como validação de formulário.

9.4 Credenciais do cartão (PAN, CVV, validade)

curl https://api.dexkey.finance/v1/cards/{id}/secure-credentials \
  -H "Authorization: Bearer $TOKEN"

Duas formas de entrega, e a integração precisa tratar as duas:

{ "deliveryMode": "hosted", "url": "https://provedor…/card/…", "expiresAt": "2026-09-15T14:35:00.000Z" }
{
  "deliveryMode": "direct",
  "pan": "5375420000004821",
  "securityCode": "123",
  "expiryMonth": "07",
  "expiryYear": "2029",
  "expirationDate": "07/29"
}
deliveryMode O que fazer
hosted Abra a url do provedor numa janela interna do app (webview) ou iframe. Os dados do cartão não passam pelo seu sistema
direct Os dados vêm na resposta. Exiba só quando a pessoa tocar para ver, não grave em log, não guarde em cache e não salve em lugar nenhum

Todo acesso a este endpoint é gravado em auditoria imutável com o IP de origem. Exibir o PAN coloca sua aplicação no escopo PCI-DSS — prefira hosted quando o provedor oferecer.

GET /cards/{id}/wallet-provisioning devolve o mesmo conteúdo no formato que Apple Wallet e Google Wallet esperam, e só funciona quando a entrega é direct.

10. Fase 6 — Recarga

Três chamadas, nesta ordem: valor mínimo → simulação → confirmação. Moedas de origem aceitas: BRT, USDC e USDT.

10.1 O valor mínimo, antes de a pessoa digitar

curl "https://api.dexkey.finance/v1/cards/load/limits?sourceCurrency=USDT" \
  -H "Authorization: Bearer $TOKEN"
{
  "sourceCurrency": "USDT",
  "minimumSourceAmount": "1156",
  "minimumUsdCents": "1000",
  "exchangeRate": "1.00000000",
  "feeFixedSourceAmount": "150",
  "feePercentageRate": "0.5"
}

minimumSourceAmount vem na **mesma unidade de **sourceAmount (centésimos) e já inclui a taxa vigente. Use este número para abrir a tela e para validar o campo de valor.

Não escreva um mínimo fixo na tela ("a partir de 10 USDT"). O mínimo muda junto com a taxa: se a taxa subir, a pessoa digita o valor anunciado e a recarga é recusada; se cair, ela recebe no cartão menos do que esperava. Pergunte o número a cada abertura de tela.

A cotação devolvida aqui é só indicativa. A que vale na operação é a da simulação (passo 10.2).

10.2 Simulação

curl -X POST https://api.dexkey.finance/v1/cards/load/preview \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "sourceCurrency": "USDT", "sourceAmount": "10000" }'
{
  "sourceCurrency": "USDT",
  "sourceAmount": "10000",
  "grossUsdCents": "10000",
  "chargedFeeSourceAmount": "200",
  "chargedFeeUsdCents": "200",
  "netLoadedUsdCents": "9800",
  "exchangeRate": "1.00000000",
  "quoteToken": "eyJhbGciOi…",
  "expiresInSeconds": 120,
  "limits": { "minimumSourceAmount": "1156", "minimumUsdCents": "1000" }
}

> Não envie cardId neste corpo. Campo desconhecido é rejeitado com 400. O cartão só entra na confirmação.

Campo O que é
grossUsdCents O que sai da conta DEX, em dólar
chargedFeeUsdCents / chargedFeeSourceAmount A taxa, nos dois lados
netLoadedUsdCents O que entra no cartão. É este número que o usuário confere
quoteToken Cotação travada por 120 segundos

10.3 Confirmação

curl -X POST https://api.dexkey.finance/v1/cards/load/confirm \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardId": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    "sourceCurrency": "USDT",
    "sourceAmount": "10000",
    "quoteToken": "eyJhbGciOi…",
    "pin": "1234"
  }'
{
  "message": "Recarga concluída",
  "loadId": "7b1f9c52-3f6a-4f2c-8f0b-2d5e7a9c1b34",
  "status": "completed",
  "netLoadedUsdCents": "9800",
  "chargedFeeUsdCents": "200"
}
status Significa
completed Saldo já disponível no cartão
awaiting_approval Retida para análise da nossa equipe — alguns participantes pedem essa conferência. O valor já saiu da conta DEX e ainda não entrou no cartão
processing Ainda não se sabe se o provedor aplicou a recarga. Consulte o status
failed Recusada. O valor e a taxa já voltaram para a conta DEX

> O 202 é o caso que exige mais cuidado. Ele vem com CARD_INTEGRATION_OUTCOME_UNKNOWN e significa que o provedor não confirmou nem negou: a recarga pode ter sido aplicada. Não repita a operação — consulte GET /cards/{id}/load/{loadId} até o status sair de processing. Uma rotina automática confere com o provedor e resolve sozinha.

> Esta chamada não tem proteção contra envio repetido. Não existe cabeçalho de idempotência aqui: se a requisição der timeout e você reenviar, o sistema entende como uma segunda recarga e debita de novo. Diante de qualquer resposta inconclusiva, consulte o status — nunca reenvie.

10.4 Status de uma recarga

curl https://api.dexkey.finance/v1/cards/{id}/load/{loadId} \
  -H "Authorization: Bearer $TOKEN"
{
  "id": "7b1f9c52-3f6a-4f2c-8f0b-2d5e7a9c1b34",
  "cardId": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
  "sourceCurrency": "USDT",
  "sourceAmount": "10000",
  "amountUsdCents": "9800",
  "chargedFeeUsdCents": "200",
  "exchangeRate": "1.00000000",
  "status": "completed",
  "createdAt": "2026-09-15T14:30:00.000Z"
}

11. Fase 6 — Resgate

Devolve saldo do cartão para a conta DEX, na moeda escolhida.

curl -X POST https://api.dexkey.finance/v1/cards/redeem/preview \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "cardId": "a0eebc99-…", "amountUsdCents": "5000", "targetCurrency": "USDT" }'
{
  "cardId": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
  "amountUsdCents": "5000",
  "chargedFeeUsdCents": "100",
  "targetCurrency": "USDT",
  "grossTargetAmount": "5000",
  "chargedFeeTargetAmount": "100",
  "targetAmount": "4900",
  "exchangeRate": "1.00000000",
  "usdToTargetRate": "1.00000000",
  "limits": { "minimumUsdCents": "1000", "maximumUsdCents": "21105", "availableUsdCents": "23450" }
}

A confirmação é o mesmo corpo **mais o **pin, em POST /cards/redeem/confirm.

> O máximo resgatável é uma porcentagem do saldo, então ele cai quando o saldo cai. Se a pessoa fizer uma compra entre a simulação e a confirmação, maximumUsdCents diminui e a confirmação é recusada — o sistema não resgata um valor menor por conta própria. Trate 422 CARD_REDEEM_ABOVE_PROVIDER_CEILING como "refaça a simulação", e não como falha do sistema.

status na confirmação Significa
completed Valor já creditado na conta DEX
pending · provider_confirmed Ainda em andamento — consulte de novo em instantes
failed Nada se moveu
settlement_failed O valor saiu do cartão e ainda não entrou na conta DEX. Uma rotina automática recoloca o crédito sozinha. O usuário não deve repetir a operação — avise que já está sendo regularizado

12. Fase 6 — Congelar e Descongelar

curl -X POST https://api.dexkey.finance/v1/cards/{id}/freeze   -H "Authorization: Bearer $TOKEN"
curl -X POST https://api.dexkey.finance/v1/cards/{id}/unfreeze -H "Authorization: Bearer $TOKEN"
{
  "id": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
  "status": "frozen",
  "frozenBy": "HOLDER",
  "frozenAt": "2026-09-15T14:32:00.000Z",
  "freezeReason": null,
  "canUnfreeze": true,
  "message": "Cartão congelado com sucesso"
}

Congelar bloqueia novas compras imediatamente, sem encerrar o cartão: número, validade e saldo continuam os mesmos, e o próprio titular desfaz quando quiser.

> Só quem congelou pode descongelar. Se o bloqueio foi aplicado pela nossa equipe, a chamada devolve 403 CARD_FREEZE_ADMIN_LOCKED e só o suporte reverte. Decida pelo campo canUnfreeze se mostra o botão de descongelar ou o contato do suporte — o status sozinho não diz quem congelou.

Um 503 significa que o emissor está fora do ar e que nada foi alterado: o cartão continua exatamente como estava. Não mostre o cartão como congelado nesse caso.

13. Fase 6 — Extrato

curl "https://api.dexkey.finance/v1/cards/{id}/transactions?limit=20&offset=0&operation=PURCHASE" \
  -H "Authorization: Bearer $TOKEN"
{
  "entries": [
    {
      "id": "c9d8e7f6-a5b4-4c3d-9e2f-1a0b9c8d7e6f",
      "operation": "PURCHASE",
      "status": "COMPLETED",
      "description": "SPOTIFY BR",
      "beneficiary": "SPOTIFY BR",
      "amountUsdCents": "1990",
      "originalCurrency": "BRL",
      "originalAmount": "10940",
      "occurredAt": "2026-09-14T20:11:00.000Z",
      "declineReason": null,
      "declineReasonCode": null,
      "exchangeRate": "5.49800000",
      "usdToOriginalRate": "5.49800000",
      "feeUsdCents": null,
      "feeOriginalAmount": null
    }
  ],
  "total": 134,
  "limit": 20,
  "offset": 0
}

Compras, recargas e resgates vêm na mesma lista, do mais recente para o mais antigo.

Filtro Valores
operation PURCHASE, CARD_LOAD, CARD_REDEEM, WITHDRAWAL, REFUND, REVERSAL, ADJUSTMENT
status COMPLETED, PROCESSING, DECLINED, CANCELLED, REVERSED
currency BRT, USDC, USDT
startDate / endDate ISO-8601
search Busca por nome do estabelecimento ou pela moeda (até 120 caracteres)
limit / offset limit máximo 100, padrão 20
  • GET /cards/{id}/transactions/{txId} devolve uma linha específica, no mesmo formato da lista.
  • GET /cards/{id}/statement/export devolve o extrato em PDF (application/pdf), aceitando os mesmos filtros. Se o período tiver mais de mil movimentos, o PDF traz os mais recentes.

14. Erros Desta Área

Código HTTP Significa
CARD_CONFIG_MODULE_DISABLED 403 DexCard não liberado para o participante do usuário
CARD_CONFIG_LOAD_DISABLED / CARD_CONFIG_REDEEM_DISABLED 403 Recarga ou resgate desativados para o participante
CARD_NOT_ELIGIBLE 403 Há impedimentos — consulte GET /cards/eligibility para saber quais
CARD_QUOTA_EXCEEDED 403 Cota de emissões do participante esgotada
CARD_POLICY_CANNOT_REAPPLY 403 Recusa anterior definitiva
CARD_AUTHZ_ACCESS_DENIED 403 O cartão é de outro titular
CARD_FREEZE_ADMIN_LOCKED 403 Bloqueio da equipe; só o suporte reverte
CARD_RESOURCE_NOT_FOUND 404 Cartão, recarga ou movimento inexistente
CARD_DOCUMENT_CONTENT_INVALID 400 Arquivo vazio, danificado, ou de formato diferente do declarado
CARD_DOCUMENTS_INCOMPLETE 422 Falta algum dos três documentos
CARD_HOLDER_DATA_INCOMPLETE 422 Falta perfil, endereço ou data de nascimento
CARD_ISSUANCE_FEE_INSUFFICIENT_BALANCE 422 Saldo não cobre a tarifa de emissão
CARD_STATE_NOT_ACTIVE 400 O cartão não está ativo para a operação
CARD_FREEZE_INVALID_STATUS 409 Congelar o que já está congelado, ou descongelar o que não está
CARD_INVALID_PIN 401 PIN incorreto
CARD_QUOTE_EXPIRED / CARD_QUOTE_MISMATCH 422 Cotação vencida ou diferente da simulada — simule de novo
CARD_AMOUNT_BELOW_FEE 422 Valor menor que a taxa aplicável
CARD_AMOUNT_BELOW_PROVIDER_MINIMUM 422 Abaixo do mínimo do provedor
CARD_LOAD_INSUFFICIENT_BALANCE 422 Saldo da conta DEX não cobre a recarga
CARD_REDEEM_INSUFFICIENT_BALANCE 422 Saldo do cartão não cobre o resgate
CARD_REDEEM_ABOVE_PROVIDER_CEILING 422 Acima do teto percentual do saldo
CARD_VELOCITY_LIMIT_EXCEEDED 429 Operações por minuto acima do permitido
CARD_INTEGRATION_OUTCOME_UNKNOWN 202 Não se sabe se a operação foi aplicada — consulte o status, não repita
CARD_INTEGRATION_FABRIC_UNAVAILABLE 503 Emissor fora do ar. Nada foi alterado
CARD_EXCHANGE_RATE_UNAVAILABLE 503 Nenhum provedor de cotação respondeu
CARD_CREDENTIALS_UNAVAILABLE 422 O provedor não devolveu as credenciais completas

Todo erro segue o formato padrão da API. Trate pelo errorCode, nunca pelo texto.

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

  1. Não há aviso automático (webhook) de cartão. Emissão, recarga, resgate e compras são descobertos por consulta. Planeje quando perguntar: application-status durante a análise, my-cards e balance ao abrir a tela, load/{loadId} enquanto uma recarga estiver sem desfecho.
  2. Recarga e resgate exigem o PIN do usuário. Não dá para fazer essas duas operações apenas de servidor para servidor: é preciso uma tela onde a pessoa digita o PIN na hora.
  3. Não existe Idempotency-Key nesta API. Reenviar load/confirm cria uma segunda recarga. Diante de qualquer resposta inconclusiva, consulte o status em vez de reenviar.
  4. Todo valor é inteiro dentro de aspas. …UsdCents em centavos de dólar; …SourceAmount e …TargetAmount em centésimos da moeda. Nunca converta um no outro por conta própria — o servidor já devolve os dois.
  5. A tarifa de emissão é cobrada no pedido, não na aprovação. Recusa gera estorno do valor pago.
  6. availableUsdCents** já vem descontado** das compras aprovadas e ainda não cobradas. Não subtraia pendingHoldUsdCents dele.
  7. Cancelar cartão não é operação do titular. Não existe endpoint de cancelamento nesta API — o pedido passa pelo suporte.
  8. Use exatamente os caminhos documentados. Qualquer coisa depois de /cards/ que não esteja nesta página é lida como identificador de cartão: /cards/qualquer-coisa vira GET /cards/{id} e devolve 400 por não ser um identificador válido.