Implemente um offramp USDT → Pix
Caminho de ponta a ponta para uma integração offramp. Da cotação ao webhook de conclusão, com tratamento de standby.
Este tutorial cobre uma integração offramp completa, da primeira cotação até o webhook de conclusão. Use como ponto de partida para sua implementação.
Pré-requisitos
- Chave de API ativa. Veja Sandbox e chaves.
- Cliente final cadastrado e com KYC aprovado. Veja Fluxo de KYC.
- Chave Pix do destinatário registrada no cliente final.
- Endpoint de webhook configurado com a verificação de assinatura usando o header
X-Blendfi-Signature. Veja Integração de webhooks.
Passo 1: criar a cotação
Sua organização chama POST /v1/quotes com o cliente final, o tipo pix_offramp, o valor em USDT (source_amount) ou BRL (target_amount) e a chave Pix de destino.
POST /v1/quotes HTTP/1.1
Authorization: Bearer sk_test_…
Idempotency-Key: <uuid>
Content-Type: application/json
{
"user_id": "usr_01J...",
"transaction_type": "pix_offramp",
"source_amount": "100.00",
"pix_key": "..."
}A resposta carrega id, exchange_rate, source_amount, target_amount, expires_at. Mostre target_amount ao cliente final como o valor que ele vai receber em BRL. A taxa vale 5 minutos.
📋 Schema completo em Reference (em breve)
A documentação detalhada do payload aparece aqui em conjunto com a disponibilidade da API. Os campos do exemplo acompanham o desenho conceitual em Cotação.
Passo 2: aceitar a cotação e mostrar o endereço de depósito
Confirmação do cliente final: aceite a cotação com POST /v1/quotes/:id/accept. Em uma única chamada atômica, a BlendFi cria a conversão, emite o endereço de depósito, reserva o limite e abre a janela de 15 minutos.
POST /v1/quotes/qt_01J.../accept HTTP/1.1
Authorization: Bearer sk_test_…
Idempotency-Key: <uuid>A resposta é a conversão completa, com id, status='awaiting_deposit', deposit_address, deposit_address_network, deposit_window_expires_at. Mostre deposit_address com QR ao cliente final, junto de expected_source_amount e do prazo restante.
Recomendações de UX:
- Renderize um contador regressivo até
deposit_window_expires_at. Após o prazo, o depósito segue parastandby. - Mostre
expected_source_amountem destaque. Cliente final que ajusta o valor "no clique" causa standby. - Ofereça um botão "cancelar" que chama
POST /v1/conversions/:id/cancelenquanto a conversão estiver emawaiting_deposit.
Passo 3: cliente final transfere USDT (fora da API)
O depósito on-chain acontece fora da API. Sua integração não chama nada nesse passo; apenas espera o webhook.
Passo 4: receber o webhook
A BlendFi entrega um webhook conforme o desfecho. Verifique a assinatura no header X-Blendfi-Signature (o payload assinado é {t}.{raw_body}, HMAC-SHA256 com o segredo do endpoint).
Eventos possíveis:
conversion.completed: caminho feliz. O Pix foi entregue ao destinatário.conversion.standby: divergência (under, over, ou janela expirada). Payload incluistandby_reason,received_amount,expected_source_amount. Veja Passo 5b.conversion.failed: erro irrecuperável apósfundedouliquidated. Payload incluifailure_reason.conversion.abandoned: 7 dias em standby sem ação. Resolução manual com a BlendFi.
Recomendações:
- Trate o handler como idempotente: a mesma entrega pode chegar mais de uma vez.
- Use o
conversion_idcomo chave de controle de duplicatas no seu lado.
📋 Schema completo em Reference (em breve)
Os payloads exatos vão na seção de webhooks quando o catálogo de eventos conversion.* for publicado.
Passo 5a: caminho feliz (conversion.completed)
Recebeu conversion.completed. O Pix está entregue. Mostre confirmação ao cliente final. O payload inclui o identificador Pix de ponta a ponta para sua referência interna ou de auditoria.
Fim do fluxo nominal.
Passo 5b: caminho de standby (conversion.standby)
Recebeu conversion.standby. A conversão está parada com received_amount em custódia. Decida com base em standby_reason:
standby_reason | Decisão usual |
|---|---|
under_funded | Liquidar pelo valor recebido (cliente final fica com BRL menor que o esperado, comunique a divergência) ou contatar o suporte para resolução caso a caso. |
over_funded | Liquidar pelo valor recebido (cliente final ganha BRL extra) ou contatar o suporte. |
window_expired | Liquidar (taxa nova será cotada) ou contatar o suporte. |
Para liquidar:
POST /v1/conversions/cnv_01J.../liquidate HTTP/1.1
Authorization: Bearer sk_test_…
Idempotency-Key: <uuid>A BlendFi cota uma nova taxa server-side sobre o received_amount atual e dispara a liquidação. A resposta carrega a conversão com liquidation_quote_id populado e status liquidated. Você ainda vai receber conversion.completed (ou conversion.failed) quando a liquidação Pix terminar.
Para esperar e ver: não fazer nada por até 7 dias. Após o prazo, a conversão vira abandoned e a resolução é manual. Veja Conversão abandonada.
Para cancelar antes do depósito chegar (cenário diferente do standby): POST /v1/conversions/:id/cancel, válido apenas em awaiting_deposit. Depois do depósito chegar, cancel não é mais opção. Veja Cancelamento.
Passo 6: tratamento de erros e idempotência
Idempotency-Keyem todoPOSTmutador. A retentativa segura de uma chamada já bem-sucedida retorna a mesma resposta sem efeitos colaterais.- Handler de webhook idempotente. Use
conversion_id(e o tipo de evento) como chave de controle de duplicatas. - Verificação de assinatura. Rejeite qualquer entrega cuja assinatura não confira. Veja Concepts → Webhooks.
- Tratamento de lock. Erro de lock no aceite indica que o cliente final já tem outra conversão offramp aberta. Leve a UX a tratar a conversão existente, não a criar uma nova. Veja Lock por usuário e tipo.
- Reconciliação de borda. Em incidente, leia
GET /v1/conversions?status=...para reconstruir o estado do que está aberto.
Próximos passos
- Conversão e estados: o mapa completo da máquina de estados.
- Modelo de taxas: como a taxa cotada é montada.
- Idempotência: a semântica do header
Idempotency-Key.
Implemente um onramp Pix → USDT
Caminho de ponta a ponta para uma integração onramp. Da cotação ao webhook de conclusão.
Verifique e roteie eventos de webhook com segurança
Handler de webhook em nível de produção em Node e Python. Verificação de assinatura, processamento idempotente, padrão de resposta rápida, fila de mensagens com falha (DLQ).
