Skip to content

Face Match

Este endpoint recebe duas imagens, localiza uma face em cada uma e responde se as duas faces são da mesma pessoa.

O uso mais comum é confrontar uma selfie com a foto impressa em um documento de identificação, mas a comparação não exige isso: qualquer par de imagens com uma face detectável serve — duas selfies, dois documentos, ou um de cada.

🚧 Face Match não é Face

  • Face Match (esta página) — recebe duas imagens e responde se são a mesma pessoa.
  • Face — recebe uma imagem e apenas descreve as faces que existem nela, sem comparar nada.

Este endpoint não faz liveness — ele não distingue uma pessoa presente na captura de uma foto de foto. Para isso, use o Liveness. E ele não consulta bases oficiais: se você precisa confrontar a face com a biometria do governo para um CPF, use o Face Match + Datavalid.

TIP

Se a selfie vem de uma sessão de liveness feita com os nossos SDKs, prefira o Face Match for Liveness: ele reaproveita a selfie já capturada, e você envia apenas o documento.

Request

POST /face-match/v2

Headers

http
Authorization: ApiKey <sua-chave-de-api>

Este endpoint também aceita o token JWT, no formato Authorization: Bearer <accessToken>. Veja Token JWT.

Parâmetros

Parâmetro de query string, opcional.

ParâmetroDescriçãoObrigatório
returnsFaceInfoQuando true, cada item de resources passa a trazer o objeto face com os dados da face usada na comparação, e metadata.filesInfo[].data vem vazio. Padrão: false.Não

Um parâmetro de query desconhecido, ou com valor de tipo inválido, faz a requisição falhar com 422.

Arquivos aceitos

ItemValor
Formatosimage/png, image/jpeg, application/pdf
Quantidade por chamada2 arquivos
Tamanho máximo (multipart)15 MB por arquivo

Os nomes dos campos do formulário são livres — eles voltam na resposta, dentro de resources e de metadata.filesInfo, e é por eles que você identifica qual imagem é qual. Enviar mais de dois arquivos é recusado com 422.

Quando o arquivo é um PDF de várias páginas, cada página é analisada em ordem e a primeira página com alguma face detectada é a que entra na comparação; as demais são descartadas.

Além do multipart/form-data, os arquivos podem ser enviados em JSON, no campo base64, como descrito em Envio de arquivos.

Exemplo Request

bash
curl -i -X POST 'https://api-homolog.nxcd.app/face-match/v2' \
  --header 'Authorization: ApiKey SUA_CHAVE_AQUI' \
  --form 'documento=@./cnh.jpg' \
  --form 'selfie=@./selfie.jpg'

Response

Os campos abaixo descrevem a resposta da v2, a versão suportada deste endpoint.

CampoDescriçãoTipo
idIdentificador único da requisiçãoString
versionVersão da API que atendeu a chamadaString
dataLista com o resultado da comparação. Traz uma entrada quando a comparação aconteceu, e vem vazia quando não.Object[]
data[].matchedtrue quando as duas faces comparadas são da mesma pessoaBoolean
data[].confidenceGrau de confiança da comparação, de 0 a 100Number
data[].resourcesAs duas faces usadas na comparação, na ordem em que foram confrontadasObject[]
data[].resources[].fieldnameNome do campo em que aquele arquivo foi enviadoString
data[].resources[].pagePágina do arquivo em que a face foi encontrada. Começa em 0; para imagens é sempre 0.Number
data[].resources[].faceDados da face usada na comparação. Só aparece com returnsFaceInfo=true.Object
data[].resources[].face.typeSELFIE quando a face ocupa boa parte da imagem, ID quando é uma face pequena, típica de foto de documentoString
data[].resources[].face.confidenceConfiança com que o detector localizou a faceNumber
data[].resources[].face.ageIdade aparente estimadaNumber
data[].resources[].face.genderObjeto com value (Male ou Female) e confidenceObject
data[].resources[].face.boundingBoxPosição da face na imagem, em proporções entre 0 e 1 (top, left, width, height)Object
data[].resources[].face.croppedBase64Recorte da face em base64String
metadataObjeto com os metadados da requisiçãoObject
metadata.filesInfoLista com uma entrada por arquivo enviado, mesmo os em que nenhuma face foi encontradaObject[]
metadata.filesInfo[].fieldnameNome do campo usado no envioString
metadata.filesInfo[].nameNome do arquivo enviadoString
metadata.filesInfo[].sizeTamanho do arquivo, em bytesNumber
metadata.filesInfo[].pagesNúmero de páginas do arquivo. Para imagens, 1.Number
metadata.filesInfo[].mimetypeTipo do arquivo enviadoString
metadata.filesInfo[].encodingCodificação do arquivo no envioString
metadata.filesInfo[].sha256Hash SHA-256 do arquivo enviadoString
metadata.filesInfo[].dataFaces encontradas naquele arquivo. Vem vazia quando returnsFaceInfo=true.Object[]
metadata.filesInfo[].data[].pagePágina em que a face foi encontrada, começando em 0Number
metadata.filesInfo[].data[].faceObjeto com boundingBox e croppedBase64 da faceObject
metadata.timeSpentTempo de processamento da requisição, em milissegundosNumber

🚧 data vazio não é erro

A comparação só acontece quando dois arquivos têm alguma face detectada. Um arquivo sem face, um único arquivo enviado, ou nenhum arquivo: a resposta é 200 com "data": [], e metadata.filesInfo continua listando tudo o que foi enviado.

Isso significa que data[0] pode não existir. Verifique o tamanho de data antes de ler matched — um código que assume data[0].matched recebe um erro em vez de um resultado negativo.

Exemplos JSON

  1. Faces correspondentes
Status Code: 200
json
{
  "id": "13cfec7c-b238-4820-a4d1-5173e4c1418e",
  "version": "v2",
  "data": [
    {
      "matched": true,
      "confidence": 97.81,
      "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.2237228155136108,
                "left": 0.2856607735157013,
                "width": 0.1555942893028259,
                "height": 0.1687679588794708
              },
              "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.1142489537596702,
                "left": 0.2693724930286407,
                "width": 0.4232554733753204,
                "height": 0.6968063116073608
              },
              "croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...SuQmCC"
            }
          }
        ]
      }
    ],
    "timeSpent": 4820
  }
}
  1. Faces de pessoas diferentes
Status Code: 200
json
{
  "id": "6a1d1e8c-4a7d-4a5e-9f2c-1b0f2a9c7e11",
  "version": "v2",
  "data": [
    {
      "matched": false,
      "confidence": 12.4,
      "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": 4610
  }
}
  1. Nenhuma face encontrada em um dos arquivos
Status Code: 200
json
{
  "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
  }
}
  1. Com returnsFaceInfo=true
Status Code: 200
json
{
  "id": "b91e5f44-1c02-4a77-9d3e-58a0f2c4e6bb",
  "version": "v2",
  "data": [
    {
      "matched": true,
      "confidence": 96.32,
      "resources": [
        {
          "fieldname": "documento",
          "page": 0,
          "face": {
            "confidence": 0.98,
            "type": "ID",
            "age": 34,
            "gender": { "value": "Male", "confidence": 99.72 },
            "boundingBox": { "top": 0.22, "left": 0.28, "width": 0.15, "height": 0.16 },
            "croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...K5CYII="
          }
        },
        {
          "fieldname": "selfie",
          "page": 0,
          "face": {
            "confidence": 0.99,
            "type": "SELFIE",
            "age": 33,
            "gender": { "value": "Male", "confidence": 99.15 },
            "boundingBox": { "top": 0.11, "left": 0.26, "width": 0.42, "height": 0.69 },
            "croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...SuQmCC"
          }
        }
      ]
    }
  ],
  "metadata": {
    "filesInfo": [
      {
        "fieldname": "documento",
        "name": "cnh.jpg",
        "size": 567098,
        "pages": 1,
        "mimetype": "image/jpeg",
        "encoding": "7bit",
        "sha256": "41c2ece339abfcf9ba1e7d5a60666162a24ef34ba95adeb41ed1d9721c91c6b0",
        "data": []
      },
      {
        "fieldname": "selfie",
        "name": "selfie.jpg",
        "size": 890098,
        "pages": 1,
        "mimetype": "image/jpeg",
        "encoding": "7bit",
        "sha256": "41c2ece339abfcf9ba1e7d5a60666162a24ef34ba95adeb41ed1d9721c91c6c4",
        "data": []
      }
    ],
    "timeSpent": 4930
  }
}

Headers de resposta

HeaderQuando aparece
Nextid-ReqIdEm todas as respostas. Traz o identificador da requisição, o mesmo do campo id do corpo.

Erros

CódigoQuando ocorre
401 UnauthorizedChave de API ou token JWT ausente, inválido, ou sem permissão para este endpoint.
404 Not FoundA versão informada na URL não existe.
406 Not AcceptableO corpo foi enviado como JSON, mas sem o campo base64.
413 Payload Too LargeUm dos arquivos enviados em multipart/form-data passa de 15 MB.
415 Unsupported Media TypeO header Content-Type está ausente ou não é suportado.
422 Unprocessable EntityParâmetro de query desconhecido ou com valor inválido, formato de arquivo não aceito, ou mais de dois arquivos.
500 Internal Server ErrorFalha inesperada durante o processamento.

O formato das respostas de erro está descrito em Códigos HTTP das respostas.

Versões

VersãoSituaçãoO que muda
v2Recomendadadata é uma lista com uma comparação, que traz confidence.

A v2 é a versão suportada deste endpoint. Ela atende tanto /face-match/v2 quanto /face-match sem versão na URL.

Nextcode | Soluções em Verificação de Identidade