Orquestre antifraude, tokenização, preparação 3DS e confirmação financeira.
| Etapa | Responsabilidade |
|---|---|
| Antifraude | Coleta de dispositivo, quando habilitada |
| Tokenização | SDK envia cartão à API da plataforma e recebe token |
| Preparação 3DS | pre_charge produz autenticação; device_only produz contexto para a cobrança |
| Criar cobrança | Seu backend usa a mesma chave de idempotência, token e contexto |
| Challenge | Se houver action, o navegador a consome uma vez |
| Confirmar pagamento | Backend valida webhook ou reconsulta e conclui os efeitos financeiros |
Para a maioria das integrações, prefira preparePayment. Use os controladores individuais quando precisar coordenar etapas separadamente.
import type { ThreeDSResult } from '@soarlabz/security-sdk';
const idempotencyKey = crypto.randomUUID();
const fraud = client.isFraudAnalysisAvailable()
? await client.fraudAnalysis.setup() : undefined;
const token = await client.tokenizer.tokenize({ card: paymentRequest.card });
let auth: ThreeDSResult | undefined;
if (client.isThreeDSAvailable()) {
auth = await client.threeds.authenticate({
...paymentRequest,
idempotencyKey,
paymentLinkId: linkId,
paymentMethod: 'credit_card',
card: { ...paymentRequest.card, brand: token.brand },
});
if (auth.status === 'failed' || auth.status === 'error') {
throw new Error('Preparação/autenticação 3DS não concluída');
}
} else if (client.isSmartThreeDSAvailable()) {
const collected = await client.zendry.threeDS();
auth = { status: 'authenticated', mode: 'device_only', device: collected.device,
userAgent: collected.user_agent ?? undefined };
}
// Rotas mistas podem exigir CAVV para um fallback e device para a Zendry.
if (auth && !auth.device && client.isSmartThreeDSAvailable()) {
const collected = await client.zendry.threeDS();
auth = { ...auth, device: collected.device, userAgent: collected.user_agent ?? undefined };
}
const charge = await criarCobrancaNoSeuBackend({
amount: paymentRequest.amount,
currency: paymentRequest.currency,
payment_method: 'credit_card',
payment_details: { token: token.token, installments: paymentRequest.installments ?? 1 },
idempotency_key: idempotencyKey,
fraud_session_id: fraud?.sessionId,
three_ds_session_id: auth?.sessionId,
three_ds: auth?.cavv ? {
cavv: auth.cavv, eci: auth.eci, xid: auth.xid, version: auth.version,
reference_id: auth.referenceId,
} : undefined,
metadata: { device: auth?.device, user_agent: auth?.userAgent },
});
if (charge.payment_fields?.threeds_action) {
marcarChallengeIniciado(idempotencyKey);
await client.zendry.completeThreeDS(charge.payment_fields.threeds_action);
}
const confirmed = await consultarConfirmacaoNoSeuBackend(charge.id, idempotencyKey);
if (confirmed.status === 'captured' && !confirmed.confirmation_pending) mostrarSucesso();Os helpers acima pertencem à sua aplicação. A chave secreta existe somente no backend. Na integração em cadeia, o backend deve enviar IP e user-agent do comprador, além do device.
Data-only/frictionless pode terminar sem tela; o emissor decide se uma interação será necessária. O retorno authorized do browser não substitui a confirmação financeira da plataforma.
Um challenge tem action de uso único e expira em 15 minutos. Marque seu início antes de chamar o SDK. Após reload, timeout ou falha de rede, consulte a cobrança original sem reexecutar action nem criar outra mutação financeira.
O link da plataforma restaura a referência da tentativa sem persistir cartão ou dados do comprador. Ele aguarda captured com confirmation_pending false, incluindo a aplicação dos efeitos financeiros, antes de confirmar e redirecionar.
Uma nova tentativa usa outra chave somente após um resultado terminal confirmado da anterior. Em resultado ambíguo, continue consultando a mesma cobrança.