Pular para o conteúdo
No ar em produção, em modo shadow: o FingerTrackID recomenda, o seu sistema decide.Status →

SDK de servidor para Node.js

No ar · modo shadowNode.js 24.16+

@fingertrackid/server é o cliente do FingerTrackID para um backend Node.js. Ele monta cada requisição com as mesmas regras que a API aplica, assina-a com o assinador de referência, faz nova tentativa apenas do que o catálogo publicado de Problems marca como passível de nova tentativa e devolve cada caso como um resultado. Ele nunca lança exceção depois da inicialização, então o seu produto mantém a própria decisão quando o FingerTrackID está lento ou indisponível.

O SDK é opcional. Qualquer backend que siga as regras de autenticação e reproduza o vetor de teste público se integra da mesma forma; os contratos publicados prevalecem sobre o SDK, como sobre qualquer exemplo.

Node.js 24.16 ou mais recente na série 24, ou 26.1 ou mais recente. Fixe a versão exata.

self-check reproduz o vetor público de assinatura no Node.js que o executa e não precisa de credencial.

O pacote não tem dependência em tempo de instalação nem script de instalação: é um único bundle não minificado que você pode ler, com as licenças de código aberto que ele carrega em THIRD-PARTY-NOTICES.txt. Compare o integrity do seu lockfile com npm view @fingertrackid/server@0.1.2 dist.integrity.

Terminal
npm install --save-exact @fingertrackid/server@0.1.2
npx --no fingertrackid-server self-check

O cliente recebe seus valores como opções; os exemplos os leem destas variáveis, que o comando check também lê:

Variável Valor
FTID_KEY_ID O key_id da credencial de servidor, do console ou de fingertrackid.integration.json
FTID_HMAC_SECRET_HEX Os 64 caracteres hexadecimais mostrados uma única vez no console, lidos do seu gerenciador de segredos

A origem da API tem como padrão https://api.fingertrackid.com; deixe apiOrigin sem definir em produção.

Crie um único cliente quando o backend iniciar. Um valor ausente ou malformado lança FtidConfigurationError com um code fixo e nunca repete o valor.

ftid.ts
import { createFtidServerClient, type FtidServerClient } from '@fingertrackid/server'
let ftid: FtidServerClient | null = null
try {
ftid = createFtidServerClient({
keyId: process.env.FTID_KEY_ID ?? '',
secretHex: process.env.FTID_HMAC_SECRET_HEX ?? '',
})
} catch (error) {
// Alert on it, and keep the product running without FingerTrackID.
logger.error('ftid.configuration_error', { code: (error as { code?: string }).code })
}

Chame assess depois das suas próprias verificações, com a etiqueta que você escolheu para o momento (jornadas e etiquetas) e o token que o Web SDK gerou para esta ação.

login.ts
// `ftid` is null after a configuration error: `result` is then undefined, and the action goes on.
const result = await ftid?.assess({
tag: 'login',
subjectRef: pseudonymOf(user), // a keyed pseudonym, never an email or tax ID
eventContextToken: body.ftidToken ?? null,
eventContextExpiresAt: body.ftidTokenExpiresAt ?? null,
})
result.kind Significado O que o seu backend faz
ASSESSED result.assessment é a resposta Registre-a; a sua própria política decide
INVALID_INPUT A requisição nunca saiu: result.issues nomeia cada campo Corrija a chamada; nada foi enviado
PROBLEM A API respondeu com um Problem do catálogo Siga result.problem.category
UNAVAILABLE Limite de taxa, indisponibilidade, relógio ou timeout, depois das novas tentativas permitidas Mantenha a sua decisão; a requisição pode ter sido armazenada
UNEXPECTED_RESPONSE Uma resposta fora do contrato Mantenha a sua decisão e informe o correlationId

Todo resultado traz severity (info, warn ou error) para os seus logs, e todo resultado de um envio traz correlationId para o suporte. Registre em log apenas identificadores e veredictos: nunca o segredo, o token, a assinatura ou o corpo da requisição.

  • Valida a requisição com o mesmo schema que a API aplica e serializa o corpo uma única vez.
  • Envia no máximo 3 tentativas dentro de 10 segundos, cada uma com timeout de 6,5 segundos, acima do orçamento de 5 segundos do servidor. O orçamento corre em um relógio que nunca volta atrás, então uma mudança no relógio do sistema não pode estendê-lo, e a primeira tentativa sempre começa. Uma nova tentativa reenvia os mesmos bytes com um novo X-FTID-Request-Id, o timestamp atual e uma nova assinatura.
  • Faz nova tentativa apenas de Problems que o catálogo publicado marca como passíveis de nova tentativa e de tentativas cujo resultado é desconhecido, aguardando o Retry-After (no mínimo 1 segundo) depois de um 429 ou 503. Um 429, 502, 503 ou 504 sem corpo de Problem, como um proxy pode enviar, conta como resultado desconhecido.
  • Descarta um token de contexto do evento que expiraria antes do fim da primeira tentativa e avalia sem ele.
  • Quando a API responde event-context-invalid a uma requisição que levava um token, avalia o evento mais uma vez como uma nova operação sem o token, com um novo ID externo do evento e uma nova chave de idempotência, que result.operation traz. Essa segunda operação mantém o instante da ação e gasta apenas o que resta das tentativas e do orçamento da chamada; se não restar o suficiente, a recusa é o resultado. Defina retryWithoutEventContext: false para desligar isso.
  • Devolve INVALID_INPUT em vez de lançar exceção para um argumento fora dos tipos documentados, como uma string ISO onde occurredAt espera um Date.
  • Informa cada tentativa, nova tentativa e resultado a um callback onEvent opcional, sem o segredo, o token, a assinatura ou o corpo.
Opção Padrão Faixa
apiOrigin https://api.fingertrackid.com Uma origem https:
timeoutMs 6500 Por tentativa
budgetMs 10000 Até 60000
maxAttempts 3 De 1 a 5
retryWithoutEventContext true
onEvent nenhum Exceções que ele lança, e rejeições de uma promise que ele retorna, são ignoradas

Um resultado de um envio traz result.operation: o caminho, o corpo exato, o ID externo e a chave de idempotência. Guarde-o junto com o seu próprio registro quando o resultado importar e envie-o de novo com o método do tipo dele: ftid.resend(operation) para uma avaliação, ftid.resendCustomerAction(operation) ou ftid.resendOutcome(operation) para feedback. Cada um envia os mesmos bytes com uma nova assinatura, como idempotência e nova tentativa exige; nunca monte um novo corpo para a mesma ação.

operation.body contém o token de contexto do evento e o subject_ref como foram enviados: mantenha-o com o registro, fora dos logs.

Essas chamadas precisam das capacidades action:write e outcome:write e devolvem os mesmos tipos de resultado, com RECORDED e o recibo no lugar de ASSESSED. Veja feedback.

Um desfecho LEGITIMATE ou FRAUD_CONFIRMED também precisa dos campos de evidência: evidenceSource, evidenceReference e evidenceConfidence.

feedback.ts
await ftid?.recordCustomerAction(assessmentId, {
action: 'ALLOWED',
basis: 'CLIENT_POLICY',
reasonCode: 'CLIENT_POLICY_RULE',
})
await ftid?.recordOutcome(assessmentId, {
truthStatus: 'PENDING',
labelMaturity: 'PROVISIONAL',
reasonCode: 'INITIAL_OBSERVATION',
})

check envia uma avaliação em modo shadow, com a etiqueta integration_check e sem token do navegador, e imprime o resultado. O key_id vem de FTID_KEY_ID ou, quando ela não está definida, do arquivo de integração (--manifest <path>, ou fingertrackid.integration.json no diretório atual) quando ele lista exatamente uma credencial que pode avaliar; com várias, defina FTID_KEY_ID. O segredo vem somente de FTID_HMAC_SECRET_HEX ou da entrada padrão (no máximo 4.096 bytes, em até 30 segundos), nunca de um argumento. FTID_API_ORIGIN, quando definida para o check, só pode indicar a API de produção ou um dublê de teste em loopback.

--no faz o npx executar só a cópia que o seu projeto instalou: ele nunca baixa do registro um pacote de mesmo nome, o que importa quando o segredo está na entrada padrão.

Terminal
your-secret-manager read ftid-hmac-secret | FTID_KEY_ID=<key_id> npx --no fingertrackid-server check

Implemente a string canônica e confira-a com o vetor de teste público antes da primeira chamada real. Um agente de IA de programação pode comparar o assinador dele com o vetor pelo servidor MCP.