Sessões de Verificação
Uma sessão representa uma verificação de identidade. Criá-la retorna uma widgetUrl que você entrega ao seu cliente e um sessionId que você usa para correlacionar o resultado.
Criar uma Sessão
Endpoint: POST /v1/sessions
Autenticação: Token Bearer com o escopo sessions
curl --request POST \
--url https://{FQDN}/v1/sessions \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"userRef": "user-123",
"language": "es",
"delivery": { "mode": "webhook" }
}'
{
"sessionId": "9f1c8e42-7c3e-4f2b-9d7a-2b1e5c8f4a10",
"status": "pending",
"widgetUrl": "https://{FQDN}/verify/8Kd2mQ…",
"expiresAt": "2026-08-02T15:02:11.481Z"
}
Campos da Requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
userRef | string (1-255) | Sim | Seu identificador para a pessoa sendo verificada. Devolvido em todos os resultados |
prefill | object | Não | Dados conhecidos sobre a pessoa — veja Prefill |
dataCheck | boolean | Não | false (padrão) verifica o documento conforme apresentado. true adicionalmente compara os dados extraídos com o prefill — veja Verificações de Dados |
delivery | object | Não | Como o resultado chega até você. O padrão é {"mode": "webhook"} |
language | string | Não | Idioma do widget, xx ou xx-XX (ex.: en, pt, es, pt-BR). Recorre ao seu padrão configurado |
maxCaptureAttempts | integer (1-10) | Não | Sobrescreve o padrão do seu tenant apenas para esta sessão. Aplica-se por tipo de captura — este número de tentativas de documento e o mesmo de selfie |
Campos da Resposta
| Campo | Descrição |
|---|---|
sessionId | Use-o para correlacionar resultados e para chamar GET /v1/sessions/{sessionId} |
status | pending na criação, a menos que um cenário de sandbox encerre a sessão de imediato |
widgetUrl | O link voltado ao cliente. Contém um código de uso único válido por 48 horas — veja Expiração da Sessão |
expiresAt | O prazo da sessão, um timestamp ISO 8601 em UTC — veja Expiração da Sessão |
Prefill
O prefill carrega o que você já sabe sobre a pessoa. Ele tem dois efeitos distintos.
| Campo | Efeito |
|---|---|
documentType | passport, drivers_license ou identity_card. Trava o widget neste documento — a tela de seleção de tipo é pulada, e um documento diferente é rejeitado. Omita-o para deixar o cliente escolher |
documentNumber | Validado quanto ao formato nesta chamada (veja abaixo) e disponível para verificação cruzada |
issuingState | Somente a subdivisão — código ou nome de estado dos EUA. Refina a validação de formato de uma carteira. Exige issuingCountry: PA é tanto Pará quanto Pennsylvania, então uma subdivisão enviada sozinha é rejeitada com 422. Um código de país aqui não nomeia nada e nunca é comparado com o documento, porque passaportes e carteiras de identidade não evidenciam subdivisão alguma |
issuingCountry | ISO 3166-1 alpha-3 — três letras. O único campo que nomeia a jurisdição emissora, e aquele contra o qual suas jurisdições aceitas são verificadas. Um código que não conseguimos situar não resolve nada, então uma sessão que o declara é julgada apenas pelo documento |
nationality | ISO 3166-1 alpha-3 — três letras. Disponível para verificação cruzada com o documento. Nunca resolve a jurisdição emissora — nacionalidade não é emissão, em nenhum tipo de documento |
firstName, lastName | Disponíveis para verificação cruzada |
dateOfBirth | YYYY-MM-DD. Disponível para verificação cruzada |
Todo campo de prefill é uma string de no máximo 255 caracteres. Envie um campo apenas quando tiver um valor para ele: um valor em branco ou só com espaços é rejeitado em vez de ignorado, para que um campo que você não forneceu nunca seja reportado como um com o qual o documento divergiu.
{
"userRef": "user-123",
"prefill": {
"documentType": "drivers_license",
"issuingCountry": "USA",
"issuingState": "PA",
"documentNumber": "31612967",
"firstName": "Ana",
"lastName": "Silva",
"dateOfBirth": "1988-03-04"
}
}
Campos de prefill diferentes de documentType não alteram a decisão a menos que você defina dataCheck: true. Sem isso, os valores são carregados para comparação e reportados no resultado, mas uma divergência não encaminha a sessão para lugar nenhum.
O prefill.documentNumber é validado nesta chamada, no entanto: um número que uma regra consegue refutar — um dígito verificador que falha, ou um valor que nenhuma jurisdição poderia emitir — é rejeitado com 422 em vez de ser aceito e reprovado depois. Um número que apenas não corresponde a nenhuma das formas que mantemos para sua jurisdição não é recusado; ele é levado adiante, e o resultado publica document_number_valid como undetermined. Verifique um número antes de chegar aqui com o endpoint validador.
Verificações de Dados
Defina dataCheck: true para verificar que o documento pertence à pessoa que você esperava — não apenas que o documento é genuíno.
{
"userRef": "user-123",
"dataCheck": true,
"prefill": {
"firstName": "Ana",
"lastName": "Silva",
"dateOfBirth": "1988-03-04"
}
}
Com dataCheck: true:
- Os dados extraídos são comparados campo a campo com o payload de prefill.
- O resultado carrega
prefillComparison(resultados por campo, incluindo pontuações de correspondência aproximada de nomes) eprefillMismatches(os nomes dos campos que divergiram). - Uma divergência adiciona uma checagem
document_data_matchreprovada e é reportada no resultado.
Nomes são comparados com correspondência aproximada (fuzzy) contra um limiar de similaridade configurável, então variações comuns de grafia e transliteração não criam falsas divergências. dataCheck: true sem um payload de prefill é um 422 — não haveria nada com que comparar.
Entrega
| Modo | Campos | Comportamento |
|---|---|---|
webhook (padrão) | — | O resultado é enviado via POST para a sua webhookUrl configurada |
redirect | redirectUrl (obrigatório) | O cliente é retornado à sua URL com o resultado e uma assinatura |
{ "delivery": { "mode": "redirect", "redirectUrl": "https://you.example/kyc-done" } }
Solicitar o modo webhook sem uma webhookUrl configurada para o seu tenant é um 422. Veja Recebendo Resultados para a verificação de assinatura em ambos os modos.
Respostas de Erro
Todas estas retornam 422 com errorCode: "validation_error"; errors[] nomeia o campo e a causa:
| Causa | Notas |
|---|---|
delivery.mode é webhook mas nenhuma webhookUrl está configurada | Peça à Inyo para registrar seu endpoint, ou use o modo redirect |
delivery.redirectUrl ausente no modo redirect | Obrigatório sempre que mode for redirect |
documentType não está habilitado para o seu tenant | A mensagem lista os tipos de documento que você pode solicitar |
| A jurisdição emissora do documento não é aceita para esse tipo de documento | A mensagem lista as jurisdições que você aceita |
prefill.documentNumber foi refutado por sua regra | Apenas uma falha comprovável — um dígito verificador, ou um valor que nenhuma jurisdição poderia emitir. A mensagem nomeia a regra, nunca o número |
dataCheck: true sem payload de prefill | Forneça pelo menos um campo de prefill comparável |
| Um campo de prefill está em branco ou contém apenas espaços | Omita o campo. Um branco não é "sem valor" — ele seria comparado com o documento e reportado como divergência |
| Um campo de prefill tem mais de 255 caracteres | O mesmo limite de userRef |
prefill.issuingState enviado sem prefill.issuingCountry | Uma subdivisão não nomeia nada sozinha — o mesmo código existe em mais de um país |
issuingCountry ou nationality não tem três letras | Nomes de país e códigos de duas letras são recusados — envie o código ISO 3166-1 alpha-3. Códigos de espécime e de apátrida (UTO, XXA, XKX) são aceitos, então a verificação é a forma, não uma lista de países |
dateOfBirth não é uma data real em YYYY-MM-DD | 1987-13-45 corresponde à forma e não é uma data |
| Um nome de campo não reconhecido em qualquer lugar da requisição | Recusado em vez de ignorado, para que um dataCheck com erro de grafia não desligue a comparação silenciosamente. Grafias em camelCase e snake_case de campos reais são ambas aceitas |
userRef ou um campo de prefill contém um NUL (\u0000) | O valor não pode ser armazenado. Acentos, pontuação e espaços dentro de um valor são aceitáveis — este é o único caractere que não é |
Falhas de autenticação e autorização retornam 401 ou 403 — veja Autenticação.
Recuperar uma Sessão
Endpoint: GET /v1/sessions/{sessionId}
Autenticação: Token Bearer com o escopo sessions
Este é o registro autoritativo de uma sessão de widget. Leia-o quando você precisar de uma garantia em vez de um push, para recuperar um webhook que você pode ter perdido, ou para ler o resultado de uma sessão que foi para revisão manual.
Uma verificação criada com POST /v1/verifications não é servida aqui — ela tem uma leitura própria em GET /v1/verifications/{verificationId}, acessível com o scope verifications. Passar uma delas aqui retorna 404.
curl --request GET \
--url https://{FQDN}/v1/sessions/$SESSION_ID \
--header "Authorization: Bearer $ACCESS_TOKEN"
{
"sessionId": "9f1c8e42-7c3e-4f2b-9d7a-2b1e5c8f4a10",
"userRef": "user-123",
"status": "completed",
"step": "done",
"deliveryMode": "webhook",
"result": { "…": "the normalized result, updated in place" },
"createdAt": "2026-07-31T14:02:11.481Z",
"updatedAt": "2026-07-31T14:04:57.902Z",
"expiresAt": "2026-08-02T15:02:11.481Z"
}
| Campo | Descrição |
|---|---|
status | pending, completed, failed ou expired — a posição no ciclo de vida, nunca um veredito. O desfecho, quando você o recebe, é result.decision |
step | Até onde o cliente chegou: device_identification, document_front, document_back, selfie ou done. device_identification é a identificação do navegador do cliente antes do documento, e aparece apenas quando a Inteligência de Dispositivo está habilitada |
deliveryMode | webhook ou redirect — como o desfecho desta sessão chega até você, escolhido na criação |
result | O resultado normalizado completo quando disponível, null antes disso. Atualizado no lugar quando um analista decide |
expiresAt | O prazo da sessão, o mesmo valor que a resposta de criação devolveu |
As sessões são estritamente limitadas ao tenant. O sessionId de outro tenant retorna 404 — nunca uma divulgação parcial.
Expiração da Sessão
Uma sessão que o cliente não termina a tempo termina em expired. O prazo dela é fixado quando você a cria: as 48 horas do link mais a hora que um cliente que abriu o link no fim tem para terminar — 49 horas após a criação por padrão, devolvido como expiresAt na resposta de criação e na leitura. Uma mudança posterior na vida útil do link nunca move o prazo de uma sessão que já existe.
| Quando | O que acontece |
|---|---|
| 48 horas após a criação | O link deixa de abrir. O cliente vê uma mensagem de link expirado |
| No prazo | A sessão termina em expired, em poucos minutos. Se o link for aberto depois do prazo, ela termina na hora |
| Um envio ainda está em avaliação no prazo | Não expira enquanto a avaliação roda — a sessão termina com o desfecho dela |
Tudo o que ainda não foi enviado expira: um link que nunca foi aberto, ou um cliente que parou no meio. Uma sessão expirada não carrega decision nem avaliação, e é entregue a você como qualquer outro desfecho — por webhook no modo webhook. Um cliente num link expirado vê a mensagem de link expirado em vez da sua redirectUrl, então no modo redirect ela chega até você como uma notificação de resultado quando você tem um webhookUrl, e pela leitura em qualquer caso. Depois que uma sessão termina, nenhuma captura adicional é aceita.
Verificações server-to-server não têm prazo e nunca expiram.
Próximos Passos
- Validador de Número de Documento — verifique um número antes de chegar aqui
- Entrega do Widget — conduzindo o cliente pelo fluxo
- Recebendo Resultados — tratamento de webhook e redirect
- Sandbox e Dados de Teste — números de documento reservados que ditam todo o resultado de uma verificação
