Full OCR
This endpoint takes images or PDFs of identity documents and returns, for each document found, three things:
- Classification — which document it is (driver's license (CNH), Brazilian ID card (RG), CRNM, CRLV…), from which country, and which side was seen.
- Extraction — the fields written on the document, read by OCR.
- Cross-check — when the document carries a CPF (the Brazilian individual taxpayer number), the data read is checked against the Brazilian Federal Revenue Service database, and the response says field by field whether it matched.
That is the difference from the Classifier, which only answers which document is this and reads nothing inside it.
This endpoint does not perform liveness (use Liveness), does not compare the face on the document with a selfie (use Face Match) and does not query the government's biometric database. To add validation in Datavalid, run by SERPRO (the Brazilian federal data processing agency), use Full OCR + Datavalid.
Proof of residence has an endpoint of its own
Full OCR recognizes proofs of residence and extracts the address from them, but the dedicated analysis is better. For proofs of residence, use Proof of residence.
Request
POST/full-ocr/v4Headers
Authorization: ApiKey <your-api-key>This endpoint also accepts the JWT token, in the format Authorization: Bearer <accessToken>. See JWT Token.
Parameters
All optional, in the query string.
| Parameter | Description | Required |
|---|---|---|
| federalRevenueNumber | A CPF you already know for the person, to guide the search at the Federal Revenue Service. Accepts formatting. Can be repeated to send more than one CPF. | No |
| returnsFaceInfo | When true, the response carries the face object for each document. Default: false. Only has an effect on v4 — on v2 and v3 the face always comes. | No |
| returnsCroppedDocumentBase64 | When true, each document carries the crop of the image in documentBase64. Default: false. | No |
| returnsMultiCroppedDocuments | When true, documentBase64 becomes a list of crops instead of a single value. Depends on returnsCroppedDocumentBase64. Default: false. | No |
| returnsCroppedDocumentsInfo | When true, each crop becomes an object { side, b64 } instead of a string. Depends on returnsCroppedDocumentBase64. Default: false. | No |
| forceLiveTaxData | When true, asks for the query to the Federal Revenue Service to be made live. Default: false. | No |
| documentscopy | When true, runs the document forensics analysis on CNH and RG. Default: false. Only has an effect on v4. See Document forensics. | No |
| groupAnalysisByField | Groups the document forensics result by field. Only makes sense together with documentscopy=true. Default: false. | No |
| analyzeForgery | Adds the tampering analysis to the document forensics result. Only makes sense together with documentscopy=true. Default: false. | No |
🚧 The boolean parameters are only turned on by the string true
Any other value — 1, TRUE, yes, or the parameter with no value — is read as false. And, unlike other endpoints, an unknown query parameter does not raise an error here: it is simply ignored. A returnFaceInfo written without the s does not return 422; it returns 200 without the face.
🚧 federalRevenueNumber is validated by its check digits
A CPF that fails validation brings the whole request down with 422, before any processing. This applies to every value when you send more than one.
Accepted files
| Item | Value |
|---|---|
| Formats | image/png, image/jpeg, application/pdf |
| Files per call | up to 7 files |
| Maximum size (multipart) | 15 MB per file |
The form field names are up to you — they come back in the response, in metadata.filesInfo. Sending more than seven files is rejected with 422.
Each page of a multi-page PDF is analyzed separately. From v3 on, the front and back of the same document found on different pages or in different files are merged into a single data entry.
Besides multipart/form-data, the files can be sent as JSON, in the base64 field, as described in Sending files.
Example request
curl -i -X POST 'https://api-homolog.nxcd.app/full-ocr/v4' \
--header 'Authorization: ApiKey YOUR_API_KEY' \
--form 'frente=@./cnh-frente.jpg' \
--form 'verso=@./cnh-verso.jpg'Stating the expected CPF, to guide the query to the Federal Revenue Service:
curl -i -X POST 'https://api-homolog.nxcd.app/full-ocr/v4?federalRevenueNumber=123.456.789-09' \
--header 'Authorization: ApiKey YOUR_API_KEY' \
--form 'documento=@./cnh.pdf'Response
This section describes v4, the recommended version. v2 and v3 return a data in a different format — see Versions.
The envelope is the API standard:
| Field | Description | Type |
|---|---|---|
| id | Unique identifier of the request | String |
| version | API version that served the call | String |
| data | List with one entry per document recognized. Comes back empty when no document was recognized. | Object[] |
| metadata | Metadata of the request | Object |
The list comes ordered from the best to the worst result
data is ordered internally: documents with Federal Revenue Service data come first, then those with more fields matching, then those with more fields extracted. If you expect a single document, read data[0] — but check first that the list is not empty.
Each item of data is assembled from the blocks below. Not all of them always appear: the conditions are given in each section.
| Block | What it is |
|---|---|
classification | Which document it is, from which country, which side |
extraction and enhanced | What was read from the document, raw and cleaned up |
taxData and matches | What the Federal Revenue Service returned and what matched |
postOfficeData | Address checked against the Correios (proofs of residence only) |
face | The face found on the document |
documentBase64 | Crop of the document image |
metadata | Files sent and processing time. Lives at the root, outside data[]. |
data[].classification
What the AI recognized in the file, before reading any field.
| Field | Description | Type |
|---|---|---|
| classification.type | Type of the document: DriversLicense, FederalID, Passport, Transportation, ProofOfResidence… | String |
| classification.subtype | Model within the type: Printed, Digital, Decree2018Paper, CRLV-Printed… | String |
| classification.country | Issuing country, in three letters: BRA, UNI, USA… | String |
| classification.side | Consolidated side of the document: Front, Back or FrontAndBack | String |
| classification.sameImage | true when front and back came from the same page of the same file | Boolean |
🚧 On v4 the side vocabulary changes and sides disappears
On v3, classification.sides is a list with one entry per page classified, and the side of each one uses OnlyFront / OnlyBack / FrontAndBack.
On v4, the list is gone from classification: what is left is a single, already consolidated side, in the Front / Back / FrontAndBack vocabulary. The per-page detail moves to metadata.filesInfo[].details — that is where the confidence and the page of each side recognized now live.
{
"classification": {
"type": "DriversLicense",
"subtype": "Printed",
"country": "BRA",
"side": "FrontAndBack",
"sameImage": false
}
}data[].extraction and data[].enhanced
These are the fields read from the document, in two versions of the same data:
extraction— the text as it came out of the OCR, untreated. It is what was written on the paper, reading noise included.enhanced— the same data normalized and corrected. This is the version that goes through the cross-check against the Federal Revenue Service: when the name matches, the CPF confirmed by the Federal Revenue Service is written here, and fields with OCR leftovers are cleaned up.
To fill in a form and to persist data, use enhanced. Use extraction when you need to know what was literally printed.
The two have the same structure, with the field-level differences marked in the table:
| Field | Description | Type |
|---|---|---|
| schemaName | Identifier of the set of fields used in this extraction. Depends on the type and the model of the document. | String |
| person | The person's data | Object |
| person.taxId | CPF | String |
| person.name | Name | String |
| person.birthdate | Date of birth | String |
| person.parentage | Parents' names on a single line. Exists only in extraction. | String |
| person.mothersName | Mother's name. Exists only in enhanced, already split out of the parentage line. | String |
| person.fathersName | Father's name. Exists only in enhanced. | String |
| otherFields | The remaining fields of the document. The set of keys varies with the type and the model. | Object |
An empty field is "", not absent
The keys of person and of otherFields are fixed for each document model: they always appear, and whatever was not read comes back as an empty string. You do not need to test whether the key exists — you need to test whether it is empty.
The set of otherFields keys is not the same in extraction and in enhanced — normalization splits some fields in two.
On a CNH, extraction carries driversLicenseCategory, expireAt, firstIssuedAt, formNumberFront, formNumberBack, issuedAt, locale, mopedsLicense, nacionality, naturalness, notes, permission, registerNumber, renach, securityNumber, sourceDocument, sourceDocumentIssuer and state. In enhanced, locale becomes localeCity and localeState, naturalness becomes naturalnessCity and naturalnessState, and the two formNumber* fields become a single formNumber; the rest is the same.
On a standard-model RG, extraction carries documentId, header, issuedAt, naturalness, origin and version. enhanced carries documentId, headerState, issuedAt, naturalnessCity, naturalnessState, originCity, originState, version, illiterate and ageTag.
{
"extraction": {
"schemaName": "driversLicense",
"person": {
"taxId": "123.456.789-09",
"name": "JOAO DA SILVA SANTOS",
"birthdate": "01/02/1990",
"parentage": "ANTONIO SANTOS MARIA DA SILVA SANTOS"
},
"otherFields": {
"driversLicenseCategory": "AB",
"expireAt": "10/03/2029",
"firstIssuedAt": "15/04/2010",
"formNumberFront": "00123456789",
"formNumberBack": "00123456789",
"issuedAt": "10/03/2019",
"locale": "SAO PAULO",
"naturalness": "SAO PAULO SP",
"registerNumber": "01234567890",
"renach": "SP012345678",
"securityNumber": "12345678901",
"sourceDocument": "12.345.678-9",
"sourceDocumentIssuer": "SSP SP",
"state": "SP",
"mopedsLicense": "",
"nacionality": "BRASILEIRA",
"notes": "",
"permission": ""
}
},
"enhanced": {
"schemaName": "driversLicense",
"person": {
"taxId": "12345678909",
"name": "JOAO DA SILVA SANTOS",
"birthdate": "1990-02-01",
"mothersName": "MARIA DA SILVA SANTOS",
"fathersName": "ANTONIO SANTOS"
},
"otherFields": {
"driversLicenseCategory": "AB",
"expireAt": "10/03/2029",
"firstIssuedAt": "15/04/2010",
"formNumber": "00123456789",
"issuedAt": "2019-03-10",
"localeCity": "SAO PAULO",
"localeState": "SP",
"mopedsLicense": "",
"nacionality": "BRASILEIRA",
"notes": "",
"permission": "",
"registerNumber": "01234567890",
"renach": "SP012345678",
"securityNumber": "12345678901",
"sourceDocument": "12.345.678-9",
"sourceDocumentIssuer": "SSP SP",
"state": "SP",
"naturalnessCity": "SAO PAULO",
"naturalnessState": "SP"
}
}
}data[].taxData and data[].matches
This is where the external cross-check lives. taxData is what the Federal Revenue Service returned for the CPF; matches says, field by field, whether what was on the document matches what the Federal Revenue Service has.
| Field | Description | Type |
|---|---|---|
| taxData.taxId | CPF found at the Federal Revenue Service | String |
| taxData.name | Name on record at the Federal Revenue Service | String |
| taxData.mothersName | Mother's name on record at the Federal Revenue Service | String |
| taxData.birthdate | Date of birth on record at the Federal Revenue Service | String |
| matches.name | true when the name read from the document matches the Federal Revenue Service's | Boolean |
| matches.mothersName | true when the mother's name matches | Boolean |
| matches.birthdate | true when the date of birth matches | Boolean |
🚧 When the two blocks do not appear
taxData and matches are removed from the response for documents that have nothing to cross-check against the Federal Revenue Service — CRLV and ANTT, for example, and the Chilean identity card.
Beyond that, the query to the Federal Revenue Service depends on the side you sent, because the CPF is not printed on both sides of every document:
- CNH — the query happens with front and back, or with the front alone. Sending only the back, it does not happen. And, for a driver's license, the query is only made when the country is
BRA. - RG — the query happens with front and back; with the back alone, only on the standard models; with the front alone, only on the 2022 CIN.
When the query does not happen, the two blocks remain in the response, but with empty fields and every matches set to false. If you need the cross-check, send the whole document.
matches.name: false does not always mean "a different name"
A name read with fewer than 8 characters — typical of an OCR that failed — is treated as unchecked: matches.name comes back false without the comparison ever being made. And, when the name does not match, the cross-check stops there: the remaining fields are not used to correct enhanced.
{
"taxData": {
"taxId": "12345678909",
"name": "JOAO DA SILVA SANTOS",
"mothersName": "MARIA DA SILVA SANTOS",
"birthdate": "1990-02-01"
},
"matches": {
"name": true,
"mothersName": true,
"birthdate": true
}
}data[].postOfficeData
Only appears when the document recognized is a proof of residence. It carries the address the Brazilian Postal Service (Correios) returned for the ZIP code read, and the result of comparing it with what was written on the proof.
| Field | Description | Type |
|---|---|---|
| postOfficeData.zipCode | ZIP code according to the Correios | String |
| postOfficeData.address | Street address according to the Correios | String |
| postOfficeData.district | District according to the Correios | String |
| postOfficeData.city | City according to the Correios | String |
| postOfficeData.state | State according to the Correios | String |
| postOfficeData.matches | Object with booleans for zipCode, address, district, city and state | Object |
To analyze proofs of residence, prefer the dedicated endpoint, which documents this block in detail.
data[].face
The face found on the document. On v4 it only appears when you send returnsFaceInfo=true, and it is gone when no face was detected.
| Field | Description | Type |
|---|---|---|
| face.age | Estimated apparent age | Number |
| face.gender.value | Male or Female | String |
| face.boundingBox | Position of the face in the image, in proportions between 0 and 1 (top, left, width, height) | Object |
| face.croppedBase64 | Crop of the face in base64 | String |
{
"face": {
"age": 34,
"gender": { "value": "Male" },
"boundingBox": {
"top": 0.2237228155136108,
"left": 0.2856607735157013,
"width": 0.1555942893028259,
"height": 0.1687679588794708
},
"croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...K5CYII="
}
}data[].documentBase64
The crop of the document image, isolated from the rest of the photo. It only appears with returnsCroppedDocumentBase64=true, and its format depends on the other two parameters:
| Parameters | Format of documentBase64 |
|---|---|
returnsCroppedDocumentBase64=true | String with the base64 |
+ returnsCroppedDocumentsInfo=true | Object with side and b64 |
+ returnsMultiCroppedDocuments=true | Array of the formats above |
Document forensics
With documentscopy=true on v4, documents of type CNH and RG gain a data[].documentscopy block with the result of the automatic forensic examination of the fields. groupAnalysisByField=true reorganizes that block by field, and analyzeForgery=true adds a forgeryAnalysis to it with the tampering analysis.
The contents of the block vary with the model of the document and are not described here. If document forensics is your main use case, the dedicated product is Automated Document Forensics.
metadata
| Field | Description | Type |
|---|---|---|
| metadata.filesInfo | List with one entry per file sent, including those where nothing was recognized | Object[] |
| metadata.filesInfo[].fieldname | Name of the field used to send the file | String |
| metadata.filesInfo[].name | Name of the file sent | String |
| metadata.filesInfo[].size | Size of the file, in bytes | Number |
| metadata.filesInfo[].pages | Number of pages of the file. For images, 1. | Number |
| metadata.filesInfo[].mimetype | Type of the file sent | String |
| metadata.filesInfo[].encoding | Encoding of the file as sent | String |
| metadata.filesInfo[].sha256 | SHA-256 hash of the file sent | String |
| metadata.filesInfo[].details | v4 only. One entry per side recognized in that file. | Object[] |
| metadata.filesInfo[].details[].side | Side recognized: Front, Back or FrontAndBack | String |
| metadata.filesInfo[].details[].page | Page where it was recognized. Starts at 0. | Number |
| metadata.filesInfo[].details[].confidence | Confidence of the classification of that side | Number |
| metadata.timeSpent | Processing time of the request, in milliseconds | Number |
Full example
Status Code: 200A driver's license sent in two files, front and back, with the CPF confirmed by the Federal Revenue Service:
{
"id": "13cfec7c-b238-4820-a4d1-5173e4c1418e",
"version": "v4",
"data": [
{
"extraction": {
"schemaName": "driversLicense",
"person": {
"taxId": "123.456.789-09",
"name": "JOAO DA SILVA SANTOS",
"birthdate": "01/02/1990",
"parentage": "ANTONIO SANTOS MARIA DA SILVA SANTOS"
},
"otherFields": {
"driversLicenseCategory": "AB",
"expireAt": "10/03/2029",
"firstIssuedAt": "15/04/2010",
"formNumber": "00123456789",
"issuedAt": "10/03/2019",
"locale": "SAO PAULO",
"mopedsLicense": "",
"nacionality": "BRASILEIRA",
"notes": "",
"permission": "",
"registerNumber": "01234567890",
"renach": "SP012345678",
"securityNumber": "12345678901",
"sourceDocument": "12.345.678-9",
"sourceDocumentIssuer": "SSP SP",
"state": "SP"
}
},
"enhanced": {
"schemaName": "driversLicense",
"person": {
"taxId": "12345678909",
"name": "JOAO DA SILVA SANTOS",
"birthdate": "1990-02-01",
"mothersName": "MARIA DA SILVA SANTOS",
"fathersName": "ANTONIO SANTOS"
},
"otherFields": {
"driversLicenseCategory": "AB",
"expireAt": "10/03/2029",
"firstIssuedAt": "15/04/2010",
"formNumber": "00123456789",
"issuedAt": "2019-03-10",
"localeCity": "SAO PAULO",
"localeState": "SP",
"mopedsLicense": "",
"nacionality": "BRASILEIRA",
"notes": "",
"permission": "",
"registerNumber": "01234567890",
"renach": "SP012345678",
"securityNumber": "12345678901",
"sourceDocument": "12.345.678-9",
"sourceDocumentIssuer": "SSP SP",
"state": "SP",
"naturalnessCity": "SAO PAULO",
"naturalnessState": "SP"
}
},
"taxData": {
"taxId": "12345678909",
"name": "JOAO DA SILVA SANTOS",
"mothersName": "MARIA DA SILVA SANTOS",
"birthdate": "1990-02-01"
},
"matches": {
"name": true,
"mothersName": true,
"birthdate": true
},
"classification": {
"type": "DriversLicense",
"subtype": "Printed",
"country": "BRA",
"side": "FrontAndBack",
"sameImage": false
}
}
],
"metadata": {
"filesInfo": [
{
"fieldname": "frente",
"name": "cnh-frente.jpg",
"size": 567098,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "41c2ece339abfcf9ba1e7d5a60666162a24ef34ba95adeb41ed1d9721c91c6b0",
"details": [
{ "side": "Front", "confidence": 0.99, "page": 0 }
]
},
{
"fieldname": "verso",
"name": "cnh-verso.jpg",
"size": 512044,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
"details": [
{ "side": "Back", "confidence": 0.97, "page": 0 }
]
}
],
"timeSpent": 9840
}
}No document recognized
Status Code: 200A file with no recognizable document is not an error: the response is 200, data comes back empty, and metadata.filesInfo still lists what was sent.
{
"id": "6a1d1e8c-4a7d-4a5e-9f2c-1b0f2a9c7e11",
"version": "v4",
"data": [],
"metadata": {
"filesInfo": [
{
"fieldname": "documento",
"name": "borrada.jpg",
"size": 152064,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"
}
],
"timeSpent": 3120
}
}Response headers
| Header | When it appears |
|---|---|
Nextid-ReqId | On every response. Carries the request identifier, the same one as the id field in the body. |
Errors
| Code | When it happens |
|---|---|
| 401 Unauthorized | API key or JWT token missing, invalid, or without permission for this endpoint. |
| 404 Not Found | The version given in the URL does not exist. Only v2, v3 and v4 are accepted. |
| 406 Not Acceptable | The body was sent as JSON, but without the base64 field. |
| 413 Payload Too Large | One of the files sent as multipart/form-data is larger than 15 MB. |
| 415 Unsupported Media Type | The Content-Type header is missing or is not supported. |
| 422 Unprocessable Entity | A federalRevenueNumber that fails check-digit validation, a file format that is not accepted, or more than seven files. |
| 500 Internal Server Error | Unexpected failure during processing. |
Example response with an invalid CPF:
Status Code: 422{
"id": "13cfec7c-b238-4820-a4d1-5173e4c1418e",
"error": {
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "Invalid Federal Revenue Number"
}
}The error response format is described in HTTP response codes.
Versions
The recommended version is v4, called at /full-ocr/v4. It is the only one that separates extraction from enhanced, that uses the Federal Revenue Service result to correct the extracted data, and where the query parameters take effect.
‼️ Omitting the version hands the call to v2
POST /full-ocr, with no version in the path, is served by v2 — not by v4. v2 has a different response format and ignores every query parameter described in the Request section. Always state the version in the URL.
| Version | Status | What changes |
|---|---|---|
| v4 | Recommended | extraction and enhanced separated, taxData/matches at the root of the item, consolidated classification.side, details inside filesInfo. The only one where the query parameters apply. |
| v3 | Available | A single extraction object, with no enhanced. The Federal Revenue Service cross-check lives in federalRevenueData. classification.sides as a list. |
| v2 | Legacy | Does not merge front and back: each side becomes a data entry of its own. classification uses the old names (CNH, RG). This is what answers when the version is omitted from the URL. |
What changes in v3
data[] stops having extraction/enhanced separated and instead has:
| Field | Description | Type |
|---|---|---|
| extraction | A flat object with the fields read from the document, with no split between raw and cleaned | Object |
| federalRevenueData | The Federal Revenue Service cross-check, now nested | Object |
| federalRevenueData.name | Name at the Federal Revenue Service | String |
| federalRevenueData.federalRevenueNumber | CPF at the Federal Revenue Service | String |
| federalRevenueData.mothersName | Mother's name at the Federal Revenue Service | String |
| federalRevenueData.birthdate | Date of birth at the Federal Revenue Service | String |
| federalRevenueData.matches | Object with name, federalRevenueNumber, mothersName and birthdate, each carrying matched | Object |
| classification.type | Type of the document | String |
| classification.subtype | Model of the document | String |
| classification.country | Issuing country | String |
| classification.sides | List with the side, page, fieldname and confidence of each side recognized | Object[] |
| postOfficeData | Same format as v4 | Object |
| face | Same format as v4, but always present — returnsFaceInfo has no effect here | Object |
{
"id": "13cfec7c-b238-4820-a4d1-5173e4c1418e",
"version": "v3",
"data": [
{
"extraction": {
"name": "JOAO DA SILVA SANTOS",
"federalRevenueNumber": "12345678909",
"mothersName": "MARIA DA SILVA SANTOS",
"birthdate": "01/02/1990",
"registerNumber": "01234567890",
"driversLicenseCategory": "AB",
"expireAt": "10/03/2029"
},
"federalRevenueData": {
"name": "JOAO DA SILVA SANTOS",
"federalRevenueNumber": "12345678909",
"mothersName": "MARIA DA SILVA SANTOS",
"birthdate": "01/02/1990",
"matches": {
"name": { "matched": true },
"federalRevenueNumber": { "matched": true },
"mothersName": { "matched": true },
"birthdate": { "matched": true }
}
},
"classification": {
"type": "DriversLicense",
"subtype": "Printed",
"country": "BRA",
"sides": [
{ "side": "OnlyFront", "page": 0, "fieldname": "frente", "confidence": 0.99 },
{ "side": "OnlyBack", "page": 0, "fieldname": "verso", "confidence": 0.97 }
]
},
"face": {
"age": 34,
"gender": { "value": "Male" },
"boundingBox": { "top": 0.22, "left": 0.28, "width": 0.15, "height": 0.16 },
"croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...K5CYII="
}
}
],
"metadata": {
"filesInfo": [
{
"fieldname": "frente",
"name": "cnh-frente.jpg",
"size": 567098,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "41c2ece339abfcf9ba1e7d5a60666162a24ef34ba95adeb41ed1d9721c91c6b0"
}
],
"timeSpent": 8120
}
}What changes in v2
Besides having no enhanced, v2 has two differences that break consumption:
- It does not merge front and back. Each side recognized becomes a separate
dataentry, each withpageandfieldnameat the root of the item. A driver's license sent in two files returns two entries, not one. classificationuses a different vocabulary.typecomes translated intoCNH,RG,CPF,PROOF-OF-RESIDENCE,SELFIE,IMPRESSOS,CARTAOCREDITOorOTHERS, and the side lives inclassification.face, with the valuesfront,backorfront-back. There is nosubtypeand nocountry.
The Federal Revenue Service cross-check lives in federalRevenueData, with the matches in federalRevenueData.matched — note the singular name, different from v3 — and each field carrying matched, confidence (0 to 1) and strategy (char-to-char or by-tokens).
{
"id": "13cfec7c-b238-4820-a4d1-5173e4c1418e",
"version": "v2",
"data": [
{
"page": 0,
"fieldname": "frente",
"extraction": {
"name": "JOAO DA SILVA SANTOS",
"federalRevenueNumber": "12345678909",
"mothersName": "MARIA DA SILVA SANTOS",
"birthdate": "01/02/1990",
"registerNumber": "01234567890",
"driversLicenseCategory": "AB"
},
"federalRevenueData": {
"name": "JOAO DA SILVA SANTOS",
"federalRevenueNumber": "12345678909",
"mothersName": "MARIA DA SILVA SANTOS",
"birthdate": "01/02/1990",
"matched": {
"name": { "matched": true, "confidence": 1, "strategy": "char-to-char" },
"federalRevenueNumber": { "matched": true, "confidence": 1, "strategy": "char-to-char" },
"mothersName": { "matched": true, "confidence": 0.97, "strategy": "by-tokens" },
"birthdate": { "matched": true, "confidence": 1, "strategy": "char-to-char" }
}
},
"classification": {
"confidence": 0.99,
"type": "CNH",
"face": "front"
},
"face": {
"age": 34,
"gender": { "value": "Male", "confidence": 99.72 },
"boundingBox": { "top": 0.22, "left": 0.28, "width": 0.15, "height": 0.16 },
"croppedBase64": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAMAAA...K5CYII="
}
}
],
"metadata": {
"filesInfo": [
{
"fieldname": "frente",
"name": "cnh-frente.jpg",
"size": 567098,
"pages": 1,
"mimetype": "image/jpeg",
"encoding": "7bit",
"sha256": "41c2ece339abfcf9ba1e7d5a60666162a24ef34ba95adeb41ed1d9721c91c6b0"
}
],
"timeSpent": 7450
}
}‼️ Switching versions breaks whoever reads the response
The path to one and the same piece of data changes across all three versions. The mother's name confirmed by the Federal Revenue Service is in data[].federalRevenueData.mothersName on v2 and v3, and in data[].taxData.mothersName on v4. The result of that check is in data[].federalRevenueData.matched.mothersName.matched on v2, in data[].federalRevenueData.matches.mothersName.matched on v3, and in data[].matches.mothersName on v4.
Code written for one version does not work on the other without changes.