Skip to main content

Natural Person Object

Submits the registration of a natural person for fraud and KYC analysis. QI Tech runs your decision tree against the submitted data and returns in analysis_status the result that your policy determined — see Status dynamics.

Start with the minimum payload

There are only 3 required fields. Go straight to Minimum payload and then add whatever makes sense for your use case.

Send final data

The data you submit must be definitive. CPF, name and date of birth should not change after this call — this ensures consistency of the anti-fraud database and a realistic risk assessment.

Using the biometrics, OCR or Device Scan SDKs?

The keys returned by the SDKs go into the face, documents and source blocks of this payload. Where each one goes — and what changes compared to Legal Person — is covered in SDK data (face, documents and device).


Minimum payload

This is the smallest body accepted by POST /onboarding/natural_person.

Minimum payload — 3 required fields
{
"id": "12345678",
"registration_date": "2026-08-07T11:37:15-03:00",
"document_number": "111.111.111-11"
}

Response:

{
"id": "12345678",
"analysis_status": "automatically_approved",
"reason": "rule_decision_enum"
}
Additional fields

The more data you send, the more validations the rules engine is able to perform.


Submit a registration

ENDPOINT
/onboarding/natural_person
METHOD
POST

Query parameters

analyze boolean optional — defaults to true With true, your decision tree is executed and the response returns the result. With false, the registration is only recorded (with no charge) and becomes part of the history used in future analyses — the response returns not_analysed.

Request examples

import requests

BASE_URL = "https://api.sandbox.caas.qitech.app"
API_KEY = "YOUR_API_KEY"

payload = {
"id": "12345678",
"registration_date": "2026-08-07T11:37:15-03:00",
"document_number": "111.111.111-11"
}

response = requests.post(
f"{BASE_URL}/onboarding/natural_person",
params={"analyze": "true"},
json=payload,
headers={"Authorization": API_KEY},
timeout=30,
)

response.raise_for_status()
result = response.json()
print(result["analysis_status"]) # automatically_approved

Response

idstringThe same id sent in the request.analysis_statusenumResult of running your decision tree. See Status dynamics.reasonstringReason for the decision, when available.
{
"id": "12345678",
"analysis_status": "automatically_approved",
"reason": "rule_decision_enum"
}
Asynchronous response

When the analysis takes longer than expected, the response comes back as in_queue or pending and the final result arrives via Webhook. Treat these two statuses as "waiting" — not as a rejection.


Object fields

Required

idstringrequiredIdentifier of the analysis in your system. 1 to 50 characters. Must be unique per request — a repeated id returns HTTP 409.registration_datedatetimerequiredDate and time of the registration, with time zone. See the accepted format.document_numberstringrequiredCPF with punctuation, in the XXX.XXX.XXX-XX format. Exactly 14 characters.

Identification

registration_idstringoptionalIdentifier of the registration in your system. Use the same value across different analyses of the same registration to group them. When omitted, it takes the value of id.namestringoptionalFull name. 1 to 500 characters.birthdatedateoptionalDate of birth in the YYYY-MM-DD format.genderenumoptionalmale or female.nationalitystringoptionalCountry in ISO 3166-1 alpha-3, 3 uppercase letters. E.g.: BRA.mother_namestringoptionalMother's full name. 1 to 500 characters. A relevant signal for bureau validation.father_namestringoptionalFather's full name. 1 to 500 characters.

Financial profile

monthly_incomeintegeroptionalGross monthly income in cents. R$ 5,000.00 → 500000.declared_assetsintegeroptionalDeclared assets in cents.occupationstringoptionalOccupation. 1 to 100 characters.is_us_personbooleanoptionalIndicates whether the person has tax obligations in the US (relevant for FATCA).pleaded_pepbooleanoptionalIndicates whether the person declared themselves a politically exposed person (PEP).

Contact and location

emailsarrayoptionalList of Email objects. Within each item, only email is required.phonesarrayoptionalList of Phone objects. If sent, each item requires international_dial_code, area_code and number.addressobjectoptionalAddress object. If sent, only postal_code is required within it.documentsobjectoptionalIdentification documents (RG, CNH, passport and others). OCR keys go here — see SDK data and Shared objects.faceobjectoptionalFacial validation data. The key returned by the biometrics SDK goes here — see SDK data.sourceobjectoptionalOrigin of the request (channel, platform, IP, session). This is where the Device Scan session_id goes — see SDK data.

Classification and extras

analysis_typestringoptionalType of analysis to apply, when your account has more than one flow configured. Align with support before using it.client_categorystringoptionalCustomer category on your platform or loyalty program. 1 to 100 characters.partnership_keystringoptionalIdentifier of the partnership associated with the registration. 1 to 500 characters.related_account_typestringoptionalType of account related to the registration. 1 to 50 characters.vehicle_platestringoptionalVehicle license plate associated with the registration. 1 to 50 characters.custom_dataobjectoptionalCustom fields for your account. Requires a schema previously registered by QI Tech — see the warning below.
Full payload
{
"id": "12345678",
"registration_id": "cad-98765",
"registration_date": "2026-08-07T11:37:15-03:00",
"analysis_type": "default",
"client_category": "Premium User",
"name": "John Sample",
"document_number": "111.111.111-11",
"birthdate": "1992-09-15",
"gender": "male",
"nationality": "BRA",
"mother_name": "Maria Sample",
"father_name": "John Sample",
"monthly_income": 500000,
"declared_assets": 7500000,
"occupation": "Teacher",
"is_us_person": false,
"pleaded_pep": false,
"emails": [
{
"email": "johnsample@test.com"
}
],
"documents": {
"rg": {
"number": "4.366.477-8",
"issuer": "II",
"issuer_state": "PR",
"issuance_date": "2002-01-12"
},
"cnh": {
"register_number": "05163811694",
"issuer_state": "PR",
"first_issuance_date": "2011-03-21",
"issuance_date": "2016-06-29",
"expiration_date": "2031-06-25",
"category": "AB"
}
},
"address": {
"street": "Rua do Teste",
"number": "111",
"neighborhood": "Bairro do Exemplo",
"city": "Aparecida de Goiânia",
"uf": "GO",
"complement": "Térreo",
"postal_code": "00000-000",
"country": "BRA"
},
"phones": [
{
"international_dial_code": "55",
"area_code": "11",
"number": "999999999",
"type": "mobile"
}
],
"source": {
"channel": "app",
"platform": "android",
"ip": "255.201.26.1",
"session_id": "54b8e3cf-15de-41e5-9305-0ecf059d6e2a",
"os_version": "14"
},
"face": {
"type": "zaig_sdk",
"registration_key": "46f38cf4-07b2-4de6-93e9-64b51a68378a"
}
}
Fields not defined in the schema are rejected

The schema uses additionalProperties: false. Any field outside the ones listed above makes the request return HTTP 400, even if the rest of the payload is correct.

custom_data requires its own schema

custom_data is validated against a schema specific to your company, registered by QI Tech. If you send this field without having the schema registered, the response is HTTP 400 with the message "Custom data not available for you account". Talk to support before using it.


Field formats

registration_date format

ISO 8601 format with a mandatory time zone. The validator accepts offsets ending in :00 or :30, or the Z suffix:

2026-08-07T11:37:15-03:00 ✅
2026-08-07T11:37:15.123456-03:00 ✅ fraction of 1 to 6 digits
2026-08-07T14:37:15Z ✅ UTC
2026-08-07T11:37:15 ❌ no time zone
2026-08-07T11:37:15-03:15 ❌ offset not allowed

document_number — CPF

Must be sent with punctuation: XXX.XXX.XXX-XX, exactly 14 characters. Sending digits only (11111111111) returns HTTP 400.

postal_code — CEP

Inside address, the postal code requires the XXXXX-XXX format (with a hyphen). 00000000 is rejected.

Monetary values

monthly_income and declared_assets are integers in cents of Brazilian reais. Multiply by 100: R$ 5,000.00 → 500000.


Enumerators

gender

ValueMeaning
maleMale
femaleFemale

phones[].type

ValueMeaning
mobileMobile
residentialResidential
commercialCommercial

| visit | Confirmed by an in-person visit | | zaig_sdk | Confirmed by QI Tech's SDK | | zaig_ocr | Confirmed by OCR of a proof document |

face.type

ValueMeaning
zaig_sdkCapture via QI Tech's SDK (use registration_key)
base_64Image sent directly in the image field

For analysis_status, client_status and risk_level, see Status dynamics.


Testing in Sandbox

In Sandbox the decision is deterministic, defined by the first digit of the CPF:

First digitResult
9automatically_approved
8automatically_reproved
7pending
6Manual analysis, with later approval
5Manual analysis, with later rejection
4automatically_challenged
0 to 3in_manual_analysis
Important warning

Do not use real natural person data in the Sandbox environment.


Errors

StatusSituationHow to resolve
400Missing required field, invalid format, enum outside the list or field not defined in the schema.Check the description in the response, which points to the field.
400custom_data without a registered schema.Ask support to register the schema.
401Missing Authorization header or deactivated API Key.Check the key.
403Invalid API Key.Confirm the key with support.
409id already used.Generate a unique id per request.
500Internal error.Our specialists are notified automatically.

Full list in HTTP Status.


Integration checklist

  • POST /onboarding/natural_person with the minimum payload returning 200 in Sandbox.
  • id unique per request (test the 409 by resending the same id).
  • registration_id stable so analyses of the same registration are grouped.
  • CPF with punctuation and postal code with a hyphen.
  • Monetary values in cents.
  • in_queue and pending treated as "waiting", not as a rejection.
  • Webhook configured to receive the asynchronous result.