Skip to content

Face Match + Datavalid

This endpoint does two things in one call:

  1. Face Match — takes two images, locates one face in each, and compares the two with each other, exactly like Face Match.
  2. Datavalid — sends one of those faces to Datavalid, the validation service run by SERPRO (the Brazilian federal data processing agency), and asks whether it matches the official biometrics on record for the CPF (the Brazilian individual taxpayer number) given in the URL.

The difference from plain Face Match is the second step: here the face is checked not only against the other image you sent, but also against the government's official database. That is what makes it possible to answer "this person really is the holder of this CPF", and not just "these two photos are of the same person".

This endpoint does not perform liveness (use Liveness) and does not extract the data written on the document (that is what OCR is for).

Request

POST /face-match-and-datavalid/v2/natural-person/{CPF}

Headers

http
Authorization: ApiKey <your-api-key>

This endpoint also accepts the JWT token, in the format Authorization: Bearer <accessToken>. See JWT Token.

SERPRO keys

The Datavalid query made by this endpoint uses our SERPRO access. You do not need a contract of your own with SERPRO to use it, and it does not read customer keys from the request: the x-customer-key and x-customer-secret headers, if sent here, are ignored.

TIP

Sending your own SERPRO keys is supported on the /full-ocr-and-datavalid endpoint, not on this one. If your contract provides for using your own keys, talk to our support team before building the integration here.

Parameters

ParameterDescriptionRequired
CPFThe CPF whose biometrics will be queried in Datavalid. Goes in the URL path, with or without formatting. It is validated by its check digits.Yes
faceToDatavalidWhich face to send to Datavalid: IdCard or Selfie. Query string. Default: IdCard.No
returnsFaceInfoWhen present, each item of resources also carries the face object, and metadata.filesInfo[].data comes back empty. Query string. Default: off.No

🚧 faceToDatavalid still applies, and it is a preference, not a guarantee

The API classifies each face found into two types, by how much of the image it takes up: large faces become SELFIE, small faces — typical of a photo printed on a document — become ID.

  • faceToDatavalid=IdCard (the default): sends the first face of type ID to Datavalid. If there is none, it sends the face of type SELFIE.
  • faceToDatavalid=Selfie: sends the first face of type SELFIE. If there is none, it sends the face of type ID.

In other words, the Datavalid query happens either way, with whichever face is available. A value outside IdCard and Selfie makes the request fail with 422.

‼️ returnsFaceInfo=false turns the parameter ON

Unlike Face Match, here the value of returnsFaceInfo is not interpreted: the mere presence of the parameter in the query string already activates it, returnsFaceInfo=false included. To leave it off, do not send the parameter at all.

Accepted files

ItemValue
Formatsimage/png, image/jpeg, application/pdf
Files per call2 files
Maximum size (multipart)15 MB per file

The form field names are up to you — they come back in the response, in resources and in metadata.filesInfo. Sending more than two files is rejected with 422.

In multi-page PDFs, each page is analyzed in order and the first one with any face detected is the one that goes into the analysis.

Besides multipart/form-data, the files can be sent as JSON, in the base64 field, as described in Sending files.

Example request

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

Choosing the selfie as the face to validate in Datavalid:

bash
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 YOUR_API_KEY' \
  --form 'documento=@./cnh.jpg' \
  --form 'selfie=@./selfie.jpg'

Response

FieldDescriptionType
idUnique identifier of the requestString
versionAPI version that served the callString
dataList with the result of the analysis. Carries one entry when the comparison happened, and comes back empty when it did not.Object[]
data[].matchedtrue when the two faces sent belong to the same person. This is the result of the face match, not of Datavalid.Boolean
data[].confidenceConfidence level of the comparison between the two faces, from 0 to 100Number
data[].datavalidResult of the Datavalid query. Comes back as {} when there was no query.Object
data[].datavalid.federalRevenueNumberAvailabilityIndicates whether the CPF given exists in the official databaseBoolean
data[].datavalid.federalRevenueNumberStatusIndicates whether the CPF's registration status in the official database is regularBoolean
data[].datavalid.faceResult of comparing the face sent with the official biometrics. Comes back as {} when there are no biometrics to compare.Object
data[].datavalid.face.availabilityIndicates whether facial biometrics are on record for that CPF in the official databaseBoolean
data[].datavalid.face.similaritySimilarity between the face sent and the official biometrics, on a scale from 0 to 1Number
data[].datavalid.face.probabilityProbability band of the face sent being the same as the one in the official database: VeryHigh, High, Low or VeryLowString
data[].resourcesThe two faces used in the comparison, in the order in which they were checkedObject[]
data[].resources[].fieldnameName of the field that file was sent inString
data[].resources[].pagePage of the file where the face was found. Starts at 0; for images it is always 0.Number
data[].resources[].faceData of the face. Only appears when returnsFaceInfo is sent.Object
data[].resources[].face.typeSELFIE or ID, following the classification described aboveString
data[].resources[].face.confidenceConfidence with which the detector located the faceNumber
data[].resources[].face.ageEstimated apparent ageNumber
data[].resources[].face.genderObject with value (Male or Female) and confidenceObject
data[].resources[].face.boundingBoxPosition of the face in the image, in proportions between 0 and 1Object
data[].resources[].face.croppedBase64Crop of the face in base64String
metadataObject with the metadata of the requestObject
metadata.filesInfoList with one entry per file sent, including those where no face was foundObject[]
metadata.filesInfo[].fieldnameName of the field used to send the fileString
metadata.filesInfo[].nameName of the file sentString
metadata.filesInfo[].sizeSize of the file, in bytesNumber
metadata.filesInfo[].pagesNumber of pages of the file. For images, 1.Number
metadata.filesInfo[].mimetypeType of the file sentString
metadata.filesInfo[].encodingEncoding of the file as sentString
metadata.filesInfo[].sha256SHA-256 hash of the file sentString
metadata.filesInfo[].dataFaces found in that file, each with page and face (boundingBox and croppedBase64). Comes back empty when returnsFaceInfo is sent.Object[]
metadata.timeSpentProcessing time of the request, in millisecondsNumber

🚧 matched and datavalid answer different questions

matched says whether the two images you sent are of the same person. datavalid.face says whether the face chosen matches the official biometrics for the CPF.

The two can disagree, and the Datavalid query is made even when matched is false — that step is not conditional on the result of the comparison. Treat the two fields as independent signals in your decision.

‼️ No two faces, no Datavalid

The analysis only happens when two files have some face detected. If one of them does not, the response is 200 with "data": [] — no matched, no confidence, and no Datavalid query at all.

Check the size of data before reading data[0].

JSON examples

  1. Matching faces and biometrics confirmed in Datavalid
Status Code: 200
json
{
  "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
  }
}
  1. Matching faces, but the CPF has no biometrics in the official database
Status Code: 200
json
{
  "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
  }
}
  1. No face found in one of the files
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
  }
}

Response headers

HeaderWhen it appears
Nextid-ReqIdOn every response. Carries the request identifier, the same one as the id field in the body.

Errors

CodeWhen it happens
401 UnauthorizedAPI key or JWT token missing, invalid, or without permission for this endpoint.
404 Not FoundThe version given in the URL does not exist. Only v2 is accepted.
406 Not AcceptableThe body was sent as JSON, but without the base64 field.
413 Payload Too LargeOne of the files sent as multipart/form-data is larger than 15 MB.
415 Unsupported Media TypeThe Content-Type header is missing or is not supported.
422 Unprocessable EntityA CPF that fails check-digit validation, a faceToDatavalid outside the enum, a file format that is not accepted, or more than two files. It is also the code returned when Datavalid rejects the face for poor image quality.
500 Internal Server ErrorUnexpected failure during processing, including Datavalid being unavailable.

Example response with an invalid CPF:

Status Code: 422
json
{
  "id": "13cfec7c-b238-4820-a4d1-5173e4c1418e",
  "error": {
    "statusCode": 422,
    "error": "Unprocessable Entity",
    "message": "Invalid Federal Revenue Number"
  }
}

Example response when Datavalid rejects the face for quality:

Status Code: 422
json
{
  "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

A face rejected for quality brings down the whole request with 422 — you do not get the face match result along with it. If you need the face match even when Datavalid cannot assess the image, make the two calls separately, through Face Match.

The error response format is described in HTTP response codes.

Versions

This endpoint has a single version, v2. It is the default when the version is omitted from the URL.

VersionStatusWhat changes
v2RecommendedThe only version. Serves both /face-match-and-datavalid/natural-person/{CPF} and /face-match-and-datavalid/v2/natural-person/{CPF}.

Any other value in the URL — /face-match-and-datavalid/v3/natural-person/{CPF}, for example — returns 404.

Nextcode | Identity Verification Solutions