Legal Person Object
Submits the registration of a legal 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.
There are only 3 required fields. Go straight to Minimum payload.
In Legal Person, face and identity documents go inside legal_representatives[], and source.session_id goes at the root. This is the main difference compared to Natural Person — see Integrating SDK data.
Minimum payload
{
"id": "87654321",
"registration_date": "2026-08-07T11:37:15-03:00",
"document_number": "11.111.111/0001-11"
}
Response:
{
"id": "87654321",
"analysis_status": "automatically_approved",
"reason": "rule_decision_enum"
}
The more data you send, the more validations the rules engine is able to perform.
Submit a registration
Query parameters
analyze boolean optional — defaults totrue
With true, the registration is analyzed. With false, it is only recorded (with no charge) and the response returns not_analysed.
- Python
- PHP
- Node.js
- Java
- C#
- curl
import requests
BASE_URL = "https://api.sandbox.caas.qitech.app"
API_KEY = "YOUR_API_KEY"
payload = {
"id": "87654321",
"registration_date": "2026-08-07T11:37:15-03:00",
"document_number": "11.111.111/0001-11"
}
response = requests.post(
f"{BASE_URL}/onboarding/legal_person",
params={"analyze": "true"},
json=payload,
headers={"Authorization": API_KEY},
timeout=30,
)
response.raise_for_status()
print(response.json()["analysis_status"])
<?php
$baseUrl = 'https://api.sandbox.caas.qitech.app';
$apiKey = 'YOUR_API_KEY';
$payload = [
'id' => '87654321',
'registration_date' => '2026-08-07T11:37:15-03:00',
'document_number' => '11.111.111/0001-11'
];
$ch = curl_init($baseUrl . '/onboarding/legal_person?analyze=true');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: ' . $apiKey
],
CURLOPT_POSTFIELDS => json_encode($payload)
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
throw new RuntimeException("Onboarding returned HTTP {$status}: {$body}");
}
echo json_decode($body, true)['analysis_status'];
const BASE_URL = "https://api.sandbox.caas.qitech.app";
const API_KEY = "YOUR_API_KEY";
const payload = {
id: "87654321",
registration_date: "2026-08-07T11:37:15-03:00",
document_number: "11.111.111/0001-11"
};
async function createLegalPerson() {
const response = await fetch(
`${BASE_URL}/onboarding/legal_person?analyze=true`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: API_KEY
},
body: JSON.stringify(payload)
},
);
if (!response.ok) {
throw new Error(`Onboarding returned HTTP ${response.status}`);
}
const result = await response.json();
console.log(result.analysis_status);
return result;
}
createLegalPerson();
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class CreateLegalPerson {
private static final String BASE_URL = "https://api.sandbox.caas.qitech.app";
private static final String API_KEY = "YOUR_API_KEY";
public static void main(String[] args) throws Exception {
String payload = """
{
"id": "87654321",
"registration_date": "2026-08-07T11:37:15-03:00",
"document_number": "11.111.111/0001-11"
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/onboarding/legal_person?analyze=true"))
.header("Content-Type", "application/json")
.header("Authorization", API_KEY)
.timeout(Duration.ofSeconds(30))
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response =
client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new IllegalStateException(
"Onboarding returned HTTP " + response.statusCode() + ": " + response.body());
}
System.out.println(response.body());
}
}
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public class CreateLegalPerson
{
private const string BaseUrl = "https://api.sandbox.caas.qitech.app";
private const string ApiKey = "YOUR_API_KEY";
public static async Task Main()
{
var payload = new
{
id = "87654321",
registration_date = "2026-08-07T11:37:15-03:00",
document_number = "11.111.111/0001-11"
};
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
client.DefaultRequestHeaders.Add("Authorization", ApiKey);
var content = new StringContent(
JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await client.PostAsync(
$"{BaseUrl}/onboarding/legal_person?analyze=true", content);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
throw new InvalidOperationException(
$"Onboarding returned HTTP {(int)response.StatusCode}: {body}");
}
Console.WriteLine(body);
}
}
curl -X POST \
'https://api.sandbox.caas.qitech.app/onboarding/legal_person?analyze=true' \
-H 'Content-Type: application/json' \
-H 'Authorization: YOUR_API_KEY' \
-d '{
"id": "87654321",
"registration_date": "2026-08-07T11:37:15-03:00",
"document_number": "11.111.111/0001-11"
}'
Object fields
Required
idstringrequiredIdentifier of the analysis. 1 to 50 characters. Unique per request — a repeated value returns HTTP 409.registration_datedatetimerequiredDate and time of the registration, with time zone. Same format as Natural Person.document_numberstringrequiredCNPJ with punctuation, in theXX.XXX.XXX/XXXX-XX format. 18 characters.Company data
registration_idstringoptionalIdentifier of the registration in your system. Takes the value ofid when omitted.legal_namestringoptionalRegistered corporate name.trading_namestringoptionalTrade name.foundation_datedateoptionalDate of incorporation in the YYYY-MM-DD format.websitestringoptionalCompany website. Up to 10,000 characters.activitystringoptionalDescription of the economic activity.activity_codestringoptionalCNAE in the XX.XX-X-XX format. Exactly 10 characters.merchant_category_codeenumoptional4-digit MCC as defined by ISO 18245. Only codes from the official list are accepted.tierstringoptionalCompany size. Up to 10 characters. E.g.: mei, epp, me.annual_revenuesintegeroptionalAnnual revenue in cents.monthly_revenuesintegeroptionalMonthly revenue in cents.Contact and location
emailsarrayoptionalList of Email objects. Each item requiresemail.phonesarrayoptionalList of Phone objects. Each item requires international_dial_code, area_code and number.addressobjectoptionalAddress object. If sent, it requires postal_code.documentsobjectoptionalCompany documents. Only accepts ie, company_statute and proof_of_address — see the warning below, SDK data and Shared objects.sourceobjectoptionalOrigin of the request. It is here at the root that the Device Scan session_id must be sent — see SDK data.Ownership structure
legal_representativesarrayoptionalList of LegalRepresentative objects. It is inside this array thatface and identity documents (RG, CNH) go — see SDK data.partnersarrayoptionalList of Partner objects with the company partners.final_beneficiariesarrayoptionalList of FinalBeneficiary objects with the ultimate beneficiaries.Classification and extras
analysis_typestringoptionalType of analysis, when your account has more than one flow configured.client_categorystringoptionalCustomer category on your platform.partnership_keystringoptionalIdentifier of the associated partnership.related_account_typestringoptionalType of related account.custom_dataobjectoptionalCustom fields. Requires a schema previously registered by QI Tech.{
"id": "87654321",
"registration_id": "cad-pj-1234",
"registration_date": "2026-08-07T11:37:15-03:00",
"client_category": "Premium Account",
"legal_name": "Empresa Exemplo LTDA",
"trading_name": "Barbearia do John",
"document_number": "11.111.111/0001-11",
"foundation_date": "1992-09-15",
"website": "www.exemplo.com.br",
"activity": "Barber Shops",
"activity_code": "96.02-5-01",
"merchant_category_code": "0742",
"tier": "epp",
"annual_revenues": 180000000,
"monthly_revenues": 15000000,
"emails": [{ "email": "contato@exemplo.com.br" }],
"address": {
"street": "Rua do Teste",
"number": "111",
"neighborhood": "Centro",
"city": "São Paulo",
"uf": "SP",
"postal_code": "04570-140",
"country": "BRA"
},
"phones": [
{
"international_dial_code": "55",
"area_code": "11",
"number": "999999999",
"type": "commercial"
}
],
"source": {
"channel": "web",
"platform": "web",
"ip": "255.201.26.1",
"session_id": "54b8e3cf-15de-41e5-9305-0ecf059d6e2a"
},
"documents": {
"company_statute": {
"ocr_key": "d8fa2fb0-5199-47c3-daae-bd8ef03f4ea9"
},
"proof_of_address": {
"document_analysis_id": "e9ab3ac1-62aa-48d4-ebbf-ce9fa14a5fb0"
}
},
"legal_representatives": [
{
"id": "rep-001",
"name": "Maria Sample",
"document_number": "222.222.222-22",
"birthdate": "1985-03-22",
"mother_name": "Ana Sample",
"pleaded_pep": false,
"face": {
"type": "zaig_sdk",
"registration_key": "46f38cf4-07b2-4de6-93e9-64b51a68378a"
},
"documents": {
"cnh": {
"register_number": "05163811694",
"issuer_state": "SP",
"ocr_key": "c7ef1eaf-4088-46b2-c9fd-ac7de92e3d98"
}
}
}
],
"partners": [
{
"name": "Maria Sample",
"document_number": "222.222.222-22"
}
],
"final_beneficiaries": [
{
"name": "Maria Sample",
"document_number": "222.222.222-22"
}
]
}
The schema uses additionalProperties: false. Any field outside the ones listed returns HTTP 400.
At the root of Legal Person, documents accepts only ie, company_statute and proof_of_address. Identity documents belong to the legal representative, inside legal_representatives[].documents. Sending them at the root returns HTTP 400.
Field formats
document_number — CNPJ
The XX.XXX.XXX/XXXX-XX format, with punctuation, 18 characters. Digits only are rejected.
activity_code — CNAE
The XX.XX-X-XX format, exactly 10 characters. E.g.: 96.02-5-01.
registration_date
Same format as Natural Person: ISO 8601 with time zone, offset ending in :00/:30 or the Z suffix.
Monetary values
annual_revenues and monthly_revenues are integers in cents. R$ 150,000.00 → 15000000.
Representatives, partners and beneficiaries
All three arrays accept the same identification fields as a natural person (name, document_number, birthdate, gender, nationality, mother_name, occupation, emails, phones, address, pleaded_pep).
Only legal_representatives[] accepts face and documents — that is where the representative's biometrics and OCR keys go. See Integrating SDK data.
Testing in Sandbox
The decision is deterministic, defined by the first digit of the CNPJ:
| First digit | Result |
|---|---|
9 | automatically_approved |
8 | automatically_reproved |
7 | pending |
6 | Manual analysis, with later approval |
5 | Manual analysis, with later rejection |
4 | automatically_challenged |
0 to 3 | in_manual_analysis |
Do not use real legal person data in the Sandbox environment.
Errors
| Status | Situation | How to resolve |
|---|---|---|
| 400 | Missing required field, invalid format or field not defined in the schema. | Check the description in the response. |
| 400 | rg/cnh at the root of documents. | Move them into legal_representatives[]. |
| 400 | custom_data without a registered schema. | Ask support to register it. |
| 401 | Missing Authorization header or deactivated key. | Check the key. |
| 403 | Invalid API Key. | Confirm it with support. |
| 409 | id already used. | Generate a unique id. |
| 500 | Internal error. | Our team is notified automatically. |
Full list in HTTP Status.
Integration checklist
-
POST /onboarding/legal_personwith the minimum payload returning200in Sandbox. - CNPJ with punctuation and CNAE in the
XX.XX-X-XXformat. -
source.session_idfilled in at the root (without it, the device does not show up on the Legal Person dashboard). -
faceand identity documents insidelegal_representatives[]. - At the root of
documents, onlyie,company_statute,proof_of_address. - Monetary values in cents.
- Webhook configured for the asynchronous result.