Face Match + Datavalid
Este endpoint faz duas coisas em uma chamada:
- Face Match — recebe duas imagens, localiza uma face em cada uma e compara as duas entre si, exatamente como o Face Match.
- Datavalid — envia uma dessas faces ao serviço Datavalid da SERPRO e pergunta se ela corresponde à biometria oficial registrada para o CPF informado na URL.
A diferença para o Face Match puro é a segunda etapa: aqui a face não é confrontada apenas com a outra imagem que você enviou, mas também com a base oficial do governo. É isso que permite responder "esta pessoa é mesmo o titular deste CPF", e não só "estas duas fotos são da mesma pessoa".
Este endpoint não faz liveness (use o Liveness) e não extrai os dados escritos no documento (para isso existe o OCR).
Request
POST/face-match-and-datavalid/v2/natural-person/{CPF}Headers
Authorization: ApiKey <sua-chave-de-api>Este endpoint também aceita o token JWT, no formato Authorization: Bearer <accessToken>. Veja Token JWT.
Chaves da SERPRO
A consulta ao Datavalid feita por este endpoint usa o nosso acesso à SERPRO. Você não precisa ter contrato próprio com a SERPRO para usá-lo, e ele não lê chaves de cliente da requisição: os headers x-customer-key e x-customer-secret, se enviados aqui, são ignorados.
TIP
O envio das próprias chaves da SERPRO é suportado no endpoint /full-ocr-and-datavalid, não neste. Se o seu contrato prevê o uso das suas chaves, fale com o nosso suporte antes de montar a integração por aqui.
Parâmetros
| Parâmetro | Descrição | Obrigatório |
|---|---|---|
| CPF | CPF cuja biometria será consultada no Datavalid. Vai no caminho da URL, com ou sem máscara. É validado pelo dígito verificador. | Sim |
| faceToDatavalid | Qual das faces enviar ao Datavalid: IdCard ou Selfie. Query string. Padrão: IdCard. | Não |
| returnsFaceInfo | Quando presente, cada item de resources passa a trazer o objeto face, e metadata.filesInfo[].data vem vazio. Query string. Padrão: desligado. | Não |
🚧 faceToDatavalid continua existindo, e é uma preferência, não uma garantia
A API classifica cada face encontrada em dois tipos, pelo tamanho que ela ocupa na imagem: faces grandes viram SELFIE, faces pequenas — típicas de foto impressa em documento — viram ID.
faceToDatavalid=IdCard(padrão): envia ao Datavalid a primeira face do tipoID. Se não houver nenhuma, envia a face do tipoSELFIE.faceToDatavalid=Selfie: envia a primeira face do tipoSELFIE. Se não houver nenhuma, envia a face do tipoID.
Ou seja, a chamada ao Datavalid acontece de qualquer jeito, com a face disponível. Um valor fora de IdCard e Selfie faz a requisição falhar com 422.
‼️ returnsFaceInfo=false liga o parâmetro
Diferente do Face Match, aqui o valor do returnsFaceInfo não é interpretado: a simples presença do parâmetro na query string já o ativa, inclusive returnsFaceInfo=false. Para deixá-lo desligado, não envie o parâmetro.
Arquivos aceitos
| Item | Valor |
|---|---|
| Formatos | image/png, image/jpeg, application/pdf |
| Quantidade por chamada | 2 arquivos |
| Tamanho máximo (multipart) | 15 MB por arquivo |
Os nomes dos campos do formulário são livres — eles voltam na resposta, em resources e em metadata.filesInfo. Enviar mais de dois arquivos é recusado com 422.
Em PDFs de várias páginas, cada página é analisada em ordem e a primeira com alguma face detectada é a que entra na análise.
Além do multipart/form-data, os arquivos podem ser enviados em JSON, no campo base64, como descrito em Envio de arquivos.
Exemplo Request
curl -i -X POST 'https://api-homolog.nxcd.app/face-match-and-datavalid/v2/natural-person/12345678909' \
--header 'Authorization: ApiKey SUA_CHAVE_AQUI' \
--form 'documento=@./cnh.jpg' \
--form 'selfie=@./selfie.jpg'Escolhendo a selfie como face a validar no Datavalid:
curl -i -X POST 'https://api-homolog.nxcd.app/face-match-and-datavalid/v2/natural-person/123.456.789-09?faceToDatavalid=Selfie' \
--header 'Authorization: ApiKey SUA_CHAVE_AQUI' \
--form 'documento=@./cnh.jpg' \
--form 'selfie=@./selfie.jpg'Response
| Campo | Descrição | Tipo |
|---|---|---|
| id | Identificador único da requisição | String |
| version | Versão da API que atendeu a chamada | String |
| data | Lista com o resultado da análise. Traz uma entrada quando a comparação aconteceu, e vem vazia quando não. | Object[] |
| data[].matched | true quando as duas faces enviadas são da mesma pessoa. É o resultado do face match, não do Datavalid. | Boolean |
| data[].confidence | Grau de confiança da comparação entre as duas faces, de 0 a 100 | Number |
| data[].datavalid | Resultado da consulta ao Datavalid. Vem como {} quando não houve consulta. | Object |
| data[].datavalid.federalRevenueNumberAvailability | Indica se o CPF informado existe na base oficial | Boolean |
| data[].datavalid.federalRevenueNumberStatus | Indica se a situação cadastral do CPF na base oficial é regular | Boolean |
| data[].datavalid.face | Resultado da comparação da face enviada com a biometria oficial. Vem como {} quando não há biometria a comparar. | Object |
| data[].datavalid.face.availability | Indica se existe biometria facial registrada para aquele CPF na base oficial | Boolean |
| data[].datavalid.face.similarity | Similaridade entre a face enviada e a biometria oficial, em uma escala de 0 a 1 | Number |
| data[].datavalid.face.probability | Faixa de probabilidade de a face enviada ser a mesma da base oficial: VeryHigh, High, Low ou VeryLow | String |
| data[].resources | As duas faces usadas na comparação, na ordem em que foram confrontadas | Object[] |
| data[].resources[].fieldname | Nome do campo em que aquele arquivo foi enviado | String |
| data[].resources[].page | Página do arquivo em que a face foi encontrada. Começa em 0; para imagens é sempre 0. | Number |
| data[].resources[].face | Dados da face. Só aparece quando returnsFaceInfo é enviado. | Object |
| data[].resources[].face.type | SELFIE ou ID, conforme a classificação descrita acima | String |
| data[].resources[].face.confidence | Confiança com que o detector localizou a face | Number |
| data[].resources[].face.age | Idade aparente estimada | Number |
| data[].resources[].face.gender | Objeto com value (Male ou Female) e confidence | Object |
| data[].resources[].face.boundingBox | Posição da face na imagem, em proporções entre 0 e 1 | Object |
| data[].resources[].face.croppedBase64 | Recorte da face em base64 | String |
| metadata | Objeto com os metadados da requisição | Object |
| metadata.filesInfo | Lista com uma entrada por arquivo enviado, mesmo os em que nenhuma face foi encontrada | Object[] |
| metadata.filesInfo[].fieldname | Nome do campo usado no envio | String |
| metadata.filesInfo[].name | Nome do arquivo enviado | String |
| metadata.filesInfo[].size | Tamanho do arquivo, em bytes | Number |
| metadata.filesInfo[].pages | Número de páginas do arquivo. Para imagens, 1. | Number |
| metadata.filesInfo[].mimetype | Tipo do arquivo enviado | String |
| metadata.filesInfo[].encoding | Codificação do arquivo no envio | String |
| metadata.filesInfo[].sha256 | Hash SHA-256 do arquivo enviado | String |
| metadata.filesInfo[].data | Faces encontradas naquele arquivo, cada uma com page e face (boundingBox e croppedBase64). Vem vazia quando returnsFaceInfo é enviado. | Object[] |
| metadata.timeSpent | Tempo de processamento da requisição, em milissegundos | Number |
🚧 matched e datavalid são respostas a perguntas diferentes
matched diz se as duas imagens que você enviou são da mesma pessoa. datavalid.face diz se a face escolhida bate com a biometria oficial do CPF.
Os dois podem discordar, e a consulta ao Datavalid é feita mesmo quando matched é false — a etapa não é condicionada ao resultado da comparação. Trate os dois campos como sinais independentes na sua decisão.
‼️ Sem duas faces, não há Datavalid
A análise só acontece quando dois arquivos têm alguma face detectada. Se um deles não tiver, a resposta é 200 com "data": [] — sem matched, sem confidence e sem nenhuma consulta ao Datavalid.
Verifique o tamanho de data antes de ler data[0].
Exemplos JSON
- Faces correspondentes e biometria confirmada no Datavalid
{
"id": "13cfec7c-b238-4820-a4d1-5173e4c1418e",
"version": "v2",
"data": [
{
"matched": true,
"confidence": 97.81,
"datavalid": {
"federalRevenueNumberAvailability": true,
"federalRevenueNumberStatus": true,
"face": {
"availability": true,
"similarity": 0.96,
"probability": "VeryHigh"
}
},
"resources": [
{ "fieldname": "documento", "page": 0 },
{ "fieldname": "selfie", "page": 0 }
]
}
],
"metadata": {
"filesInfo": [
{
"fieldname": "documento",
"name": "cnh.jpg",
"size": 567098,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "41c2ece339abfcf9ba1e7d5a60666162a24ef34ba95adeb41ed1d9721c91c6b0",
"data": [
{
"page": 0,
"face": {
"boundingBox": { "top": 0.22, "left": 0.28, "width": 0.15, "height": 0.16 },
"croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...K5CYII="
}
}
]
},
{
"fieldname": "selfie",
"name": "selfie.jpg",
"size": 890098,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "41c2ece339abfcf9ba1e7d5a60666162a24ef34ba95adeb41ed1d9721c91c6c4",
"data": [
{
"page": 0,
"face": {
"boundingBox": { "top": 0.11, "left": 0.26, "width": 0.42, "height": 0.69 },
"croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...SuQmCC"
}
}
]
}
],
"timeSpent": 7340
}
}- Faces correspondentes, mas o CPF não tem biometria na base oficial
{
"id": "6a1d1e8c-4a7d-4a5e-9f2c-1b0f2a9c7e11",
"version": "v2",
"data": [
{
"matched": true,
"confidence": 95.12,
"datavalid": {
"federalRevenueNumberAvailability": true,
"federalRevenueNumberStatus": true,
"face": {
"availability": false
}
},
"resources": [
{ "fieldname": "documento", "page": 0 },
{ "fieldname": "selfie", "page": 0 }
]
}
],
"metadata": {
"filesInfo": [
{
"fieldname": "documento",
"name": "cnh.jpg",
"size": 567098,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "41c2ece339abfcf9ba1e7d5a60666162a24ef34ba95adeb41ed1d9721c91c6b0",
"data": [
{
"page": 0,
"face": {
"boundingBox": { "top": 0.22, "left": 0.28, "width": 0.15, "height": 0.16 },
"croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...K5CYII="
}
}
]
},
{
"fieldname": "selfie",
"name": "selfie.jpg",
"size": 890098,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "41c2ece339abfcf9ba1e7d5a60666162a24ef34ba95adeb41ed1d9721c91c6c4",
"data": [
{
"page": 0,
"face": {
"boundingBox": { "top": 0.11, "left": 0.26, "width": 0.42, "height": 0.69 },
"croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...SuQmCC"
}
}
]
}
],
"timeSpent": 6980
}
}- Nenhuma face encontrada em um dos arquivos
{
"id": "a7f0c3d2-9e51-4b8a-8f31-2d4c6b9e0a77",
"version": "v2",
"data": [],
"metadata": {
"filesInfo": [
{
"fieldname": "documento",
"name": "cnh.jpg",
"size": 567098,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "41c2ece339abfcf9ba1e7d5a60666162a24ef34ba95adeb41ed1d9721c91c6b0",
"data": [
{
"page": 0,
"face": {
"boundingBox": { "top": 0.22, "left": 0.28, "width": 0.15, "height": 0.16 },
"croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...K5CYII="
}
}
]
},
{
"fieldname": "selfie",
"name": "borrada.jpg",
"size": 152064,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
"data": []
}
],
"timeSpent": 3120
}
}Headers de resposta
| Header | Quando aparece |
|---|---|
Nextid-ReqId | Em todas as respostas. Traz o identificador da requisição, o mesmo do campo id do corpo. |
Erros
| Código | Quando ocorre |
|---|---|
| 401 Unauthorized | Chave de API ou token JWT ausente, inválido, ou sem permissão para este endpoint. |
| 404 Not Found | A versão informada na URL não existe. Só a v2 é aceita. |
| 406 Not Acceptable | O corpo foi enviado como JSON, mas sem o campo base64. |
| 413 Payload Too Large | Um dos arquivos enviados em multipart/form-data passa de 15 MB. |
| 415 Unsupported Media Type | O header Content-Type está ausente ou não é suportado. |
| 422 Unprocessable Entity | CPF que não passa na validação do dígito verificador, faceToDatavalid fora do enum, formato de arquivo não aceito, ou mais de dois arquivos. Também é o código devolvido quando o Datavalid recusa a face por baixa qualidade da imagem. |
| 500 Internal Server Error | Falha inesperada durante o processamento, incluindo indisponibilidade do Datavalid. |
Exemplo de resposta com CPF inválido:
Status Code: 422{
"id": "13cfec7c-b238-4820-a4d1-5173e4c1418e",
"error": {
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "Invalid Federal Revenue Number"
}
}Exemplo de resposta quando o Datavalid recusa a face por qualidade:
Status Code: 422{
"id": "6a1d1e8c-4a7d-4a5e-9f2c-1b0f2a9c7e11",
"error": {
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "The face is of poor quality to be processed in the datavalid"
}
}TIP
Uma face recusada por qualidade derruba a requisição inteira com 422 — você não recebe o resultado do face match junto. Se precisa do face match mesmo quando o Datavalid não consegue avaliar a imagem, faça as duas chamadas separadamente, pelo Face Match.
O formato das respostas de erro está descrito em Códigos HTTP das respostas.
Versões
Este endpoint tem uma única versão, a v2. Ela é o padrão quando a versão é omitida na URL.
| Versão | Situação | O que muda |
|---|---|---|
| v2 | Recomendada | Única versão. Atende tanto /face-match-and-datavalid/natural-person/{CPF} quanto /face-match-and-datavalid/v2/natural-person/{CPF}. |
Qualquer outro valor na URL — /face-match-and-datavalid/v3/natural-person/{CPF}, por exemplo — devolve 404.