# QI Tech — Risk Solutions

Documentação da QI Tech em texto corrido, para colar em um LLM.
Fonte: https://docs.qitech.com.br
166 página(s).

Índice:
- Autenticação (/documentation/caas/account_event/authentication)
- Objeto Device Validation (/documentation/caas/account_event/device_validation)
- Status HTTP (/documentation/caas/account_event/http_status)
- Introdução (/documentation/caas/account_event/introduction)
- Pre PIX Transaction (/documentation/caas/account_event/pre_pix_transaction)
- Recuperar um Evento de Conta (/documentation/caas/account_event/query_registration)
- Padrões (/documentation/caas/account_event/standards)
- Dinâmica dos Status (/documentation/caas/account_event/status_dynamics)
- Criação de Conta (/documentation/caas/account_monitoring/account_registration)
- authentication (/documentation/caas/account_monitoring/authentication)
- Status HTTP (/documentation/caas/account_monitoring/http_status)
- Introdução (/documentation/caas/account_monitoring/introduction)
- Criação de Pessoas (/documentation/caas/account_monitoring/person_registration)
- Padrões (/documentation/caas/account_monitoring/standards)
- Webhook (/documentation/caas/account_monitoring/webhook)
- Criação de Sessão (/documentation/caas/auth_session_manager/auth_session)
- Autenticação (/documentation/caas/auth_session_manager/authentication)
- Status HTTP (/documentation/caas/auth_session_manager/http_status)
- Introdução (/documentation/caas/auth_session_manager/introduction)
- Gestão de Sessão (/documentation/caas/auth_session_manager/retrieve_session)
- Boleto (/documentation/caas/banking/bankslips)
- Pagamento de Contas (/documentation/caas/banking/bill_payments)
- Depósitos (/documentation/caas/banking/deposits/introduction)
- Status HTTP (/documentation/caas/banking/http_status)
- Introdução (/documentation/caas/banking/introduction)
- Objetos Compartilhados (/documentation/caas/banking/objects)
- PIX Dict Operation (/documentation/caas/banking/pix_dict_operations)
- PIX Infraction Report (/documentation/caas/banking/pix_infraction_reports)
- PIX Transaction (/documentation/caas/banking/pix_transactions)
- Padrões (/documentation/caas/banking/standards)
- Webhook (/documentation/caas/banking/webhook)
- Transferências (/documentation/caas/banking/wire_transfers)
- Saques (/documentation/caas/banking/withdrawals)
- Status HTTP (/documentation/caas/car_rental/http_status)
- Imagens (/documentation/caas/car_rental/image)
- Introdução (/documentation/caas/car_rental/introduction)
- Troca de Mensagens (/documentation/caas/car_rental/messages)
- Objetos Compartilhados (/documentation/caas/car_rental/objects)
- Envio de Resultado Quiz (/documentation/caas/car_rental/quiz)
- RentalAgreement-v1 (/documentation/caas/car_rental/rental_agreement)
- RentalAgreement-v2 (/documentation/caas/car_rental/rental_agreement_v2)
- Reservation-v1 (/documentation/caas/car_rental/reservation)
- Reservation-v2 (/documentation/caas/car_rental/reservation_v2)
- Padrões (/documentation/caas/car_rental/standards)
- Webhook (/documentation/caas/car_rental/webhook)
- Alertas de Portadores (/documentation/caas/card_issuance/alerts)
- Status HTTP (/documentation/caas/card_issuance/http_status)
- Introdução (/documentation/caas/card_issuance/introduction)
- Padrões (/documentation/caas/card_issuance/standards)
- Transaction (/documentation/caas/card_issuance/transaction)
- Status HTTP (/documentation/caas/card_order/http_status)
- Introdução (/documentation/caas/card_order/introduction)
- Objetos (/documentation/caas/card_order/objects)
- Order (/documentation/caas/card_order/order)
- Padrões (/documentation/caas/card_order/standards)
- Webhook (/documentation/caas/card_order/webhook)
- Fluxo de Desafio (/documentation/caas/credit_analysis/challenge_flow)
- Recuperar uma Análise de Crédito (/documentation/caas/credit_analysis/get_credit_analysis)
- Status HTTP (/documentation/caas/credit_analysis/http_status)
- Introdução (/documentation/caas/credit_analysis/introduction)
- Análise de Crédito - Pessoa Jurídica (/documentation/caas/credit_analysis/legal_person)
- Análise de Crédito - Pessoa Física (/documentation/caas/credit_analysis/natural_person)
- Objetos Compartilhados (/documentation/caas/credit_analysis/objects)
- Dados Sistema de Informações de Créditos (SCR - BACEN) (/documentation/caas/credit_analysis/scr)
- Padrões (/documentation/caas/credit_analysis/standards)
- Dinâmica dos Status (/documentation/caas/credit_analysis/status_dynamics)
- Atualizar o status de uma Análise de Crédito (/documentation/caas/credit_analysis/update_credit_analysis)
- Webhook (/documentation/caas/credit_analysis/webhook)
- Objeto Account (/documentation/caas/device_manager/account)
- Autenticação (/documentation/caas/device_manager/authentication)
- Objeto Device (/documentation/caas/device_manager/device_registration)
- Status HTTP (/documentation/caas/device_manager/http_status)
- Introdução (/documentation/caas/device_manager/introduction)
- Objeto Person (/documentation/caas/device_manager/person)
- Recuperar ou Desativar uma Account, Person ou Device (/documentation/caas/device_manager/query_registration)
- Padrões (/documentation/caas/device_manager/standards)
- Dinâmica dos Status (/documentation/caas/device_manager/status_dynamics)
- O objeto DeviceScan (/documentation/caas/device_scan/android/device_scan_object)
- Implementação (/documentation/caas/device_scan/android/example)
- Soluções híbridas (/documentation/caas/device_scan/android/hybrid_solutions)
- Coleta de informações (/documentation/caas/device_scan/android/information_gathering)
- Introdução (/documentation/caas/device_scan/android/introduction)
- Integração nativa (/documentation/caas/device_scan/android/native_java)
- Permissões (/documentation/caas/device_scan/android/permissions)
- Autenticação (/documentation/caas/device_scan/api/authentication)
- O objeto QitechDeviceScan (/documentation/caas/device_scan/flutter/device_scan_object)
- Implementação (/documentation/caas/device_scan/flutter/example)
- Introdução (/documentation/caas/device_scan/flutter/introduction)
- Permissões (/documentation/caas/device_scan/flutter/permissions)
- O objeto QITechIosDeviceScan (/documentation/caas/device_scan/ios/device_scan_object)
- Implementação (/documentation/caas/device_scan/ios/example)
- Soluções híbridas (/documentation/caas/device_scan/ios/hybrid_solutions)
- Coleta de informações (/documentation/caas/device_scan/ios/information_gathering)
- Introdução (/documentation/caas/device_scan/ios/introduction)
- Integração nativa (/documentation/caas/device_scan/ios/native_swift)
- Permissões (/documentation/caas/device_scan/ios/permissions)
- Desktop Device Scan (/documentation/caas/device_scan/web/desktop)
- O objeto DeviceScan (/documentation/caas/device_scan/web/device_scan_object)
- Implementação (/documentation/caas/device_scan/web/example)
- Importando a biblioteca (/documentation/caas/device_scan/web/import)
- Coletando os Retornos (/documentation/caas/device_scan/web/information_gathering)
- Introdução (/documentation/caas/device_scan/web/introduction)
- Enviando um documento (/documentation/caas/document_analysis/document_submission)
- Status HTTP (/documentation/caas/document_analysis/http_status)
- Introdução (/documentation/caas/document_analysis/introduction)
- Webhook (/documentation/caas/document_analysis/webhook)
- Coletando os Resultados (/documentation/caas/face_recognition/android/collecting_response)
- Soluções híbridas (/documentation/caas/face_recognition/android/hybrid_solutions)
- Introdução (/documentation/caas/face_recognition/android/introduction)
- Integração nativa (/documentation/caas/face_recognition/android/native_java)
- Autenticação (/documentation/caas/face_recognition/api/authentication)
- Registro de rosto (1:1) (/documentation/caas/face_recognition/api/face_registration)
- Status HTTP (/documentation/caas/face_recognition/api/http_status)
- Imagem (/documentation/caas/face_recognition/api/image)
- Introdução (/documentation/caas/face_recognition/api/introduction)
- Padrões (/documentation/caas/face_recognition/api/standards)
- Coletando os Retornos do SDK (/documentation/caas/face_recognition/ios/collecting_response)
- QITechIosFaceRecognitionConfiguration (/documentation/caas/face_recognition/ios/configuration)
- Soluções híbridas (/documentation/caas/face_recognition/ios/hybrid_solutions)
- Introdução (/documentation/caas/face_recognition/ios/introduction)
- Importando o SDK (/documentation/caas/face_recognition/ios/native_swift)
- Coletando os Retornos do SDK (/documentation/caas/face_recognition/web/collecting_response)
- Implementação (/documentation/caas/face_recognition/web/example)
- O construtor QITechWebFaceRecon.WebFaceRecon() (/documentation/caas/face_recognition/web/example_zaigwebfacerecon)
- Importando a biblioteca (/documentation/caas/face_recognition/web/import)
- Introdução (/documentation/caas/face_recognition/web/introduction)
- Registro de Rosto e Validação 1:1 (/documentation/caas/face_recognition/web/registration_and_validation)
- Status HTTP (/documentation/caas/limits/http_status)
- Introdução (/documentation/caas/limits/introduction)
- Cadastro de Novo Limite (/documentation/caas/limits/limit_registration)
- Criando uma lista de beneficiários (/documentation/caas/limits/recipient_list)
- Padrões (/documentation/caas/limits/standards)
- Dinâmica dos Status (/documentation/caas/limits/status_dynamics)
- Webhook (/documentation/caas/limits/webhook)
- Coletando os Retornos (/documentation/caas/ocr/android/collecting_response)
- DocumentRecognitionStep (/documentation/caas/ocr/android/document_step)
- Soluções híbridas (/documentation/caas/ocr/android/hybrid_solutions)
- Introdução (/documentation/caas/ocr/android/introduction)
- Integração nativa (/documentation/caas/ocr/android/native_java)
- Status HTTP (/documentation/caas/ocr/api/http_status)
- Introdução (/documentation/caas/ocr/api/introduction)
- Enviando um Documento (/documentation/caas/ocr/api/send_image)
- Coletando os Retornos (/documentation/caas/ocr/ios/collecting_response)
- QITechIosOcrConfiguration (/documentation/caas/ocr/ios/configuration)
- Soluções híbridas (/documentation/caas/ocr/ios/hybrid_solutions)
- Introdução (/documentation/caas/ocr/ios/introduction)
- Importando o SDK (/documentation/caas/ocr/ios/native_swift)
- Coletando os Retornos (/documentation/caas/ocr/web/collecting_results)
- O construtor QiTechWebOCR.WebOCR() (/documentation/caas/ocr/web/constructor_info)
- Implementação (/documentation/caas/ocr/web/example)
- Importando a biblioteca (/documentation/caas/ocr/web/import)
- A função initialize() (/documentation/caas/ocr/web/initialize_info)
- Introdução (/documentation/caas/ocr/web/introduction)
- Autenticação (/documentation/caas/onboarding/authentication)
- Status HTTP (/documentation/caas/onboarding/http_status)
- Integrações (/documentation/caas/onboarding/integrations)
- Introdução (/documentation/caas/onboarding/introduction)
- Objeto Legal Person (/documentation/caas/onboarding/legal_person)
- Objeto Natural Person (/documentation/caas/onboarding/natural_person)
- Objetos Compartilhados (/documentation/caas/onboarding/objects)
- Recuperar um Cadastro (/documentation/caas/onboarding/query_registration)
- Integrando os dados do SDK (face, documentos e device) (/documentation/caas/onboarding/sdk_integration)
- Padrões (/documentation/caas/onboarding/standards)
- Dinâmica dos status (/documentation/caas/onboarding/status_dynamics)
- Atualizar um cadastro (/documentation/caas/onboarding/update_registration)
- Webhook (/documentation/caas/onboarding/webhook)

---

# Autenticação

URL: /documentation/caas/account_event/authentication

> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição.
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> Substitua a API Key 'EXAMPLE-OF-API-KEY' pela sua chave, que deve ser obtida através do nosso time de suporte.

Utilizamos uma API Key para permitir acesso à nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE-OF-API-KEY`

:::info **Atenção**

Você deve substituir EXAMPLE-OF-API-KEY pela sua chave, que deve ser obtida através do nosso time de suporte.
:::

---

# Objeto Device Validation

URL: /documentation/caas/account_event/device_validation

A validação de um dispositivo por identificação única deve ser realizada através do endpoint de Event Type Device Validation. Os dados enviados deverão ser os dados gerados na API de Cadastro de Dispositivos, juntamente com um id de sessão de Device Scan, isto é, para realizar uma validação de dispositivo a aplicação deve utilizar o SDK para gerar um identificador único e deve ser realizado o cadastro do dispositivo para que ele possa ser identificado posteriormente.

### Dinâmica dos Status - **analysis_status**

O status **analysis_status** indica o status da decisão do motor de fraude e possui uma máquina de estados bastante simples:

* automatically_approved
* automatically_reproved
* in_manual_analysis
* manually_approved
* manually_reproved
* pending

## Definição do Objeto Device Validation

Request Body

```json
{
  "id": "12345678",
  "account_id": "12345678",
  "person_id": "12345678",
  "session_id": "12345678",
  "event_date": "2019-12-11T11:37:15.12-03:00"
}
```

Todas as trocas de informação de uma validação utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

nome | tipo | descrição
:----: | :----: | ---------
id | string | Identificador do evento. **É essencial que este número seja único para cada requisição** *(obrigatório)*
account_id | string | Identificador da conta cadastrada no sistema de cadastro de dispositivo. Para realizar mais de uma análise referente a um mesmo cadastro, apenas utilize o mesmo account_id nas diferentes análises.*(obrigatório)*
person_id | string | Identificador do usuário associado a conta cadastrada no sistema de cadastro de dispositivo. Para realizar mais de uma análise referente a um mesmo cadastro, apenas utilize o mesmo person_id nas diferentes análises.*(obrigatório)*
session_id | string | Identificador da sessão de análise da Device Scan.*(obrigatório)*
face_recognition_key | string | Identificador da imagem gerada no SDK para identificação facial.
event_date | datetime | Data e hora o evento *(obrigatório)*

## Enviar um Device Validation

Request Body

```json
  {
    "id": "12345",
    ...
  }
```

Response Body

```json
  {
    "id": "12345",
    "analysis_status": "automatically_approved",
    "reason": "rule_decision_enum"
  }
```

Para realizar a validação de um Dispositivo, basta enviar um objeto do tipo Device Validation ao seguinte endpoint:

`POST https://api.caas.qitech.app/account_event/event_type/device_validation/event`

---

# Status HTTP

URL: /documentation/caas/account_event/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, conforme a RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Geralmente, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, conforme a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/account_event/introduction

Bem vindo à API de Eventos de Conta da QI Tech! Esta API dá acesso aos serviços de monitoramento e regras para eventos dentro de contas da sua plataforma!

Esta API pode ser utilizada para a validação de dispositivos juntamente com a api de Device Scan e Cadastro de Dispositivos, mas pode ser usada para outras validações como:

* Login.
* Acesso a telas.
* Alteração de senha.
* Alteração de dados cadastrais.
* Validações pré-transações.
* Validações de liveness.

Você pode utilizar a nossa API para acessar os endpoints para avaliar os seguintes tipos de eventos:

* **Device Validation** - utilizado para validação de identificação única de um dispositivo.
* **Pre Pix Transaction** - utilizado para a pré-validação de transações Pix.
* **Registration Data Validation** - utilizado para a validação de dados cadastrais.

Diferentes tipos de eventos podem ser implementados dependendo das necessidades do seu sistema.

Ao lado, você pode observar a implementação da API utilizando curl. Com isso, você possui exemplos para poder adaptar adequadamente à linguagem de programação da sua preferência.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já notou), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/account_event/`
* Sandbox - `https://api.sandbox.caas.qitech.app/account_event/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.
:::

No ambiente de Sandbox, as análises enviadas não são cobradas e são respondidas conforme a regra configurada para o evento.

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

---

# Pre PIX Transaction

URL: /documentation/caas/account_event/pre_pix_transaction

No momento em que o pagador tiver a intenção de iniciar um pagamento, os dados da transação poderão ser avaliados previamente pelo nosso servidor. Deste modo, será possível realizar uma análise prévia do risco envolvido na transação, baseado naquele conjunto de dados.

## Definição do Objeto de Pre Pix Transactions

Request Body

```json
{
    "id": "082373263",
    "transaction_direction": "received",
    "client": {
        "id": "123456",
        "document_number": "056.966.649-03",
        "name": "Francisco Oliveira Benedetti",
        "type": "natural_person",
        "address": {
            "street": "Avenida 13",
            "number": "704",
            "neighbourhood": "Centro",
            "city": "Ituiutaba",
            "uf": "MG",
            "complement": "Apt 1101",
            "postal_code": "38300-140"
        },
        "phone": {
            "international_dial_code": "55",
            "area_code": "16",
            "number": "981610077",
            "type": "mobile"
        },
        "sales_channel": "inbound_sales",
        "segment": "Personalité"
    },
    "amount": 13725,
    "dict_key": {
        "key_type": "cpf",
        "key_value": "09991222669",
        "assignment_date": "2020-01-15T18:00:00-03:00"
    },
    "face_recognition_key": "ef39e206-13d5-48de-b368-6c3bbc6f0222",
    "source_account": {
        "participant": "17315359",
        "branch": "0000",
        "account_number": "10442",
        "account_digit": "6",
        "owner": {
            "type": "legal_person",
            "document_number": "07.487.735/0001-69",
            "name": "Gioconda Pizzaria e Rotisseria LTDA."
        },
        "account_type": "CACC",
        "opening_date": "2020-01-15T18:00:00-03:00"
    },
    "destination_account": {
        "participant": "60701190",
        "branch": "3675",
        "account_number": "10442",
        "account_digit": "6",
        "owner": {
            "type": "natural_person",
            "document_number": "056.966.649-03",
            "name": "Francisco Oliveira Benedetti"
        },
        "account_type": "SLRY",
        "opening_date": "2020-01-15T18:00:00-03:00"
    },
    "destination_statistics": {
        "person":{
            "settlements":{
                "d90":4,
                "m12":67,
                "m60":618
            },
            "application_frauds":{
                "d90":0,
                "m12":4,
                "m60":9
            },
            "mule_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "scammer_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "other_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "unknown_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "total_frauds_transaction_amount":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "distinct_fraud_reporters":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "open_reports":0,
            "open_reports_distinct_reporters":0,
            "rejected_reports":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "registered_accounts":0
        },
        "owner":{
            "settlements":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "application_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "mule_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "scammer_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "other_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "unknown_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "total_frauds_transaction_amount":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "distinct_fraud_reporters":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "open_reports":0,
            "open_reports_distinct_reporters":0,
            "registered_accounts":0
        },
        "key":{
            "settlements":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "application_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "mule_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "scammer_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "other_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "unknown_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "total_frauds_transaction_amount":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "distinct_fraud_reporters":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "open_reports":0,
            "open_reports_distinct_reporters":0,
            "rejected_reports":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "distinct_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            }
        }
    },
    "source": {
        "channel": "internet_banking",
        "platform": "android",
        "ip": "198.185.065.098",
        "session_id": "7839jdqd9a8wd9"
    },
    "event_date": "2019-12-11T11:37:15.12-03:00"
}
```

Uma transação deve ser enviada para a API antes de ser encaminhada para o sistema de processamento, a fim de realizar uma validação prévia de fraude.

O status da transação representa a decisão retornada pelo modelo sobre aquela transação. Os seguintes status são utilizados na flag **analysis_status**:

* `automatically_approved`
* `automatically_reproved`
* `automatically_challenged`
* `pending`

Abaixo estão listados os significados de cada uma das decisões, devolvidas na flag analysis_status:

status | descrição
:----: | ---------
automatically_approved      | Recomenda-se que esta transação seja aprovada.
automatically_reproved      | Recomenda-se que esta transação seja reprovada.
automatically_challenged    | Os algoritmos da QI Tech recomendam que esta transação seja desafiado.
pending                     | A transação está sendo processada.

nome | tipo | descrição
:----:  | :----:  | ---------
id | string | Identificador do pagamento no sistema do cliente. **É essencial que este número seja único para cada processo de pagamento** *(obrigatório)*
transaction_direction   | enumerador  | Tipo da transação cadastrada. Define se o cliente está recebendo ou enviando dinheiro. *(obrigatório)*
client                  | *client* | Objeto que representa os dados do cliente, seja ele o pagador ou o recebedor. *(obrigatório)*
amount                  | inteiro  | O valor do pagamento, em centavos- conforme descrição da seção "Padrões". *(obrigatório)*
pix_modality            | string   | Tipo de transação cadastrada. Indica se representa uma transferência, um troco ou um saque.
dict_key                | *dict_key*                | Objeto que representa os dados da chave de vínculo no DICT, utilizada pelo cliente na transação.
face_recognition_key    | string                    | Chave de reconhecimento facial, caso tenha sido feito reconhecimento facial pela nossa API de reconhecimento facial.
source_account          | *source_account* | Objeto que representa os dados da conta debitada. *(obrigatório)*
destination_account     | *destination_account* | Objeto que representa os dados da conta creditada. *(obrigatório)*
destination_statistics  | *destination_statistics*  | Objeto que representa o histórico de transações e fraudes da conta creditada provenientes da API de DICT do BACEN.
source                  | *source* | Objeto do tipo Source que descreve as informações provenientes da aplicação utilizada para envio do pagamento
event_date              | datetime | A data e hora de início da transação, com fuso horário. *(obrigatório)*

Existem os seguintes enumeradores para *transaction_direction*: `sent` e `received`.

Existem os seguintes enumeradores para *pix_modality*: `transacation`, `change` e `withdraw`.

## Enviar uma Pré Transação

Request Body

```json
  {
    "id": "12345",
    ...
  }
```

Response Body

```json
  {
    "id": "12345",
    "analysis_status": "automatically_approved",
    "reason": "rule_decision_enum",
    "reason_desciption": "Descrição da regra"
  }
```

Para realizar a avaliação de uma pre transação, basta enviar um objeto do tipo Transaction ao seguinte endpoint:

`POST https://api.caas.qitech.app/account_event/event_type/pre_pix_transaction`

## Fluxo de Desafio

É possível, após a execução da análise, ter como decisão desafiar o usuário para realizar uma nova ação em sua plataforma. Esse fluxo pode ser utilizado para, por exemplo, solicitar um 2FA, como uma análise facial, para o usuário.

## Passo-a-passo da execução do fluxo

**1.** O Evento é submetido para análise, e retornará o status *automatically_challenged*.

Request Body

```json
{
    "id": "082373263",
    ...
    "event_date": "2019-12-11T11:37:15.12-03:00"
}
```

Response Body

```json
{
  "id": "082373263",
  "analysis_status": "automatically_challenge"
  ...
}
```

**2.** Após a primeira requisição de análise ter retornado um *analysis_status* de desafio, uma nova requisição pode ser enviada com o resultado do processo do cliente caso o mesmo tenha sido finalizado. Esta requisição deve ser feita no mesmo *event_id* da requisição anterior e o status atual deve ser obrigatoriamente *automatically_challenged*. Os possíveis status para essa atualização são:

* `approved_by_client`
* `reproved_by_client`

`PATCH https://api.caas.qitech.app/account_event/event_type/pre_pix_transaction/{event_id}`

Request Body: Envio com informações adicionais

```json
{
    "analysis_status": "approved_by_client"
}
````

Response Body

```json
{
  "id": "082373263",
  "analysis_status": "approved_by_client"
  ...
}
```

Atente-se para utilizar o mesmo event_id utilizado na sua primeira análise.

---

# Recuperar um Evento de Conta

URL: /documentation/caas/account_event/query_registration

A fim de recuperar um evento de conta específico, basta realizar uma requisição GET. O resultado retornado é o JSON mais atualizado do evento em questão. Caso este identificador não esteja relacionado a nenhum objeto, o HTTP Status 404 é retornado.

## Possiveis eventos:
- device_validation
- pre_pix_transaction

`GET https://api.caas.qitech.app/event_type/{event_name}/event/{event_id}`

```shell
curl "https://api.caas.qitech.app/event_type/device_validation/event/12345678"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

---

# Padrões

URL: /documentation/caas/account_event/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões seguidos em toda a API.

## Valores Monetários
> Exemplos:

```
10000
12345
98741
1223
1
0
```

As APIs assumem que todos os valores monetários enviados são em reais brasileiros. Os valores devem ser enviados como inteiro em centavos.

## Data e Hora com Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12.232-03:00
2018-05-01T13:32:11.297+00:00
2019-05-01T00:00:00.000+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será valido.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss.sss±hh:mm`

## Data e Hora sem Fuso Horario
> Alguns exemplos:

```
2019-10-15T22:35:12
2018-05-01T13:32:11
2019-05-01T00:00:00
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão ser enviados sem ele, sempre em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ss.sssZ`

## Data
> Alguns exemplos

```
2019-10-15
2019-01-01
2017-03-20
```

No caso de campos que recebem somente a data, sem nenhum horário. Deve ser enviada com o seguinte formato:

`YYYY-MM-dd`

## Documentos
Uma vez que os números de documento são bastante variados e muitos deles possuem caracteres que não se enquadram como numéricos, definem-se todos os números de documento como string. Outro bom motivo para defini-los como string é evitar que os zeros à esquerda desapareçam. Documentos previstos nesta página possuem uma máscara bem definida e estarão sujeitos à validação. O restante dos documentos, como RG, dada sua falta de padronização, não serão validados.

## CPF

> Exemplos de CPFs válidos contra a máscara definida:

```
123.456.789-12
321.987.543-23
111.283.333-00
```

> Exemplos de CPFs inválidos contra a máscara definida:

```
8.577.477-8
08.104.627/0001-23
123.456.789-1
23.456.789-01
```

O CPF é sempre definido como uma string e será validado contra a máscara:

`###.###.###-##`

## CNPJ

> Exemplos de CNPJs válidos contra a máscara definida:

```
08.104.627/0001-02
01.079.210/0114-67
32.402.502/0001-35
```

> Exemplos de CNPJs inválidos contra a máscara definida:

```
8.577.477-8
123.456.789-12
321.987.543-23
32.402.502/0001-3
032.402.502/0001-3
```

O CNPJ é sempre definido como uma string e será validado contra a máscara:

`##.###.###/####-##`

## IP

> Exemplos de IPs válidos contra a máscara definida:

```
201.81.161.86
201.081.161.86
201.81.161.086
201.81.0.1
```

> Exemplos de IPs inválidos:

```
201.81..86
358.81.161.86
201.81.161
```

IPs deverão ser enviados sempre em IPv4, zeros à esquerda poderão ou não ser enviados, respeitando a seguinte máscara:

`###.###.###.###`

---

# Dinâmica dos Status

URL: /documentation/caas/account_event/status_dynamics

O processo de análise consiste em enviar um evento, como de Device Validation, por exemplo, no endpoint adequado e esperar a resposta.

Após a QI Tech realizar a análise do evento, ela retornará uma resposta com um status referente à análise. O campo **analysis_status** representa o resultado da análise de evento realizada pela QI Tech.

### **analysis_status**

Conforme descrito anteriormente, a QI Tech possui oito **analysis_status** que indicam o status da decisão do motor de eventos de conta e possui uma máquina de estados bastante simples:

analysis_status | Descrição
:---------: | ---------
automatically_approved | Os algoritmos da QI Tech recomendam que este evento seja aprovado.
automatically_reproved | Os algoritmos da QI Tech recomendam que este evento seja reprovado.
automatically_challenge | Os algoritmos da QI Tech recomendam que o usuário tome uma ação para adquirir mais informações para a análise.
in_manual_analysis | Os algoritmos da QI Tech enviaram este evento para a análise manual.
manually_approved | Após análise manual, o analista decidiu aprovar o evento.
manually_reproved | Após análise manual, o analista decidiu reprovar o evento.
in_queue | O evento está sendo realizado de forma assíncrona. O resultado do evento será respondido via Webhook.
pending | As consultas estão demorando mais do que o esperado, este evento entrou em uma fila de análise automática e será respondido por meio de Webhook.
not_analysed | O evento foi enviado com a flag de análise falsa, o que significa que nossos sistemas não retornarão uma recomendação.

---

# Criação de Conta

URL: /documentation/caas/account_monitoring/account_registration

O Produto de Monitoramento de Conta é dividido entre Conta Pessoa Física e Conta Pessoa Jurídica, onde uma Conta Pessoa Física pode possuir apenas pessoas físicas, enquanto a Conta Pessoa Júridica pode possuir tanto pessoas jurídicas quanto físicas. Para realizar a criação de uma conta basta enviar um objeto do tipo _Account_ para um dos seguintes endpoints:

- Conta Pessoa Física

`POST https://api.caas.qitech.app/account_monitoring/natural_person_account`

> Exemplo

```json
{
    "account_id": "5ce7fab5-8165-44a5-9b89-bb2d6d61e4f4",
    "registration_date": "2019-12-20T15:23:12"
}
```
- Conta Pessoa Jurídica

`POST https://api.caas.qitech.app/account_monitoring/legal_person_account`

> Exemplo

```json
{
    "account_id": "5ce7fab5-8165-44a5-9b89-bb2d6d61e4f4",
    "registration_date": "2019-12-20T15:23:12"
}
```

Todas as trocas de informação de um cadastro utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

nome | tipo | descrição
:----: | :----: | ---------
account_id | string | Identificador único da conta. **É essencial que este número seja único para cada requisição**
registration_date |	string (ISO 8601) | Data e hora do cadastro.

## Desativação e Reativação de Conta

Para realizar a desativação de contas dentro do produto de monitoramento de contas, deve-se realizar uma requisição no seguinte endpoint com o seguinte payload, passando o campo de new_account_status como 'deactivated':

- Conta Pessoa Física

`PATCH https://api.caas.qitech.app/account_monitoring/natural_person_account/{account_id}`

> Exemplo

```json
{
    "new_account_status" : "deactivated"
}
```
- Conta Pessoa Jurídica

`PATCH https://api.caas.qitech.app/account_monitoring/legal_person_account/{account_id}`

> Exemplo

```json
{
    "new_account_status" : "deactivated"
}
```

Isso desativará a conta e interromperá seu monitoramento. Para reativar uma conta, e consequentemente retomar seu monitoramento, basta realizar uma requisição no seguinte endpoint com o seguinte payload, passando agora o new_account_status como 'active':

- Conta Pessoa Física

`PATCH https://api.caas.qitech.app/account_monitoring/natural_person_account/{account_id}`

> Exemplo

```json
{
    "new_account_status" : "active"
}
```
- Conta Pessoa Jurídica

`PATCH https://api.caas.qitech.app/account_monitoring/legal_person_account/{account_id}`

> Exemplo

```json
{
    "new_account_status" : "active"
}
```

Ao se realizar a reativação de uma conta, os interavalos de monitoramento dos tópicos da conta serão reiniciados. Por exemplo, caso todos os tópicos sejam monitorados de 24 em 24 horas, no momento da reativação da conta, as atualizações serão realizadas 24 horas após a reativação.

---

# authentication

URL: /documentation/caas/account_monitoring/authentication

## Autenticação

> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE_API_KEY"
```

> Substitua a API key 'EXAMPLE_API_KEY' com a sua chave adquirida com o nosso suporte.

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE_API_KEY`

:::info **Atenção**

Você deve substituir EXAMPLE_API_KEY com a API Key recebida do suporte.
:::

---

# Status HTTP

URL: /documentation/caas/account_monitoring/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/account_monitoring/introduction

Bem vindo à API de Monitoramento de Conta da QI Tech! Você pode utilizar a nossa API para monitorar contas e pessoas em cima de diversos tópicos de monitoramento, respeitando intervalos de monitoramento totalmente personalizáveis de acordo com as demandas e necessidades do cliente. Hoje o produto possúi os seguintes tópicos de monitoramento:

- Para Pessoas Físicas;
  - Lista OFAC - Lista de Sanções do Escritório de Controle de Ativos Estrangeiros (Office of Foreign Assets Control)
  - Lista UNSC - Lista de Sanções do Conselho de Segurança das Nações Unidas (United Nations Security Council)
  - Lista IBAMA - Lista de Penalidades Ambientais do Instituto Brasileiro do Meio Ambiente e dos Recursos Naturais Renováveis
  - Lista PEP - Lista de Pessoas Expostas Politicamente
  - Status Receita Federal - Situação Cadastral na Receita Federal do Brasil

- Para Pessoas Jurídicas;
  - Lista OFAC - Lista de Sanções do Escritório de Controle de Ativos Estrangeiros (Office of Foreign Assets Control)
  - Lista UNSC - Lista de Sanções do Conselho de Segurança das Nações Unidas (United Nations Security Council)
  - Lista IBAMA - Lista de Penalidades Ambientais do Instituto Brasileiro do Meio Ambiente e dos Recursos Naturais Renováveis
  - Lista CEIS - Cadastro de Empresas Inidôneas e Suspensas
  - Lista CNEP - Cadastro Nacional de Empresas Punidas
  - Status Receita Federal - Situação Cadastral na Receita Federal do Brasil

Lembrando que os intervalos são definidos por tópico de monitoramento e por tipo de pessoa monitorada, podendo por exemplo a Lista OFAC ser monitorada de 10 em 10 dias para Pessoas Físicas e de 30 em 30 dias para Pessoas Jurídicas

Os intervalo de monitoramento de cada tópico segue o padrão ISO 8601, podendo ser qualquer um dos intervalos abaixo apresentados, ou uma combinação dos mesmos:

### Dias, Semanas, Meses e Anos

| Notação  | Significado |
|----------|------------|
| `"P1D"`  | 1 dia      |
| `"P7D"`  | 7 dias     |
| `"P1W"`  | 1 semana   |
| `"P1M"`  | 1 mês      |
| `"P1Y"`  | 1 ano      |

---

### Horas, Minutos e Segundos

| Notação      | Significado                      |
|-------------|----------------------------------|
| `"PT1H"`    | 1 hora                           |
| `"PT30M"`   | 30 minutos                       |
| `"PT45S"`   | 45 segundos                      |
| `"PT2H30M"` | 2 horas e 30 minutos             |
| `"PT1H15M10S"` | 1 hora, 15 minutos e 10 segundos |

---

### Exemplos Personalizados

| Notação         | Significado                              |
|----------------|----------------------------------------|
| `"P1DT12H"`    | 1 dia e 12 horas                      |
| `"P2W3DT4H30M"` | 2 semanas, 3 dias, 4 horas e 30 minutos |

Abaixo, você pode observar a implementação da API utilizando curl. Com isso você possui exemplos para poder adaptar adequadamente à linguagem de programação da sua preferência.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/account_monitoring/`
* Sandbox - `https://api.sandbox.caas.qitech.app/account_monitoring/`

No ambiente de Sandbox, as análises enviadas não são cobradas e são respondidas de acordo com regras pré estabelecidas.

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

## Autenticação

> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE_API_KEY"
```

> Substitua a API key 'EXAMPLE_API_KEY' com a sua chave adquirida com o nosso suporte.

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE_API_KEY`

:::info **Atenção**

Você deve substituir EXAMPLE_API_KEY com a API Key recebida do suporte.
:::

---

# Criação de Pessoas

URL: /documentation/caas/account_monitoring/person_registration

Para criar as pessoas de suas respectivas contas, deve-se manter a segregação entre endpoints de natural_person_account e legal_person_account.

Para solicitar a criação de uma para uma conta, basta enviar um objeto do tipo Person a um dos seguintes endpoints, respeitando a segregação feita no momento de criação de contas:

### Conta Pessoa Física

- Criação de Pessoa Física

`POST https://api.caas.qitech.app/account_monitoring/natural_person_account/{account_id}/natural_person`

> Exemplo

```json
{
    "id": "cc2f97ba-08c8-4a91-8d0d-49313a6c1245",
    "registration_date": "2024-11-04T13:37:00Z",
    "data": {
        "name": "John Doe",
        "document_number": "123.456.789-09",
        "birthdate": "2000-07-13"
    }
}
```
### Conta Pessoa Jurídica

- Criação de Pessoa Física

`POST https://api.caas.qitech.app/account_monitoring/legal_person_account/{account_id}/natural_person`

> Exemplo

```json
{
    "id": "cc2f97ba-08c8-4a91-8d0d-49313a6c1245",
    "registration_date": "2024-11-04T13:37:00Z",
    "data": {
        "name": "John Doe",
        "document_number": "123.456.789-09",
        "birthdate": "2000-07-13"
    }
}
```
O campo birthdate é obrigatório apenas para as contas que possuam monitoramento de status na receita federal, sendo necessário para consulta de pessoas menores de 18 anos.

- Criação de Pessoa Jurídica

`POST https://api.caas.qitech.app/account_monitoring/legal_person_account/{account_id}/legal_person`

> Exemplo

```json
{
    "id": "cc2f97ba-08c8-4a91-8d0d-49313a6c1245",
    "registration_date": "2024-11-04T13:37:00Z",
    "data": {
        "name": "Empresa das Tampas",
        "document_number": "12.482.243/0001-34"
    }
}
```

## Desativação e Reativação de Pessoas

Para desativar pessoas, a operação é análoga a realizada para contas, nos seguintes endpoints:

### Conta Pessoa Física

- Criação de Pessoa Física

`PATCH https://api.caas.qitech.app/account_monitoring/natural_person_account/{account_id}/natural_person`

> Exemplo

```json
{
    "new_person_status" : "deactivated"
}
```
### Conta Pessoa Jurídica

- Criação de Pessoa Física

`PATCH https://api.caas.qitech.app/account_monitoring/legal_person_account/{account_id}/natural_person`

> Exemplo

```json
{
    "new_person_status" : "deactivated"
}
```

- Criação de Pessoa Jurídica

`PATCH https://api.caas.qitech.app/account_monitoring/legal_person_account/{account_id}/legal_person`

> Exemplo

```json
{
    "new_person_status" : "deactivated"
}
```

Para reativar pessoas previamente desativadas, a operação é a mesma realizada para desativar pessoas, porém com o envio do new_person_status como 'active nos seguintes endpoints:

### Conta Pessoa Física

- Criação de Pessoa Física

`PATCH https://api.caas.qitech.app/account_monitoring/natural_person_account/{account_id}/natural_person`

> Exemplo

```json
{
    "new_person_status" : "active"
}
```
### Conta Pessoa Jurídica

- Criação de Pessoa Física

`PATCH https://api.caas.qitech.app/account_monitoring/legal_person_account/{account_id}/natural_person`

> Exemplo

```json
{
    "new_person_status" : "active"
}
```

- Criação de Pessoa Jurídica

`PATCH https://api.caas.qitech.app/account_monitoring/legal_person_account/{account_id}/legal_person`

> Exemplo

```json
{
    "new_person_status" : "active"
}
```

---

# Padrões

URL: /documentation/caas/account_monitoring/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões que são seguidos em toda a API.

## Data e Hora com Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12-03:00
2018-05-01T13:32:11+00:00
2019-05-01T00:00:00+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será valido. Por exemplo, se um aluguel estiver marcado para começar às 09:30 no aeroporto de Brasília, o horário enviado deverá ser representado por 09:30-03:00, se o aluguel estiver marcado para começar às 09:30 em Manaus, deverá ser representado por 09:30-04:00.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss±hh:mm`

## Data e Hora sem Fuso Horario
> Alguns exemplos:

```
2019-10-15T22:35:12Z
2018-05-01T13:32:11Z
2019-05-01T00:00:00Z
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão ser enviados sem ele, sempre em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ssZ`

## Data
> Alguns exemplos

``` 
2019-10-15
2019-01-01
2017-03-20
```

No caso de campos que recebem somente data, uma data de nascimento, por exemplo, somente a data, sem nenhum horário deve ser enviada com o seguinte formato:

`YYYY-MM-dd`
 

## Documentos
Uma vez que os números de documento são bastante variados e muitos deles possuem caracteres que não se enquadram como numéricos, definem-se todos os números de documento como string. Outro bom motivo para definí-los como string é evitar que os zeros à esquerda desapareçam. Documentos previstos nesta página possuem uma máscara bem definida e estarão sujeitos a validação. O restante dos documentos, como RG, dada sua falta de padronização, não serão validados.

## CPF

> Exemplos de CPFs válidos contra a máscara definida:

```
123.456.789-12
321.987.543-23
111.283.333-00
```

> Exemplos de CPFs inválidos contra a máscara definida:

```
8.577.477-8
08.104.627/0001-23
123.456.789-1
23.456.789-01
```

O CPF é sempre definido como uma string e será validado conta a máscara:

`###.###.###-##`

## CNPJ

> Exemplos de CNPJs válidos contra a máscara definida:

```
08.104.627/0001-02
01.079.210/0114-67
32.402.502/0001-35
```

> Exemplos de CNPJs inválidos contra a máscara definida:

```
8.577.477-8
123.456.789-12
321.987.543-23
32.402.502/0001-3
032.402.502/0001-3
```

O CNPJ é sempre definido como uma string e será validado conta a máscara:

`##.###.###/####-##`

---

# Webhook

URL: /documentation/caas/account_monitoring/webhook

Webhook

Atualizações nos tópicos de monitoramento serão notificadas por meio do envio de webhooks. Para tanto, é necessário, por meio da equipe do [suporte](mailto:suporte.caas@qitech.com.br), configurar um endereço do endpoint por onde vamos notificar as atualizações e também uma *signature_key* que será utilizada para assinar a requisição. Vale ressaltar que todos os envios de webhook serão feitos para um único endpoint.

:::info **Atenção**

Por questões de segurança, todas as requisições de Webhook serão somente realizadas em endpoints servidos por HTTPS.
:::

## Assinatura do Webhook

## Webhook de Atualização de Evento

Request Body

```json
{
    "person_type" : "natural_person",
    "account_type" : "natural_person_account",
    "person_id" : "22f5d028-0ce7-46f7-9b63-e7e38171b485",
    "account_id" : "e49ac344-f941-4668-9afb-a52ce4e5754a",
    "monitoring_topic" : "OFAC",
    "event" : "entered"
}
```

Abaixo está o significado de cada campo:

| Nome             | Tipo              | Descrição                                                          
|:----------------:|:-----------------:|-------------------------------------------------------------------------
| person_type      | string            | Tipo de pessoa (natural_person ou legal_person).                        
| account_type     | string            | Tipo de conta (natural_person_account ou legal_person_account).         
| person_id        | strin             | Identificador único da pessoa, passado na requisição de criação.       
| account_id       | string            | Identificador único da conta, passado na requisição de criação.        
| monitoring_topic | string            | Tópico monitorado em que ocorreu a mudança.                            
| event            | string            | Tipo de evento ocorrido, como "entered" (entrada) ou "exited" (saída) para os tópicos de listas restritivas. 

A requisição de atualização do tópico de monitoramento possui o formato acima e notifica a mudança no status de um dos tópico de monitoramento dentro da conta. O método utilizado é um PUT e o endereço do endpoint pode conter também o id do evento, de acordo com a necessidade do cliente. É importante ressaltar que o corpo da requisição é enviado como texto codificado em UTF-8.

## Retentativas

A notificação é considerada realizada quando recebe como resposta um HTTP Status 200. Caso as notificações falhem, serão feitas 7 retentativas, com os seguintes intervalos, até que um 200 seja retornado ou as tentativas terminem:

* 10 segundos
* 40 segundos
* 160 segundos
* 640 segundos
* 2560 segundos
* 10240 segundos
* 40960 segundos

---

# Criação de Sessão

URL: /documentation/caas/auth_session_manager/auth_session

O objeto de sessão de autenticação é uma entidade que representa o fluxo de autenticação do usuário. Através desse elemento, você poderá gerenciar o processo de coleta das informações de cadastro.

## Definição do Objeto Sessão de Autenticação

Request Body

```json
{
  "id": "12345678",
  "document_number": "111.111.111-11",
  "settings": {
    "steps": [
      {
        "step": "device_scan"
      },
      {
        "step":"face_recognition",
      },
      {
        "step":"personal_document",
        "show_success_screen": true,
        "show_introduction_screen": true,
        "document_templates":[
            "rg",
            "cnh",
            "cnh_digital"
        ]
      }
    ],
    "session_expiration_time_in_minutes": 120,
    "token_expiration_seconds": 3600,
    "open_mode": "iframe"
  }
}
```

Todas as trocas de informação de uma sessão utilizam a seguinte definição para este objeto

nome | tipo | descrição
:----: | :----: | ---------
id | string | Identificador da sessão. **É essencial que este número seja único para cada sessão** *(obrigatório)*
document_number | string | CPF do indivíduo sendo cadastrado, com pontos e hífens, de acordo com a padronização. *(obrigatório)*
settings | objeto | Objeto com as configurações personalizadas da sessão de autenticação. Caso não seja enviada, será utilizada a configuração padrão da empresa.

## Objeto settings

O objeto settings contém o campo `steps` que contempla a sequência das etapas de autenticação e suas respectivas configurações:
Os possíveis steps aceitos são:

* device_scan
* face_recognition
* personal_document

Além disso são aceitos os seguintes campos:

nome | tipo | descrição
:----: | :----: | ---------
session_expiration_time_in_minutes | integer | Data de expiração da sessão. Após essa data, a sessão não será válida.
token_expiration_seconds | interger | Tempos de expiração do token de sessão em segundos. (deve esstar entre 1 e 172800, máximo de 48 horas. O valor padrão é 1800)
open_mode | string | Define o modo de abertura da sessão, para a mensagem e botões do fuxo de finalização. (deve ser: "iframe" ou "link").

### device_scan

O step de device_scan indica a execução da coleta das informações do dispositivo. **Não possui configurações adicionais**

### face_recognition

O step de face_recognition indica a execução da coleta do fluxo de prova de vida através da biometria facial. **Não possui configurações adicionais**

### personal_document

O step de personal_document indica a execução da coleta do fluxo de OCR para leitura de documentos.

nome | tipo | descrição
:----: | :----: | ---------
document_templates | array | Lista de documentos que podem ser coletados no fluxo de cadastro. *(obrigatório)*
show_success_screen | boolean | Define a existência da tela de sucesso no fluxo de captura de documentos. Valor padrão `true`.
show_introduction_screen | boolean | Define a existência da tela de introdução no fluxo de captura de documentos. Valor padrão `true`.

Possíveis `document_templates` aceitos:

Nome | Tipo | Descrição
---- | ---- | ---------
cnh | string | Captura de CNH física FRENTE e VERSO (**fechada**), em duas etapas
rg | string | Captura de RG físico FRENTE e VERSO (**fechado**), em duas etapas
cnh_digital | string | Envio de CNH **digital** (pdf)
passport | string | Envio de Passapore FRENTE e VERSO (**fechada**), em duas etapas.
rne | string | Envio de Registro Nacional de Estrangeiros FRENTE e VERSO (**fechada**), em duas etapas.
crnm | string | Envio de Carteira de Registro Nacional Migratório FRENTE e VERSO (**fechada**), em duas etapas.
ctps | string | Envio de Carteira de Trabalho e Previdência Social FRENTE e VERSO (**fechada**), em duas etapas.
others | string | Envio de qualquer documento **isento de validação** FRENTE e VERSO (**fechada**), em duas etapas.

## Enviar um Auth Session

Request Body

```json
  {
    "id": "12345",
    ...
  }
```

Response Body

```json
  {
    "id": "12345678",
    "status": "pending",
    "expiration_date": "2025-12-11T11:37:15.12-03:00",
    "settings": {
      ...
    },
    "auth_session_hash": "1cFL1vM",
    "step": "device_scan",
    "auth_session_url": "https://auth-session.production.caas.qitech.app/s/1cFL1vM/t/fc0bae39-1c41-4bc2-a5a1-39a7ca01121b",
    "token": "fc0bae39-1c41-4bc2-a5a1-39a7ca01121b",
    "token_expiration_date": "2025-12-10T11:37:15.12-03:00",
  }
```

Para realizar a criação de uma sessão, basta enviar um objeto do tipo Auth Session ao seguinte endpoint:

`POST https://api.caas.qitech.app/auth_session_manager/auth_session`

---

# Autenticação

URL: /documentation/caas/auth_session_manager/authentication

> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> Substitua a API Key 'EXAMPLE-OF-API-KEY' pela sua chave, que deve ser obtida através do nosso time de suporte.

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE-OF-API-KEY`

:::info **Atenção**

Você deve substituir EXAMPLE-OF-API-KEY pela sua chave, que deve ser obtida através do nosso time de suporte.
:::

---

# Status HTTP

URL: /documentation/caas/auth_session_manager/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/auth_session_manager/introduction

Bem vindo à API de Gerenciamento de Sessões de Autenticação da QI Tech! Esta api foi projetada para controlar o fluxo completo de KYC do usuário!

Este serviço organiza o processo de autenticação. Possibilitando a criação de sessões de cadastro KYC com fluxos personalizados e uso dos demais serviços de autenticação da QI Tech:

* Device Scan
* Face Recognition
* OCR

Desse modo, é possível iniciar o fluxo de coleta das informações de cadastro através do link retornado pela API.
Assim que iniciada, a página web será responsável por guiar o usuário a executar as etapas de KYC definidas naquela sessão. 

Além disso, por estar diretamente integrada com os demais serviços descritos acima, ela é capaz de coletar as informações necessárias para a finalização do fluxo de autenticação. Com essas informações, será possível efetuar a análise desejada nos demais serviços da QI Tech, como o cadastro de pessoa física ou uma análise pré transacional, por exemplo.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já notou), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/auth_session_manager/`
* Sandbox - `https://api.sandbox.caas.qitech.app/auth_session_manager/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

No ambiente de Sandbox, as análises enviadas não são cobradas e são respondidas de acordo com a regra configurada para o evento.

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

---

# Gestão de Sessão

URL: /documentation/caas/auth_session_manager/retrieve_session

Ao criar uma sessão de autenticação, basta utilizar o link gerado para iniciar o fluxo de cadastro do usuário. Isso pode ser feito através do envio do link ou do uso dele diretamente em seu website, com ferramentas como `iframe`.

## Objeto de retorno

O objeto de retorno da criação e resgate de uma `auth_session` contém as seguintes informações:

Response Body

```json
  {
    "id": "12345678",
    "status": "pending",
    "expiration_date": "2025-12-11T11:37:15.12-03:00",
    "step_data": {
      "face_recognition": {
        "image_key": "65441d8d-015a-4a0f-97b6-b7d4fc5619b7",
        "event_date": "2025-12-11T11:37:15.12-03:00"
      },
      "personal_document": {
          "document_template": "rg",
          "ocr_keys": [
            "e13c71d0-ae0e-48e2-8c42-26f997412039",
            "3991b716-0980-409f-8e33-e3a8dd9a671c"
          ],
          "event_date": "2025-12-11T11:37:15.12-03:00"
      },
      "device_scan": {
          "session_id":  "4d450227-c77c-4487-830b-42dcd127798a",
          "event_date": "2025-12-11T11:37:15.12-03:00"
      }
    }
    "settings": {
      ...
    },
    "auth_session_hash": "1cFL1vM",
    "step": "device_scan",
    "auth_session_url": "https://auth-session.production.caas.qitech.app/s/1cFL1vM/t/fc0bae39-1c41-4bc2-a5a1-39a7ca01121b",
    "token": "fc0aaa39-1c21-1bc1-a5a1-39a7ca01121b",
    "token_expiration_date": "2025-12-10T11:37:15.12-03:00",
  }
```

Esse objeto é retornado no enpoint de resgate da sessão:

`GET https://api.caas.qitech.app/auth_session_manager/auth_session/{id}`

Descrição do campos de resposta:

nome | tipo | descrição
:----: | :----: | ---------
id | string | Id da sessão.
status | string | Status da sessão.
expiration_date | date | Data de expiração da sessão. Após essa data, a sessão é invalidada.
step_data | object | Objeto de retorno dos eventos da sessão.
settings | object | Objeto de configuração da sessão.
auth_session_hash | string | Hash de identificação da sessão.
step | string | Etapa atual do usuário.
auth_session_url | string | Url capaz de coletar as informações do cadastro.
token | string | Token de autenticação da sessão.
token_expiration_date | date | Data de expiração do token temporário de autenticação. Padrão definido para 2 horas após a geração da sessão.

### Status

Possíveis status:

* pending
* completed
* expired

### Objeto step_data

Objeto que contém os dados coletados de cada step.

:::info Informação
Caso o step não esteja listado nas settings da sessão, o mesmo não estará presente como campo do objeto `step_data`
:::

`face_recognition`

Nome | Tipo | Descrição
---- | ---- | ---------
image_key | string | Chave de identificação da etapa de face_recognition.
event_date | date | Data de finalização da etapa.

`personal_document`

Nome | Tipo | Descrição
---- | ---- | ---------
document_template | string | Template selecionado pelo usuário no momento da coleta do documento.
ocr_keys | list | Lista com as chaves de identificação de cada documento coletado.
event_date | date | Data de finalização da etapa.

`device_scan`

Nome | Tipo | Descrição
---- | ---- | ---------
session_id | string | Chave de identificação da etapa de scan do dispositivo.
event_date | date | Data de finalização da etapa.

## Autenticação do fluxo web

Para garantir mais segurança para a aplicação, retornamos um token temporário para a página web.
É possível resgatar o token, ou gerar um novo através do endpoint:

`POST https://api.caas.qitech.app/auth_session_manager/auth_session/{id}/token`

Request Body

```json
  {
    "token_expiration_seconds": 3600
  }
```

O objeto de token tem somente um campo opcional:

Nome | Tipo | Descrição
---- | ---- | ---------
token_expiration_seconds | interger | Tempos de expiração do token de sessão em segundos. (deve esstar entre 1 e 172800, máximo de 48 horas. O valor padrão é 1800)

Response Body

```json
  {
    "id": "12345678",
    "token": "e7e99a40-0b26-4bb9-a068-9fa4886eeef3",
    "token_expiration_date": "2025-12-10T13:37:15.12-03:00",
  }
```

Assim, caso o token tenha expirado, é possível seguir com a sessão de autenticação gerando um novo token.

# Webhook

A finalização da sessão será notificada por meio do envio de webhook. Para tanto, é necessário, por meio da equipe do [suporte](mailto:suporte.caas@qitech.com.br), configurar um endereço do endpoint por onde vamos notificar as atualizações e também uma *signature_key* que será utilizada para assinar a requisição. Vale ressaltar que todos os envios de webhook serão feitos para um único endpoint.

:::info **Atenção**

Por questões de segurança, todas as requisições de Webhook serão somente realizadas em endpoints servidos por HTTPS.
:::

## Comunicação com a página web

A página web poderá ser integrada através de uma ferramenta chamada `iframe`. Da seguinte maneira:

```html
<iframe id="iframe" src="" href="{auth_session_url}" allow="camera; microphone" referrerPolicy="no-referrer"></iframe>
```

> ⚠️ **Configuração Obrigatória**
>
> Para que o iframe funcione corretamente em **produção** (`auth-session.caas.qitech.app`) e **sandbox** (`auth-session.sandbox.caas.qitech.app`), é necessário configurar o seguinte header de Permissions-Policy:
>
> **Configuração com URLs específicas (recomendado):**
> ```json
> {
>   "key": "Permissions-Policy",
>   "value": "geolocation=(self \"https://auth-session.caas.qitech.app\" \"https://auth-session.sandbox.caas.qitech.app\"), microphone=(self \"https://auth-session.caas.qitech.app\" \"https://auth-session.sandbox.caas.qitech.app\"), camera=(self \"https://auth-session.caas.qitech.app\" \"https://auth-session.sandbox.caas.qitech.app\"), fullscreen=(self \"https://auth-session.caas.qitech.app\" \"https://auth-session.sandbox.caas.qitech.app\")"
> }
> ```
>
> **Configuração alternativa (menos restritiva):**
> ```json
> {
>   "key": "Permissions-Policy",
>   "value": "geolocation=*, microphone=*, camera=*, fullscreen=()"
> }
> ```
>
> Essa configuração deve ser aplicada no servidor que hospeda a página que contém o iframe para garantir que as permissões necessárias sejam concedidas.

Caso o link seja chamado dessa maneira, a página web irá enviar mensagens de retorno para a página que a requisitou. As possíveis mensagens de retorno são:

* success
* canceled
* invalid_token
* expired

Que podem ser acessadas da seeguinte maneira:

```javascript
window.addEventListener("message", (event) => {
            if (event.data === "canceled") {
              //close iframe
            }
            if (event.data === "invalid_token") {
              //close iframe
            }
            if (event.data === "success") {
              //close iframe
            }  
            if (event.data === "expired") {
              //close iframe
            }
        });
```

## Finalização do fluxo

Este serviço irá gerenciar o fluxo de coleta de dados de autenticação, que poderão ser utilizados nos demais serviços. 
Para mais informações de como utilizar as chaves retornadas nos demais produtos, segue o exemplo da análise cadastral de pessoa física [Análise Cadastral](/documentation/caas/onboarding/query_registration)

---

# Boleto

URL: /documentation/caas/banking/bankslips

No momento em que um usuário efetuar ou receber um pagamento por boleto, os dados do pagamento deverão ser enviados para a QI Tech. Deste modo, será possível realizar uma análise do risco envolvido na operação, baseado naquele conjunto de dados.

## Definição do Objeto de Boleto

Request Body

```json
{
    "id": "082373263",
    "bankslip_direction": "received",
    "document_amount": 13725,
    "discount_amount": 1000,
    "other_deduction_amount": 0,
    "interest_amount": 254,
    "amount": 12979,
    "bankslip_payment_date": "2020-10-07T15:06:25-03:00",
    "bankslip_due_date": "2020-10-07",
    "bankslip_issuing_date": "2020-10-07",
    "description": "BOLETO PARA PAGAMENTO DA MENSALIDADE DE SETEMBRO",
    "face_recognition_key": "ef39e206-13d5-48de-b368-6c3bbc6f0222",
    "validation_key": "69a59de3-0198-4a26-933a-c1de624c147d",
    "payer": {
        "id": "182373263",
        "type": "legal_person",
        "document_number": "07.487.735/0001-69",
        "name": "Gioconda Pizzaria e Rotisseria LTDA.",
        "address": {
            "street": "Avenida 13",
            "number": "704",
            "neighbourhood": "Centro",
            "city": "Ituiutaba",
            "uf": "MG",
            "complement": "Apt 1101",
            "postal_code": "38300-140"
        },
        "phone": {
            "international_dial_code": "55",
            "area_code": "16",
            "number": "981610077",
            "type": "mobile"
        },
        "email": "mailto@qitech.com.br",
        "account": {
            "participant": "60701190",
            "branch": "3675",
            "account_number": "13212",
            "account_digit": "5",
            "account_type": "CACC"
        },
        "sales_channel": "inbound_sales",
        "segment": "Personalité"
    },
    "recipient": {
        "id": "282373263",
        "type": "legal_person",
        "document_number": "056.966.649-03",
        "name": "Francisco Oliveira Benedetti",
        "address": {
            "street": "Avenida 13",
            "number": "704",
            "neighbourhood": "Centro",
            "city": "Ituiutaba",
            "uf": "MG",
            "complement": "Apt 1101",
            "postal_code": "38300-140"
        },
        "phone": {
            "international_dial_code": "55",
            "area_code": "16",
            "number": "981610077",
            "type": "mobile"
        },
        "account": {
            "participant": "60701190",
            "branch": "3675",
            "account_number": "10552",
            "account_digit": "6",
            "account_type": "CACC"
        }
    },
    "final_recipient": {
        "id": "382373263",
        "type": "legal_person",
        "document_number": "056.966.649-03",
        "name": "Francisco Oliveira Benedetti",
        "address": {
            "street": "Avenida 13",
            "number": "704",
            "neighbourhood": "Centro",
            "city": "Ituiutaba",
            "uf": "MG",
            "complement": "Apt 1101",
            "postal_code": "38300-140"
        },
        "phone": {
            "international_dial_code": "55",
            "area_code": "16",
            "number": "981610077",
            "type": "mobile"
        },
        "account": {
            "participant": "60701190",
            "branch": "3675",
            "account_number": "10442",
            "account_digit": "6",
            "account_type": "CACC"
        }
    },
    "source": {
        "channel": "internet_banking",
        "platform": "android",
        "ip": "198.185.056.098",
        "session_id": "7839jdqd9a8wd9"
    }
}
```

Um pagamento de boleto deve ser enviado para a API antes de ser encaminhada para o sistema de processamento, a fim de realizar uma validação prévia de fraude.

O status do pagamento representa a decisão retornada pelo modelo sobre aquele boleto. Os seguintes status são utilizados na flag **analysis_status**:

* `automatically_approved`
* `automatically_reproved`
* `in_manual_analysis`
* `pending`

Abaixo estão listados os significados de cada uma das decisões, devolvida na flag analysis_status:

status | descrição
:----: | ---------
automatically_approved      | Recomenda-se que este pagamento de boleto seja aprovado.
automatically_reproved      | Recomenda-se que este pagamento de boleto seja reprovado.
in_manual_analysis          | Recomenda-se que este pagamento de boleto seja analisado manualmente.
pending                     | O pagamento de boleto está sendo processado.

nome | tipo | descrição
:----:  | :----:  | ---------
id | string | Identificador da transação no sistema do cliente. **É essencial que este número seja único para cada pagamento de boleto**
bankslip_direction        | enumerador                | Modalidade do pagamento do boleto. Define se o cliente está pagando o boleto ou recebendo o pagamento do boleto.
document_amount         | inteiro                   | Valor do documento em centavos - conforme descrição da seção "Padrões".
discount_amount          | inteiro                   | Valor do desconto ou abatimento aplicado sobre o valor do documento em centavos - conforme descrição da seção "Padrões".
other_deduction_amount  | inteiro                   | Valor das outras deduções aplicadas sobre o valor do documento em centavos - conforme descrição da seção "Padrões".
interest_amount         | inteiro                   | Valor da multa, mora ou juros aplicados sobre o valor do documento em centavos - conforme descrição da seção "Padrões".
amount                  | inteiro                   | Valor final pago no boleto - conforme descrição da seção "Padrões".
bankslip_payment_date     | datetime                  | A data e hora do pagamento do boleto, com fuso horário.
bankslip_due_date         | date                      | Data de vencimento do boleto de acordo com a padronização
description             | string                    | Campo descrição ou observações do boleto.
face_recognition_key    | string                    | Chave de reconhecimento facial, caso tenha sido feito reconhecimento facial pela nossa API de reconhecimento facial.
validation_key          | string                    | Chave de validação, caso tenha sido feita algum teste de validação do cliente em nossa API de validações.
payer                   | *bankslip_payer*            | Objeto que representa a pessoa física ou pessoa jurídica que pagou o boleto.
recipient               | *bankslip_recipient*        | Objeto que representa a pessoa física ou pessoa jurídica beneficiária do boleto.
final_recipient         | *bankslip_recipient*        | Objeto que representa a pessoa física ou pessoa jurídica beneficiária final do boleto.
source                  | *source*                  | Objeto do tipo Source que descreve as informações provenientes da aplicação utilizada para o pagamento do boleto.

Existem os seguintes enumeradores para *bankslip_direction*: `payed` e `received`.

## Enviar um Pagamento de Boleto

Request Body

```json
  {
    "id": "12345",
    ...
  }
```

Response Body

```json
  {
    "bankslip_key": "13d680ef-4b72-4cb2-a63d-cf3d790abaaf",
    "status": "automatically_approved",
    "reason": "rule_decision_enum"
  }
```

Para realizar a avaliação de um pagamento de boleto, basta enviar um objeto do tipo Boleto ao seguinte endpoint:

`POST https://api.caas.qitech.app/bankslip/bankslip`

## Recuperar um Pagamento de Boleto

Response Body

```json
  {
    "id": "082373263",
    "bankslip_direction": "received",
    ...
  }
```

Para recuperar os dados de um pagamento de boleto, basta enviar uma requisição ao seguinte endpoint:

`GET https://api.caas.qitech.app/bankslip/bankslip/{bankslip_id}`

Onde *bankslip_id* é o identificador da transação no sistema do cliente utilizado no envio do boleto.

## Atualizar um pagamento de boleto

Request Body

```json
  {
    "bankslip_status": "completed",
    "event_date": "2020-10-07T15:06:25-03:00"
  }
```

Response Body

```json
  {
    "bankslip_key": "13d680ef-4b72-4cb2-a63d-cf3d790abaaf",
    "bankslip_status": "completed"
  }
```

Após um pagamento de boleto ser criado e analisado, ela será enviado à câmara de compensação para ser processado. Deste modo, é necessário que seja informada a atualizações de status do pagamento quando este for enviado, através do endpoint:

`PUT https://api.caas.qitech.app/bankslip/bankslip/{bankslip_id}`

Deste modo, garante-se que nossa base de dados seja atualizada e sejamos capazes de identificar os pagamentos de boleto que estejam realmente sucetíveis a fraude.

---

# Pagamento de Contas

URL: /documentation/caas/banking/bill_payments

No momento em que um usuário efetuar um pagamento de contas, os dados do pagamento deverão ser enviados para a QI Tech. Deste modo, será possível realizar uma análise do risco envolvido na operação, baseado naquele conjunto de dados.

## Definição do Objeto de Pagamento de Contas

Request Body

```json
{
    "id": "082373263",
    "amount": 12979,
    "bill_payment_date": "2020-10-07T15:06:25-03:00",
    "bill_due_date": "2020-10-07",
    "bill_issuing_date": "2020-10-07",
    "service_description": "CONTA DE ELETRICIDADE ENEL",
    "face_recognition_key": "ef39e206-13d5-48de-b368-6c3bbc6f0222",
    "validation_key": "69a59de3-0198-4a26-933a-c1de624c147d",
    "company": {
        "id": "451673263",
        "provided_service": "eletricity", 
        "name" : "Enel",
        "legal_name": "Eletropaulo Metropolitana Eletricidade de São Paulo S.A.",
        "document_number": "61.695.227/0001-93",
        "address": {
            "street": "Av. Dr. Marcos Penteado de Ulhôa Rodrigues",
            "number": "939",
            "neighbourhood": "Sítio Tamboré",
            "city": "Barueri",
            "uf": "SP",
            "complement": "Loja 1 e 2",
            "postal_code": "06460-040"
        }
    },
    "payer": {
        "id": "182373263",
        "type": "legal_person",
        "document_number": "07.487.735/0001-69",
        "name": "Gioconda Pizzaria e Rotisseria LTDA.",
        "email": "gioconda_pizza@bol.com.br",
        "address": {
            "street": "Avenida 13",
            "number": "704",
            "neighbourhood": "Centro",
            "city": "Ituiutaba",
            "uf": "MG",
            "complement": "Apt 1101",
            "postal_code": "38300-140"
        },
        "phone": {
            "international_dial_code": "55",
            "area_code": "16",
            "number": "981610077",
            "type": "mobile"
        },
        "account": {
            "participant": "60701190",
            "branch": "3675",
            "account_number": "13212",
            "account_digit": "5",
            "account_type": "CACC"
        },
        "sales_channel": "inbound_sales",
        "segment": "Personalité"
    },
    "source": {
        "channel": "internet_banking",
        "platform": "android",
        "ip": "198.185.105.098",
        "session_id": "7839jdqd9a8wd9"
    }
}
```

Um pagamento de conta deve ser enviado para a API antes de ser encaminhada para o sistema de processamento, a fim de realizar uma validação prévia de fraude.

O status do pagamento representa a decisão retornada pelo modelo sobre aquela conta. Os seguintes status são utilizados na flag **analysis_status**:

* `automatically_approved`
* `automatically_reproved`
* `in_manual_analysis`
* `pending`

Abaixo estão listados os significados de cada uma das decisões, devolvida na flag analysis_status:

status | descrição
:----: | ---------
automatically_approved      | Recomenda-se que este pagamento de conta seja aprovado.
automatically_reproved      | Recomenda-se que este pagamento de conta seja reprovado.
in_manual_analysis          | Recomenda-se que este pagamento de conta seja analisado manualmente.
pending                     | O pagamento de conta está sendo processado.

nome | tipo | descrição
:----:  | :----:  | ---------
id | string | Identificador da transação no sistema do cliente. **É essencial que este número seja único para cada pagamento de conta**
document_amount         | inteiro                   | Valor do documento em centavos - conforme descrição da seção "Padrões".
other_deduction_amount  | inteiro                   | Valor das outras deduções aplicadas sobre o valor do documento em centavos - conforme descrição da seção "Padrões".
interest_amount         | inteiro                   | Valor da multa, mora ou juros aplicados sobre o valor do documento em centavos - conforme descrição da seção "Padrões".
amount                  | inteiro                   | Valor final pago no conta - conforme descrição da seção "Padrões".
bill_payment_date     | datetime                  | A data e hora do pagamento do conta, com fuso horário.
bill_due_date         | date                      | Data de vencimento do conta de acordo com a padronização
description             | string                    | Campo descrição ou observações do conta.
face_recognition_key    | string                    | Chave de reconhecimento facial, caso tenha sido feito reconhecimento facial pela nossa API de reconhecimento facial.
validation_key          | string                    | Chave de validação, caso tenha sido feita algum teste de validação do cliente em nossa API de validações.
client                  | *client*                  | Objeto que representa os dados do cliente, seja ele o cliente que está efetuando o pagamento do boleto ou o recebendo o pagamento.
company                 | *company*                 | Objeto que representa a concessionária ou prestador de serviço referente àquela conta.
payer                   | *bill_payer*              | Objeto que representa a pessoa física ou pessoa jurídica que pagou a conta.
recipient               | *bill_client*             | Objeto que representa a pessoa física ou pessoa jurídica para quem a conta foi emitida.
source                  | *source*                  | Objeto do tipo Source que descreve as informações provenientes da aplicação utilizada para o pagamento da conta.

## Enviar um Pagamento de Conta

Request Body

```json
  {
    "id": "12345",
    ...
  }
```

Response Body

```json
  {
    "bill_payment_key": "13d680ef-4b72-4cb2-a63d-cf3d790abaaf",
    "status": "automatically_approved",
    "reason": "rule_decision_enum"
  }
```

Para realizar a avaliação de um pagamento de conta, basta enviar um objeto do tipo BillPayment ao seguinte endpoint:

`POST https://api.caas.qitech.app/bill_payment/bill_payment`

## Recuperar um Pagamento de Conta

Response Body

```json
  {
    "id": "082373263",
    "amount": 12979,
    ...
  }
```

Para recuperar os dados de um pagamento de conta, basta enviar uma requisição ao seguinte endpoint:

`GET https://api.caas.qitech.app/bill_payment/bill_payment/{bill_payment_id}`

Onde *bill_payment_id* é o identificador da transação no sistema do cliente utilizado no envio do pagamento de conta.

## Atualizar um pagamento de conta

Request Body

```json
  {
    "bill_payment_status": "completed",
    "event_date": "2020-10-07T15:06:25-03:00"
  }
```

Response Body

```json
  {
    "bill_payment_key": "13d680ef-4b72-4cb2-a63d-cf3d790abaaf",
    "bill_payment_status": "completed"
  }
```

Após um pagamento de conta ser criado e analisado, ela será enviado à câmara de compensação para ser processado. Deste modo, é necessário que seja informada a atualizações de status do pagamento quando este for enviado, através do endpoint:

`PUT https://api.caas.qitech.app/bill_payment/bill_payment/{bill_payment_id}`

Deste modo, garante-se que nossa base de dados seja atualizada e sejamos capazes de identificar os pagamentos que estejam realmente sucetíveis a fraude.

---

# Depósitos

URL: /documentation/caas/banking/deposits/introduction

No momento em que um usuário efetuar um depósito, os dados do depósito deverão ser enviados para a QI Tech. Deste modo, será possível realizar uma análise do risco de fraude e Prevenção a Lavagem de Dinheiro envolvido na operação, baseado naquele conjunto de dados.

## Definição do Objeto de Depósito

Request Body

```json
{
    "id": "082373263",
    "amount": 12979,
    "deposit_date": "2020-10-07T15:06:25-03:00",
    "client": {
        "id": "182373263",
        "type": "natural_person",
        "document_number": "123.456.789-10",
        "name": "Benedito Calixto de Jesus",
        "email": "benedito@test.com",
        "address": {
            "street": "Rua José Wasth Rodrigues",
            "number": "243",
            "neighbourhood": "Vila Maria",
            "city": "São Paulo",
            "uf": "SP",
            "complement": "Apartamento 14B",
            "postal_code": "02121-010"
        },
        "phone": {
            "international_dial_code": "55",
            "area_code": "11",
            "number": "998861708",
            "type": "mobile"
        },
        "sales_channel": "inbound_sales",
        "segment": "Personalité"
    },
    "destination_account": {
        "participant": "17315359",
        "branch": "0000",
        "account_number": "10442",
        "account_digit": "6",
        "account_type": "CACC",
        "opening_date": "2020-01-15T18:00:00-03:00"
    },
    "terminal": {
        "id": "1234566",
        "latitude": -45.2753548,
        "longitude": -15.24587,
        "address": { 
            "street": "Av. Eng. Luis Carlos Berrini",
            "number": "105",
            "neighbourhood": "Brooklin",
            "city": "São Paulo",
            "uf": "SP",
            "complement": "Cj 303",
            "postal_code": "04501-140"
        },
        "type": "atm"
    },
    "authentication": {
        "used_password": true,
        "used_card": true,
        "used_fingerprint": true,
        "typed_account_number": false
    }
}
```

Um depósito deve ser enviado para a API antes de ser encaminhada para o sistema de processamento, a fim de realizar uma validação prévia de fraude.

O status do depósito representa a decisão retornada pelo modelo sobre aquela conta. Os seguintes status são utilizados na flag **analysis_status**:

* `automatically_approved`
* `automatically_reproved`

Abaixo estão listados os significados de cada uma das decisões, devolvida na flag analysis_status:

status | descrição
:----: | ---------
automatically_approved      | Recomenda-se que este depósito seja aprovado.
automatically_reproved      | Recomenda-se que este depósito seja reprovado.

nome | tipo | descrição
:----:  | :----:  | ---------
id | string | Identificador do depósito no sistema do cliente. **É essencial que este número seja único para cada depósito**
amount                      | integer                   | Valor do depósito em centavos - conforme descrição da seção "Padrões".
deposit_date                | datetime                  | Data e hora da realização do depósito - conforme descrição da seção "Padrões".
client                      | *client*                  | Objeto com os dados do cliente detentor da conta de origem.
destination_account         | *account*                 | Objeto que determina a conta de destino do recurso a ser depositado.
terminal                    | *terminal*                | Objeto com os dados do terminal onde o depósito está sendo realizado.
authentication              | *authentication*          | Objeto com as informações de autenticação.

## Objetos do Depósito

### Objeto Terminal

Request Body

```json
{
    "id": "1234566",
    "latitude": -45.2753548,
    "longitude": -15.24587,
    "address": { 
        "street": "Av. Eng. Luis Carlos Berrini",
        "number": "105",
        "neighbourhood": "Brooklin",
        "city": "São Paulo",
        "uf": "SP",
        "complement": "Cj 303",
        "postal_code": "04501-140"
    },
    "type": "atm"
}
```

Objeto que representa o terminal que foi utilizado para o depósito.

nome | tipo | descrição
:----:  | :----:  | ---------
id                          | string                    | Identificador do terminal no sistema do cliente
latitude                    | number                    | Latitude, em graus, da localização do terminal
longitude                   | number                    | Longitude, em graus, da localização do terminal
address                     | *address*                 | Endereço do terminal
type                        | enum                      | Tipo do terminal, possíveis valores: "atm", "counter"

### Objeto Authentication

Request Body

```json
{
    "used_password": true,
    "used_card": true,
    "used_fingerprint": true,
    "typed_account_number": false
}
```

Objeto que define os parâmetros da autenticação utilizada no momento do depósito.

nome | tipo | descrição
:----: | :----: | -----------
used_password               | boolean                           | Determina se o usuário utilizou senha
used_card                   | boolean                           | Determina se o usuário está com o cartão presente na autenticação
used_card_chip_and_pin      | boolean                           | Determina se o usuário utilizou o chip e senha do cartão
used_card_magnetic_stripe   | boolean                           | Determina se o usuário utilizou a tarja magnética do cartão
used_fingerprint            | boolean                           | Determina se o usuário utilizou fingerprint
typed_account_number        | boolean                           | Determina se o usuário digitou os dados da conta

## Enviar um Depósito

Request Body

```json
  {
    "id": "12345",
    ...
  }
```

Response Body

```json
  {
		"id": "082373263",
    "analysis_status": "automatically_approved",
    "reason": "2019-10-01T10:37:25-03:00"
  }
```

Para realizar a avaliação de um depósito, basta enviar um objeto do tipo deposit ao seguinte endpoint:

`POST https://api.caas.qitech.app/deposit/deposit`

## Recuperar um Depósito

Response Body

```json
  {
		"id": "082373263",
    "analysis_status": "automatically_approved",
    "reason": "2019-10-01T10:37:25-03:00"
  }
```

Para recuperar os dados de um depósito, basta enviar uma requisição ao seguinte endpoint:

`GET https://api.caas.qitech.app/deposit/deposit/{deposit_id}`

Onde *deposit_id* é o identificador da transação no sistema do cliente utilizado no envio do depósito.

## Atualizar um depósito

Request Body

```json
  {
    "deposit_status": "completed",
    "event_date": "2020-10-07T15:06:25-03:00"
  }
```

Response Body

```json
  {
		"id": "082373263",
    "deposit_status": "completed"
  }
```

Após um depósito ser criado e analisado, o dinheiro será disponibilizado ao usuário. Este processo pode ser interrompido por alguma outra regra de negócio. Deste modo, é necessário que seja informada a atualizações de status do saque quando este for finalizado, através do endpoint:

`PUT https://api.caas.qitech.app/deposit/deposit/{deposit_id}`

Deste modo, garante-se que nossa base de dados seja atualizada e sejamos capazes de identificar os depósitos que estejam realmente sucetíveis a fraude.

---

# Status HTTP

URL: /documentation/caas/banking/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/banking/introduction

Bem vindo à API de Banking da QI Tech! Esta API dá acesso à funcionalidade de prevenção a fraudes para operações de bancos e contas digitais, como por exemplo análises de transferências, pagamentos de contas e pagamentos de boletos.

Abaixo, você pode observar a implementação da API utilizando cUrl. Com isso você possui exemplos para poder adaptar adequadamente à linguagem de programação da sua preferência.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já notou), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/`
* Sandbox - `https://api.sandbox.caas.qitech.app/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

## Análises no ambiente de Sandbox

No ambiente de Sandbox, as análises não são cobradas e são respondidas de acordo com regras simplificadas.
Para o caso de *wire_transfers*, *bankslips*, *bill_payments* e *pix*, a resposta dada será baseada no valor da operação (*amount*) enviado na requisição:

mínimo | máximo | decisão
------ | ------ | -------
16000 | - | Contestado Automaticamente*
10000 | 15999 | Aprovado Automaticamente
6000 | 9999 | Derivado para Análise Manual
0 | 5999 | Reprovado Automaticamente

\* Contestado Automaticamente está disponível apenas para o serviço de *pix*.

Para o caso de *withdrawal* e *deposit* a resposta dada será baseada no valor da operação (*amount*) enviado na requisição:

mínimo | máximo | decisão
------ | ------ | -------
10000 | - | Aprovado Automaticamente
0 | 9999 | Reprovado Automaticamente

No caso de operações na DICT, a resposta dada será baseada na chave de vínculo na DICT (*dict_key*) enviada na requisição:

chave na Dict | decisão
:----------: | -------
"Approve_dict_key"      | Aprovado Automaticamente
Qualquer outra string   | Derivado para Análise Manual
"Reprove_dict_key"      | Reprovado Automaticamente

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

## Fluxos - Transferências

O fluxo de análise de transferências é iniciado em duas situações:

- Uma transferência está sendo efetuada pelo usuário do PSP
- Uma transferência está sendo recebida pelo usuário do PSP

Em ambos os casos, uma chamada ao endpoint de *wire_transfer* deve ser realizada e os possíveis status resultantes são:

enumerador | descrição
:--------: | ---------
automatically_approved | Aprovado Automaticamente
automatically_reproved | Reprovado Automaticamente
in_manual_analysis     | Derivado para Análise Manual
pending                | O objeto de transferência bancária está sendo processado.

Caso a transferência seja derivada para análise manual, um analista deverá aprovar ou reprovar a transferência. Neste momento, um Webhook pode ser gerado para notificar a alteração de status ao PSP ou o PSP pode acompanhar a transferência por meio de Polling. Em ambos os casos, os seguintes status podem ser retornados:

enumerador | descrição
:--------: | ---------
manually_approved | Aprovado Manualmente
manually_reproved | Reprovado Manual

## Fluxos - Boletos

O fluxo de análise de Boletos é iniciado em duas situações:

- Um pagamento de boleto está sendo efetuado pelo usuário do PSP
- Um pagamento de boleto está sendo recebido pelo usuário do PSP

Em ambos os casos, uma chamada ao endpoint de *bankslip* deve ser realizada e os possíveis status resultantes são:

enumerador | descrição
:--------: | ---------
automatically_approved | Aprovado Automaticamente
automatically_reproved | Reprovado Automaticamente
in_manual_analysis     | Derivado para Análise Manual
pending                | O objeto de boleto está sendo processado.

Caso o pagamento de boleto seja derivado para análise manual, um analista deverá aprovar ou reprovar o pagamento. Neste momento, um Webhook pode ser gerado para notificar a alteração de status ao PSP ou o PSP pode acompanhar o pagamento por meio de Polling. Em ambos os casos, os seguintes status podem ser retornados:

enumerador | descrição
:--------: | ---------
manually_approved | Aprovado Manualmente
manually_reproved | Reprovado Manual

## Fluxos - Pagamentos de Contas

O fluxo de análise de Pagamentos de Contas é iniciado quando:

- Um pagamento de conta está sendo efetuado pelo usuário do PSP

Neste caso uma chamada ao endpoint de *bill_payment* deve ser realizada e os possíveis status resultantes são:

enumerador | descrição
:--------: | ---------
automatically_approved | Aprovado Automaticamente
automatically_reproved | Reprovado Automaticamente
in_manual_analysis     | Derivado para Análise Manual
pending                | O objeto de pagamento de contas está sendo processado.

Caso o pagamento de conta seja derivado para análise manual, um analista deverá aprovar ou reprovar o pagamento. Neste momento, um Webhook pode ser gerado para notificar a alteração de status ao PSP ou o PSP pode acompanhar o pagamento por meio de Polling. Em ambos os casos, os seguintes status podem ser retornados:

enumerador | descrição
:--------: | ---------
manually_approved | Aprovado Manualmente
manually_reproved | Reprovado Manual

## Fluxos - Saques

O fluxo de análise de Saques é iniciado na seguinte situação:

- Um saque está sendo efetuado pelo usuário do PSP

Em ambos os casos, uma chamada ao endpoint de *withdrawal* deve ser realizada e os possíveis status resultantes são:

enumerador | descrição
:--------: | ---------
automatically_approved | Aprovado Automaticamente
automatically_reproved | Reprovado Automaticamente

Caso o saque seja derivado para análise manual, um analista deverá aprovar ou reprovar o saque. Neste momento, um Webhook pode ser gerado para notificar a alteração de status ao PSP ou o PSP pode acompanhar o pagamento por meio de Polling. Em ambos os casos, os seguintes status podem ser retornados:

enumerador | descrição
:--------: | ---------
manually_approved | Aprovado Manualmente
manually_reproved | Reprovado Manual

## Fluxos - Transação PIX

O fluxo de pagamento PIX é iniciado em duas situações:

- Um pagamento sendo efetuado pelo usuário do PSP integrado na QI Tech
- Um pagamento sendo recebido de outro PSP

Em ambos os casos, uma chamada ao endpoint de pagamento deve ser realizada e os possíveis status resultantes são:

enumerador | descrição
:--------: | ---------
automatically_approved | Aprovado Automaticamente
automatically_reproved | Reprovado Automaticamente
in_manual_analysis     | Derivado para Análise Manual

Caso o pagamento seja derivado para análise manual, um analista deverá aprovar ou reprovar o pagamento. Neste momento, um Webhook pode ser gerado para notificar a alteração de status ao PSP ou o PSP pode acompanhar o pagamento por meio de Polling. Em ambos os casos, os seguintes status podem ser retornados:

enumerador | descrição
:--------: | ---------
manually_approved | Aprovado Manualmente
manually_reproved | Reprovado Manualmente

## Fluxos - Alteração na DICT

O fluxo de alteração na DICT é iniciado em duas situações:

- O usuário do PSP integrado à QI Tech pede um cadastro/alteração/portabilidade/reivindicação ao PSP integrado à QI Tech
- Uma portabilidade/reivindicação é recebida pelo PSP integrado à QI Tech

Nos cadastros iniciados pelo usuário do PSP, o fluxo de validação de chave deve ser executado antes da alteração na DICT, por meio das APIs de validação da QI Tech. Caso a validação seja realizada pelo próprio PSP, esta informação também pode ser enviada na requisição à QI Tech.

Para dar início ao processo, nestes dois momentos o PSP integrado à QI Tech deverá realizar uma chamada no endpoint adequado, que responderá um dos seguintes status:

enumerador | descrição
:--------: | ---------
automatically_approved | Aprovado Automaticamente
automatically_reproved | Reprovado Automaticamente
in_manual_analysis     | Derivado para Análise Manual

Caso a alteração seja derivada para análise manual, um analista deverá aprovar ou reprovar a alteração. Neste momento, um Webhook pode ser gerado para notificar a alteração de status ao PSP ou o PSP pode acompanhar a alteração por meio de Polling. Em ambos os casos, os seguintes status podem ser retornados:

enumerador | descrição
:--------: | ---------
manually_approved | Aprovado Manualmente
manually_reproved | Reprovado Manualmente
## Autenticação

> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE_API_KEY"
```

> Substitua a API key 'EXAMPLE_API_KEY' com a sua chave adquirida com o nosso suporte.

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE_API_KEY`

:::info **Atenção**

Você deve substituir EXAMPLE_API_KEY com a API Key recebida do suporte.
:::

---

# Objetos Compartilhados

URL: /documentation/caas/banking/objects

Boa parte dos dados são compartilhados entre os diferentes eventos de uma conta. Abaixo as definições destes objetos podem ser localizadas de maneira facilitada.

## Objeto Client

Request Body

```json
{
    "id": "123456",
    "type": "natural_person",
    "document_number": "023.456.789-01",
    "name": "John Payer",
    "email": "john@payer.com",
    "address": {
        "street": "Av. Eng. Luis Carlos Berrini",
        "number": "105",
        "neighbourhood": "Brooklin",
        "city": "São Paulo",
        "uf": "SP",
        "complement": "Cj 303",
        "postal_code": "04501-140"
    },
    "phone": {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "998861708",
        "type": "mobile"
    },
    "sales_channel": "inbound_sales",
    "segment": "Personalité"
}
```

Objeto que representa os dados do detenedor da conta.

nome | tipo | descrição
:----:  | :----:  | ---------
type                        | enum *(obrigatório)* | Tipo do cliente: "natural_person" ou "legal_person"
document_number             | string *(obrigatório)* | Número do documento, de acordo co seção padronização
name                        | string *(obrigatório)* | Nome do cliente
email                       | string                    | E-mail do cliente
address                     | *address*                 | Dados de endereço do cliente
phone                       | *phone*                   | Dados telefônicos do cliente
sales_channel               | enum *(obrigatório)*| Canal por onde o cliente se cadastrou
segment                     | string *(obrigatório)*| Segmento do cliente dentro da insituição (ex.: premium, gold)

Existem os seguintes enumeradores para tipo de telefone: `inbound_sales`, `app`, `website`, `call_center` e `branch`

## Objeto Address

Request Body

```json
{
  "street": "Rua do Teste",
  "number": "111",
  "neighbourhood": "Bairro do Exemplo",
  "city": "Aparecida de Goiânia",
  "uf": "GO",
  "complement": "Térreo",
  "postal_code": "00000-000",
  "country": "BRA"
}
```

O objeto *address* é utilizado para representar endereços em toda a API, endereços no território brasileiro são representados da seguinte maneira:

nome | tipo | descrição
---- | :----: | ---------
street | string *(obrigatório)* | Rua do endereço, incluindo o logradouro, evitando, se possível, abreviações.
number | string  *(obrigatório)* | Número do imóvel, incluindo letras caso possua.
neighbourhood | string *(obrigatório)*| Bairro, sem abreviações. **e.g.: Santa Felicidade**
city | string *(obrigatório)*| Nome completo da cidade, sem abreviações
uf | string *(obrigatório)* | A unidade federativa, com duas letras maiúsculas. **e.g.: SP**
complement | string | Quaisquer complementos para localizar o imóvel. **e.g.: Apartamento 101, Conjunto 12**
postal_code  | string *(obrigatório)* | O código postal da localidade, contendo o hífen.
country | string *(obrigatório)* | Código ISO 3166-1 alfa-3 do país do endereço.

No caso dos endereços cujo país não seja Brasil ("BRA"), o postal_code e a unidade federativa poderão ser preenchidos livremente.

## Objeto Phone

Request Body

```json
{
  "international_dial_code": "1",
  "area_code": "11",
  "number": "999999999",
  "type": "mobile"
}
```

Um objeto *phone* representa um número telefônico, dentro ou fora do Brasil e sua classificação. Para isso, os campos são:

nome | tipo | descrição
---- | :----: | ---------
international_dial_code | string *(obrigatório)* | Código de discagem internacional, sem zero ou +, somente números
area_code | string *(obrigatório)* | Código de área, sem zero, somente números
number | string  *(obrigatório)* | Número do telefone, sem o hífen
type | enum  *(obrigatório)* | Tipo de número: celular, residencial, comercial, etc.

Existem os seguintes enumeradores para tipo de telefone: `residential`, `commercial` e `mobile`.

## Objeto Account

Request Body

```json
{
    "participant": "17315359",
    "branch": "0000",
    "account_number": "10442",
    "account_digit": "6",
    "account_type": "CACC",
    "opening_date": "2020-01-15T18:00:00-03:00"
}
```

Objeto que representa os dados de uma conta.

nome | tipo | descrição
:----:  | :----:  | ---------
participant                 | string *(obrigatório)* | ISPB da instituição detentora da conta
branch                      | string *(obrigatório)* | Agência da Conta
account_number              | string *(obrigatório)* | Número da Conta sem o dígito
account_digit               | string *(obrigatório)* | Dígito da conta
account_type                | enum *(obrigatório)* | Tipo da conta de origem, possíveis valores: "CACC", "SLRY" e "SVGS"
opening_date                | datetime | Data de abertura da conta.

## Objeto Source

Request Body

```json

{
    "channel": "app",
    "platform": "android",
    "ip":"255.201.26.1",
    "session_id": "54b8e3cf-15de-41e5-9305-0ecf059d6e2a"
}

```

O objeto source representa o conjunto de informações da plataforma utilizada pelo usuário para realizar a operação. Os campos são:

nome | tipo | descrição
:----: | :----: | ---------
channel     | string | Canal utilizado pelo usuário para realizar a operação, ex.: internet banking, app
platform    | string | Plataforma utilizada pela aplicação
ip          | string | IP coletado do device
session_id  | string | Identificador único da sessão, utilizado para fazer o cruzamento do Device Scan com o evento em questão

## Objeto Dict Key

Request Body

```json
  {
    "key_type": "cpf",
    "key_value": "09991222669",
    "assignment_date": "2020-01-15T18:00:00-03:00"
  }
```

O objeto **dict_key**  é utilizado para representar os dados da chave de vínculo no DICT do cliente, seja ele o recebedor ou o pagador da transação. Os campos desse objeto são:

nome | tipo | descrição
:----: | :----: | ---------
key_type        | string *(obrigatório)* | Enumerador que contém o tipo da chave de vinculo no DICT.
key_value       | string | Contém a chave de vínculo cadastrada no DICT.
assignment_date | datetime  | Data que a chave de vínculo foi cadastrada no DICT.

Os enumeradores para o campo *key_type* são os mesmos definidos na API do DICT: `cpf`,`cnpj`,`email`,`phone` e `evp`.

## Objeto Destination Statistics

Request Body

```json
{
  "account":{
      "settlements":{
          "d3":4,
          "d30":67,
          "m6":618
      },
      "rejected":{
          "d3":4,
          "d30":67,
          "m6":618
      },
      "reported_frauds":{
          "d3":0,
          "d30":0,
          "m6":0
      },
      "reported_aml_cft":{
          "d3":0,
          "d30":0,
          "m6":0
      },
      "confirmed_frauds":{
          "d3":0,
          "d30":0,
          "m6":0
      },
      "confirmed_aml_cft":{
          "d3":0,
          "d30":0,
          "m6":0
      }
  },
  "owner":{
      "settlements":{
          "d3":6,
          "d30":88,
          "m6":996
      },
      "rejected":{
          "d3":4,
          "d30":67,
          "m6":618
      },
      "reported_frauds":{
          "d3":0,
          "d30":0,
          "m6":0
      },
      "reported_aml_cft":{
          "d3":0,
          "d30":0,
          "m6":0
      },
      "confirmed_frauds":{
          "d3":0,
          "d30":0,
          "m6":0
      },
      "confirmed_aml_cft":{
          "d3":0,
          "d30":0,
          "m6":0
      }
  },
  "key":{
      "settlements":{
          "d3":3,
          "d30":51,
          "m6":312
      },
      "rejected":{
          "d3":4,
          "d30":67,
          "m6":618
      },
      "reported_frauds":{
          "d3":0,
          "d30":0,
          "m6":0
      },
      "reported_aml_cft":{
          "d3":0,
          "d30":0,
          "m6":0
      },
      "confirmed_frauds":{
          "d3":0,
          "d30":0,
          "m6":0
      },
      "confirmed_aml_cft":{
          "d3":0,
          "d30":0,
          "m6":0
      }
  }
}
```

Para que o risco de fraude em uma transação seja avaliado com maior precisão, é necessário informar o histórico transacional e de fraudes do creditado através do objeto *Destination Statistics*. Tais dados podem ser obtidos ao se consultar a chave de vinculo do creditado na base de dados do DICT. É exigência do BACEN que esses dados sejam utilizados na avaliação de fraude das transações.

nome | tipo | descrição
:----: | :----: | ---------
account | *account* *(obrigatório)* | Objeto que contém o histórico transacional e de fraudes da conta do creditado.
owner   | *owner* *(obrigatório)* | Objeto que contém o histórico transacional e de fraudes associados ao documento do creditado.
key     | *key* *(obrigatório)* | Objeto que contém o histórico transacional e de fraudes associados a chave fornecida pelo creditado.

Onde cada um dos objetos definidos acima possui os mesmos campos:

nome | tipo | descrição
:----: | :----: | ---------
settlements       | *settlements* *(obrigatório)*   | Objeto que contém o histórico transacional.
rejected          | *rejected* *(opcional)*   | Objeto que contém o histórico de operações negadas.
reported_frauds   | *reported_frauds*  *(obrigatório)* | Objeto que contém o histórico de relatos de fraudes.
reported_aml_cft  | *reported_aml_cft* *(opcional)* | Objeto que contém o histórico de relatos de PLD/FT.
confirmed_frauds  | *confirmed_frauds* *(obrigatório)* | Objeto que contém o histórico de relatos de fraudes confirmados.
confirmed_aml_cft | *confirmed_aml_cft* *(opcional)* | Objeto que contém o histórico de relatos de PLD/FT confirmados.

Onde cada um desses objetos contém os campos **d3**, **d30** e **m6**, contendo o número de ocorrências nos ultimos 3 dias, 30 dias e 6 meses, que são campos obrigatórios, respectivamente. Da mesma forma que é definido pela API do DICT do BCB.

---

# PIX Dict Operation

URL: /documentation/caas/banking/pix_dict_operations

No momento em que o usuário iniciar uma mudança na DICT, os dados deverão ser enviados para o nosso servidor, de maneira que possamos realizar uma análise do risco envolvido naquele conjunto de dados.

## Definição do Objeto de Dict Operation

Request Body

```json
{
  "id": "f58e8a19-429d-4e36-a010-ed00a323c2c5",
  "dict_key": {
      "key_type": "phone",
      "key_value": "16981610077",
      "assignment_date": "2020-01-15T18:00:00-03:00"
  },
  "dict_operation_direction": "claimer",
  "dict_operation_reason": "user_requested",
  "dict_operation_creation_date": "2020-10-14T18:00:00-03:00",
  "dict_operation_type": "claim_portability",
  "client": {
      "id": "123456",
      "document_number": "099.912.226-69",
      "name": "João Jorge da Silva",
      "type": "natural_person",
      "address": {
          "street": "Avenida 13",
          "number": "704",
          "neighbourhood": "Centro",
          "city": "Ituiutaba",
          "uf": "MG",
          "complement": "Apt 1101",
          "postal_code": "38300-140"
      },
      "phone": {
          "international_dial_code": "55",
          "area_code": "65",
          "number": "988961210",
          "type": "mobile"
      },
      "sales_channel": "inbound_sales",
      "segment": "Personalité"
  },
  "source_account": {
      "participant": "04184779",
      "branch": "0001",
      "account_number": "1122",
      "account_digit": "6",
      "owner": {
          "type": "legal_person",
          "document_number": "94.948.708/0001-12",
          "name": "Irmão Soares Ferragista LTDA."
      },
      "account_type": "CACC",
      "opening_date": "2020-01-15T18:00:00-03:00"
  },
  "destination_account": {
      "participant": "00000000",
      "branch": "3675",
      "account_number": "10442",
      "account_digit": "6",
      "owner": {
          "type": "natural_person",
          "document_number": "099.912.226-69",
          "name": "João Jorge da Silva"
      },
      "account_type": "SLRY",
      "opening_date": "2020-01-15T18:00:00-03:00"
  },
  "destination_statistics": {
      "account":{
          "settlements":{
              "d3":12,
              "d30":65,
              "m6":344
          },
          "rejected":{
              "d3":4,
              "d30":67,
              "m6":618
          },
          "reported_frauds":{
              "d3":0,
              "d30":0,
              "m6":0
          },
          "reported_aml_cft":{
              "d3":0,
              "d30":0,
              "m6":0
          },
          "confirmed_frauds":{
              "d3":0,
              "d30":0,
              "m6":0
          },
          "confirmed_aml_cft":{
              "d3":0,
              "d30":0,
              "m6":0
          }
      },
      "owner":{
          "settlements":{
              "d3":4,
              "d30":12,
              "m6":88
          },
          "rejected":{
              "d3":4,
              "d30":67,
              "m6":618
          },
          "reported_frauds":{
              "d3":0,
              "d30":0,
              "m6":0
          },
          "reported_aml_cft":{
              "d3":0,
              "d30":0,
              "m6":0
          },
          "confirmed_frauds":{
              "d3":0,
              "d30":0,
              "m6":0
          },
          "confirmed_aml_cft":{
              "d3":0,
              "d30":0,
              "m6":0
          }
      },
      "key":{
          "settlements":{
              "d3":1,
              "d30":6,
              "m6":12
          },
          "rejected":{
              "d3":4,
              "d30":67,
              "m6":618
          },
          "reported_frauds":{
              "d3":0,
              "d30":0,
              "m6":0
          },
          "reported_aml_cft":{
              "d3":0,
              "d30":0,
              "m6":0
          },
          "confirmed_frauds":{
              "d3":0,
              "d30":0,
              "m6":0
          },
          "confirmed_aml_cft":{
              "d3":0,
              "d30":0,
              "m6":0
          }
      }
  },
  "source": {
      "channel": "internet_banking",
      "platform": "android",
      "ip": "198.185.065-98",
      "session_id": "7839jdqd9a8wd9"
  }
}
```

Uma Dict Operation deve ser enviada para a API antes de ser encaminhada para o sistema de processamento do BCB, a fim de realizar uma validação prévia de fraude de cadastro.

O status da análise da Dict Operation representa a decisão retornada pelo modelo sobre aquela operação. Os seguintes status são utilizados na flag **analysis_status**:

* `automatically_approved`
* `automatically_reproved`
* `in_manual_analysis`
* `pending`

Abaixo estão listados os significados de cada uma das decisões, devolvida na flag analysis_status:

status | descrição
:----: | ---------
automatically_approved      | Recomenda-se que esta operação seja aprovada.
automatically_reproved      | Recomenda-se que esta operação seja reprovada.
in_manual_analysis          | Recomenda-se que a operação seja analisada manualmente por um analista.
pending                     | A operação está sendo processada.

nome | tipo | descrição
:----:  | :----:  | ---------
id | string | Identificador da operação no sistema do cliente. **É essencial que este número seja único para cada processo de autorização**
client                  | *client*                  | Objeto que representa os dados do cliente, seja ele o doador ou o recebedor.
transaction_date        | datetime                  | A data e hora de início da transação, com fuso horário.
dict_key                | *dict_key*                | Objeto que representa os dados da chave de vínculo no DICT, utilizada pelo cliente na trasação.
dict_key_type           | enumerador                | Tipo da chave de vínculo ao DICT.
dict_operation_direction| enumerador                | Direção de operação no DICT, isto é, se uma chave está sendo cedida ou obtida.
dict_operation_reason   | enumerador                | A razão pelo qual a Operação na Dict está sendo realizada.
dict_operation_creation_date     | datetime                  | Data da operação no DICT.
dict_operation_type     | enumerador                | Tipo de operação no DICT.
source_account          | *source_account*          | Objeto que representa os dados da conta que está cedendo a chave de vínculo.
destination_account     | *destination_account*     | Objeto que representa os dados da conta que está recebendo a chave de vínculo.
destination_statistics  | *destination_statistics*  | Objeto que representa o histórico de transações e fraudes da conta que esta recebendo a chave de vinculo.
source                  | *source*                  | Objeto do tipo Source que descreve as informações provenientes da aplicação utilizada para envio do cadastro

O campo *dict_key_type* aceita os mesmos enumeradores definidos na API do DICT: `cpf`,`cnpj`,`email`,`phone` e `evp`.

O campo *dict_operation_direction* aceita os enumeradores: `donor` e `claimer`.

O campo *dict_operation_type* aceita os enumeradores `registration`, `claim_ownership` e `claim_portability`. 
Sendo estas todos os tipos de operações na DICT definidas pelo BCB.

## Enviar uma Dict Operation

Request Body

```json
  {
    "id": "f58e8a19-429d-4e36-a010-ed00a323c2c5",
    ...
  }
```

Response Body

```json
  {
    "dict_operation_key": "7f85e162-5a7d-41fa-a578-69df6f3df958",
    "status": "automatically_approved"
  }
```

Para realizar a avaliação de um pagamento, basta enviar um objeto do tipo Payment ao seguinte endpoint:

`POST https://api.caas.qitech.app/pix/dict_operation`

## Recuperar uma Dict Operation

Response Body

```json
  {
    "id": "f58e8a19-429d-4e36-a010-ed00a323c2c5",
    ...
  }
```

Para recuperar uma Dict Operation, basta enviar uma requisição ao seguinte endpoint:

`GET https://api.caas.qitech.app/pix/dict_operation/{dict_operation_id}`

Onde *dict_operation_id* é o identificador da operação que nos foi enviado no momento do cadastro desta, no campo "id".

Será, então, retornado o objeto Dict Operation associado a chave provida.

## Atualizar uma Dict Operation

Request Body

```json
  {
    "dict_operation_status": "cancelled_by_client",
    "reason": "user_requested",
    "event_date": "2020-10-07T15:06:25-03:00"
  }
```

Uma Dict Operation possui várias fases junto ao BCB antes que seja concluída. Deste modo, é necessário que sejam informadas todas as atualizações de status das operações, através do endpoint:

`PUT https://api.caas.qitech.app/pix/dict_operation/{dict_operation_id}`

Deste modo, garate-se que nossa base de dados seja atualizada e esteja sempre coerente com a base de dados do BCB.

Algumas operações na DICT demandam que seja submetida a razão da operação juntos dos dados. Para estes casos, é necessário informar o campo *reason* no objeto de envio, contendo o mesmo enumerador provido ao sistema do BCB.
São esses:

enumerador | descrição
:--------: | ---------
user_requested    | A operação foi requisitada pelo cliente.
account_closure   | A operação foi iniciada devido ao fechamento da conta do cliente.
branch_transfer   | A operação foi requisitada devido a mudança de agência do cliente.
entry_inactivity  | A operação foi requisitada devido a inatividade na conta do cliente.
reconciliation    | A operação foi requisitada após um processo de reconcialiation.
default_operation | A operação foi requisitada por uma ação padrão do participante.
fraud             | A operação foi requisitada devido a um fraude ligada a conta do cliente.

As fases de uma operação na DICT aceitas pelo campo *dict_operation_status* são:

enumerador | descrição
:--------: | ---------
created                   | A dict_operation foi criada mas ainda não foi analisada.
reproved                  | A dict_operation foi reprovada na análise e não será enviada ao BCB.
waiting_resolution        | A dict_operation foi enviada ao BCB e está esperando a resolução.
cancelled_by_client       | A dict_operation foi cancelada pelo cliente.
cancelled_by_counterpart  | A dict_operation foi cancelada pela outra parte da operação.
confirmed                 | A dict_operation foi confirmada pela outra parte da operação.
completed                 | A dict_operation foi completada e adicionada a base de dados do BCB.

---

# PIX Infraction Report

URL: /documentation/caas/banking/pix_infraction_reports

## Definição do Objeto de Infraction Reports

Request Body

```json
{
    "infraction_report_type": "compliance",
    "infraction_report_details": "Cliente realizou várias compras de valor alto em estabelecimentos comerciais cuja atividade econômica é de alto risco de lavagem de dinheiro. Após uma investigação minuciosa, decidiu-se realizar o report ao COAF e bloquear o saldo em conta até que a origem do dinheiro seja esclarecida. ",
    "infraction_report_creator": "external",
    "infraction_report_date": "2020-10-14T00:25:42-03:00",
    "infraction_report_status": "received",
    "infraction_report_events": [               
        {
            "new_status": "received",
            "event_date": "2020-10-14T00:25:42-03:00"
        }
    ]
}
```

Caso algum comportamento suspeito seja dectado por qualquer uma das partes da transação, um Infraction Report pode ser criado para relatar a suspeita. Esse Infraction Report será então analisado pela outra parte e poderá ser confimado ou não. Seguindo o padrão estabelecido pelo BCB, um Infraction Report deverá ter os campos:

nome | tipo | descrição
:----: | :----: | ---------
infraction_report_type      | enumerador | Enumerador que define o tipo de atividade suspeita presente na transação.
infraction_report_details   | string     | Detalhes das circustâncias que levaram o criador do Infraction Report a acreditar que possa existir algum tipo de infração associada a transação.
infraction_report_creator   | enumerador | Enumerador que define quem criou o Infraction Report.
infraction_report_date      | datetime   | Data do incidente.

O campo *infraction_report_type* poderá conter os enumeradores: `fraud` e `compliance`.

O campo *infraction_report_creator* poderá conter os enumeradores: `client` e `external`.

## Enviar um Infraction Report

Request Body

```json
{
    "infraction_report_type": "compliance",
    "infraction_report_details": "Cliente realizou várias compras de valor alto em estabelecimentos comerciais cuja atividade econômica é de alto risco de lavagem de dinheiro. Após uma investigação minuciosa, decidiu-se realizar o report ao COAF e bloquear o saldo em conta até que a origem do dinheiro seja esclarecida. ",
    "infraction_report_creator": "external",
    "infraction_report_date": "2020-10-14T00:25:42-03:00"
}
```

Response Body

```json
  {
    "infraction_report_key": "7f85e162-5a7d-41fa-a578-69df6f3df958",
    "infraction_report_status": "received"
  }
```

Para realizar a o envio de um Infraction Report, basta enviar uma requisição ao endpoint:

`POST https://api.caas.qitech.app/pix/transaction/{transaction_id}/infraction_report`

Onde *transaction_id* é o identificador da transação que nos foi enviado no momento do cadastro desta, no campo "id".

## Recuperar um Infraction Report

Response Body

```json
  {
      "infraction_report_type": "compliance",
      "infraction_report_details": "Cliente realizou várias compras de valor alto em estabelecimentos comerciais cuja atividade econômica é de alto risco de lavagem de dinheiro. Após uma investigação minuciosa, decidiu-se realizar o report ao COAF e bloquear o saldo em conta até que a origem do dinheiro seja esclarecida. ",
      "infraction_report_creator": "external",
      "infraction_report_date": "2020-10-14T00:25:42-03:00",
      "infraction_report_status": "received",
      "infraction_report_events": [               
          {
              "new_status": "received",
              "event_date": "2020-10-14T00:25:42-03:00"
          }
      ],
      "transaction_data": {
        "transaction_direction": "received",
        "id": "082373263",
        ...
      }
  }
```

Para recuperar um Infraction Report, basta enviar uma requisição ao seguinte endpoint:

`GET https://api.caas.qitech.app/pix/transaction/{transaction_id}/infraction_report/{infraction_report_key}`

Será, então, retornado o objeto Infraction Report associado o *transaction_id* provido e com *infraction_report_key* idêntica a chave enviada.

## Atualizar um Infraction Report

Request Body

```json
  {
    "infraction_report_status": "acknowledged",
    "event_date": "2020-10-07T15:06:25-03:00"
  }
```

Um Infraction Report possui várias fases junto ao BCB antes que seja concluído. Deste modo, é necessário que sejam informadas todas as atualizações de status do Infraction Report, através do endpoint:

`PUT https://api.caas.qitech.app/pix/transaction/{transaction_id}/infraction_report/{infraction_report_key}`

---

# PIX Transaction

URL: /documentation/caas/banking/pix_transactions

No momento em que o pagador iniciar ou receber um pagamento, os dados  da transação deverão ser enviados para o nosso servidor. Deste modo, será possível realizar uma análise do risco envolvido na transação, baseado naquele conjunto de dados.

## Definição do Objeto de Pix Transactions

Request Body

```json
{
    "transaction_direction": "received",
    "id": "082373263",
    "client": {
        "id": "123456",
        "document_number": "056.966.649-03",
        "name": "Francisco Oliveira Benedetti",
        "type": "natural_person",
        "address": {
            "street": "Avenida 13",
            "number": "704",
            "neighbourhood": "Centro",
            "city": "Ituiutaba",
            "uf": "MG",
            "complement": "Apt 1101",
            "postal_code": "38300-140"
        },
        "email": "mailto@qitech.com.br",
        "phone": {
            "international_dial_code": "55",
            "area_code": "16",
            "number": "981610077",
            "type": "mobile"
        },
        "sales_channel": "inbound_sales",
        "segment": "Personalité"
    },
    "amount": 13725,
    "transaction_date": "2020-10-07T15:06:25-03:00",
    "dict_key": {
        "key_type": "cpf",
        "key_value": "09991222669",
        "assignment_date": "2020-01-15T18:00:00-03:00"
    },
    "capture_method": "static_qr_code",
    "face_recognition_key": "ef39e206-13d5-48de-b368-6c3bbc6f0222",
    "validation_key": "69a59de3-0198-4a26-933a-c1de624c147d",
    "source_account": {
        "participant": "17315359",
        "branch": "0000",
        "account_number": "10442",
        "account_digit": "6",
        "owner": {
            "type": "legal_person",
            "document_number": "07.487.735/0001-69",
            "name": "Gioconda Pizzaria e Rotisseria LTDA."
        },
        "account_type": "CACC",
        "opening_date": "2020-01-15T18:00:00-03:00"
    },
    "destination_account": {
        "participant": "60701190",
        "branch": "3675",
        "account_number": "10442",
        "account_digit": "6",
        "owner": {
            "type": "natural_person",
            "document_number": "056.966.649-03",
            "name": "Francisco Oliveira Benedetti"
        },
        "account_type": "SLRY",
        "opening_date": "2020-01-15T18:00:00-03:00"
    },
    "destination_statistics": {
        "person":{
            "settlements":{
                "d90":4,
                "m12":67,
                "m60":618
            },
            "application_frauds":{
                "d90":0,
                "m12":4,
                "m60":9
            },
            "mule_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "scammer_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "other_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "unknown_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "total_frauds_transaction_amount":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "distinct_fraud_reporters":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "open_reports":0,
            "open_reports_distinct_reporters":0,
            "rejected_reports":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "registered_accounts":0         
        },
        "owner":{
            "settlements":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "application_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "mule_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "scammer_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "other_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "unknown_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "total_frauds_transaction_amount":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "distinct_fraud_reporters":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "open_reports":0,
            "open_reports_distinct_reporters":0,
            "registered_accounts":0     
        },
        "key":{
            "settlements":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "application_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "mule_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "scammer_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "other_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "unknown_frauds":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "total_frauds_transaction_amount":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "distinct_fraud_reporters":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "open_reports":0,
            "open_reports_distinct_reporters":0,
            "rejected_reports":{
                "d90":0,
                "m12":0,
                "m60":0
            },
            "distinct_accounts":{
                "d90":0,
                "m12":0,
                "m60":0
            }
        }
    },
    "source": {
        "channel": "internet_banking",
        "platform": "android",
        "ip": "198.185.065.098",
        "session_id": "7839jdqd9a8wd9"
    }
}
```

Uma transação deve ser enviado para a API antes de ser encaminhada para o sistema de processamento, a fim de realizar uma validação prévia de fraude.

O status da transação representa a decisão retornada pelo modelo sobre aquela transação. Os seguintes status são utilizados na flag **analysis_status**:

* `automatically_approved`
* `automatically_reproved`
* `in_manual_analysis`
* `pending`

Abaixo estão listados os significados de cada uma das decisões, devolvida na flag analysis_status:

status | descrição
:----: | ---------
automatically_approved      | Recomenda-se que esta transação seja aprovada.
automatically_reproved      | Recomenda-se que esta transação seja reprovada.
approved_by_time            | A transação foi aprovada por expiração de tempo de análise manual
reproved_by_time            | A transação foi aprovada por expiração de tempo de análise manual
in_manual_analysis          | Recomenda-se que a transação seja analisada manualmente por um analista.
pending                     | A transação está sendo processada.

nome | tipo | descrição
:----:  | :----:  | ---------
transaction_direction   | enumerador  | Tipo da transação cadastrada. Define se o cliente está recebendo ou enviando dinheiro. *(obrigatório)*
id | string | Identificador do pagamento no sistema do cliente. **É essencial que este número seja único para cada processo de pagamento** *(obrigatório)*
client                  | *client* | Objeto que representa os dados do cliente, seja ele o pagador ou o recebedor. *(obrigatório)*
amount                  | inteiro  | O valor do pagamento, em centavos- conforme descrição da seção "Padrões". *(obrigatório)*
pix_modality            | string   | Tipo de transação cadastrada. Indica se representa uma transferência, um troco ou um saque.
transaction_date        | datetime | A data e hora de início da transação, com fuso horário. *(obrigatório)*
dict_key                | *dict_key*                | Objeto que representa os dados da chave de vínculo no DICT, utilizada pelo cliente na trasação.
capture_method          | enumerador | Método utilizado para iniciação do pagamento, se foi via QR Code estático ou dinâmico, via preenchimento de dados ou via chave da DICT. *(obrigatório)*
face_recognition_key    | string                    | Chave de reconhecimento facial, caso tenha sido feito reconhecimento facial pela nossa API de reconhecimento facial.
validation_key          | string                    | Chave de validação, caso tenha sido feita algum teste de validação do cliente em nossa API de validações.
source_account          | *source_account* | Objeto que representa os dados da conta debitada. *(obrigatório)*
destination_account     | *destination_account* | Objeto que representa os dados da conta creditada. *(obrigatório)*
destination_statistics  | *destination_statistics*  | Objeto que representa o histórico de transações e fraudes da conta creditada provenientes da API de DICT do BACEN. *(obrigatório)*
source                  | *source* | Objeto do tipo Source que descreve as informações provenientes da aplicação utilizada para envio do pagamento

Existem os seguintes enumeradores para *transaction_direction*: `sent` e `received`.

Existem os seguintes enumeradores para *pix_modality*: `transacation`, `change` e `withdraw`.

Existem os seguintes enumeradores para *capture_method*: `static_qr_code`, `dynamic_qr_code`, `offline_qr_code`, `typed`.

## Enviar uma Transação

Request Body

```json
  {
    "id": "12345",
    ...
  }
```

Response Body

```json
  {
    "transaction_key": "13d680ef-4b72-4cb2-a63d-cf3d790abaaf",
    "analysis_status": "automatically_approved",
    "reason": "rule_decision_enum"
  }
```

Para realizar a avaliação de uma transação, basta enviar um objeto do tipo Transaction ao seguinte endpoint:

`POST https://api.caas.qitech.app/pix/transaction`

## Recuperar uma Transação

Response Body

```json
  {
    "transaction_direction": "received",
    "id": "082373263",
    ...
  }
```

Para recuperar os dados de uma transação, basta enviar uma requisição ao seguinte endpoint:

`GET https://api.caas.qitech.app/pix/transaction/{transaction_id}`

Onde *transaction_id* é o identificador da transação que nos foi enviado no momento do cadastro, no campo "id".

## Atualizar uma Transação

Request Body

```json
  {
    "transaction_status": "sent",
    "event_date": "2020-10-07T15:06:25-03:00"
  }
```

Após uma transação ser criada e analisada, ela deve ser enviada ao BCB para ser processada. Deste modo, é necessário que seja informada a atualizações de status da transação quando essa for enviada ao BCB, através do endpoint:

`PUT https://api.caas.qitech.app/pix/transaction/{transaction_id}`

Deste modo, garante-se que nossa base de dados seja atualizada e esteja sempre coerente com a base de dados do BCB.

## Transação não efetivada

Request Body

```json
  {
    "transaction_status": "cancelled",
    "reason": "refused_by_counterpart",
    "event_date": "2020-10-07T15:06:25-03:00"
  }
```

Caso uma transação, por qualquer motivo, não tenha sido efetivada (i.e.: Saldo debitado da conta de origem e creditado na conta de destino), a transação pode ser atualizada para o status `cancelled`, com a razão do cancelamento para que seja possível identificar perfis de fraude relacionados a transação não efetivadas. O status cancelled só pode ser utilizado em transações que ainda possuem o status created, uma vez que o status `sent` é utilizado nos casos em que a transação foi evetivada.

`PUT https://api.caas.qitech.app/pix/transaction/{transaction_id}`

As seguintes reasons são atualmente aceitas pela API, caso você veja a necessidade de enquadrar o motivo do cancelamento em outra reason, por favor, entre em contato com suporte.caas@qitech.com.br.

reason | descrição
:----:  | ---------
insufficient_balance | O cliente não possui saldo na conta para realizar a transação
fraud_prevention | A transação foi cancelada pois não foi aprovada no sistema antifraude
system_block | Algum bloqueio de sistema não permitiu a execução da transação, por exemplo conta cancelada/inativa ou limite alcançado
invalid_destination | A instituição contraparte não aceitou a transação pois a conta de destino não existe
refused_by_counterpart | A instituição contraparte rejeitou a transação
system_error | A transação foi cancelada pois houve um erro no sistema da própria instituição
invalid_authentication | A transação foi cancelada pois o cliente não passou em algum fluxo de autenticação

---

# Padrões

URL: /documentation/caas/banking/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões que são seguidos em toda a API.

## Valores Monetários
> Exemplos:

```
10000
12345
98741
1223
1
0
```

Os valores devem ser enviados como inteiro em centavos.

## Data e Hora com Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12-03:00
2018-05-01T13:32:11+00:00
2019-05-01T00:00:00+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será valido. Por exemplo, se um aluguel estiver marcado para começar às 09:30 no aeroporto de Brasília, o horário enviado deverá ser representado por 09:30-03:00, se o aluguel estiver marcado para começar às 09:30 em Manaus, deverá ser representado por 09:30-04:00.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss±hh:mm`

## Data e Hora sem Fuso Horario
> Alguns exemplos:

```
2019-10-15T22:35:12Z
2018-05-01T13:32:11Z
2019-05-01T00:00:00Z
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão ser enviados sem ele, sempre em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ssZ`

## Data
> Alguns exemplos

``` 
2019-10-15
2019-01-01
2017-03-20
```

No caso de campos que recebem somente data, uma data de nascimento, por exemplo, somente a data, sem nenhum horário deve ser enviada com o seguinte formato:

`YYYY-MM-dd`

---

# Webhook

URL: /documentation/caas/banking/webhook

Webhook

Atualizações no status de fraude (Para eventos que sejam derivados para análise manual ou que sejam respondidos como Pendente), são notificados por meio de Webhook. Para tanto, é necessário, por meio da equipe do [suporte](mailto:suporte.caas@qitech.com.br), configurar um endereço do endpoint por onde vamos notificar as atualizações e também uma *signature_key* que será utilizada para assinar a requisição.

O cliente pode também utilizar a técnica de [polling](https://en.wikipedia.org/wiki/Polling_(computer_science)). Neste caso, basta não configurar o endpoint de webhook e utilizar os endpoints de recuperação para proceder com o polling.

:::info **Atenção**

Por questões de segurança, todas as requisições de Webhook serão somente realizadas em endpoints servidos por HTTPS.
:::

## Assinatura do Webhook

## Webhook de Atualização de Evento

Request Body

```json
    {
        "id": "123456",
        "analysis_status": "automatically_approved",
        "event_date": "2019-10-01T10:37:25-03:00"
    }
```

A requisição de atualização do status de análise de um evento possui o formato acima e notifica a mudança no status de fraude. O método utilizado é um PUT e o endereço do endpoint pode conter também o id do evento, de acordo com a necessidade do cliente. É importante ressaltar que o corpo da requisição é enviado como texto codificado em UTF-8.

Exemplos de endpoints para atualização de evento:

* https://apidocliente.com.br/\{evento\}
* https://apidocliente.com.br/admin/\{evento\}/123456

O campo \{evento\}, localizado na URL da requisição, pode assumir os seguintes valores, a depender do evento sendo notificado:
* bill_payment
* bankslip
* wire_transfer
* withdrawal
* pix

O campo event_date indica a data e hora em que a notificação foi criada e pode estar no passado caso envios de notificação anteriores tenham falhado.

## Retentativas

A notificação é considerada realizada quando recebe como resposta um HTTP Status 200. Caso as notificações falhem, serão feitas 7 retentativas, com os seguintes intervalos, até que um 200 seja retornado ou as tentativas terminem:

* 10 segundos
* 40 segundos
* 160 segundos
* 640 segundos
* 2560 segundos
* 10240 segundos
* 40960 segundos

---

# Transferências

URL: /documentation/caas/banking/wire_transfers

No momento em que um usuário efetuar ou receber uma transferência, os dados da transferência deverão ser enviados para a QI Tech. Deste modo, será possível realizar uma análise do risco envolvido na transação, baseado naquele conjunto de dados.

## Definição do Objeto de Transferência

Request Body

```json
{
    "id": "082373263",
    "wire_transfer_direction": "received",
    "wire_transfer_type": "ted",
    "amount": 13725,
    "wire_transfer_date": "2020-10-07T15:06:25-03:00",
    "face_recognition_key": "ef39e206-13d5-48de-b368-6c3bbc6f0222",
    "validation_key": "69a59de3-0198-4a26-933a-c1de624c147d",
    "client": {
        "type": "natural_person",
        "id": "123456",
        "document_number": "056.966.649-03",
        "name": "Francisco Oliveira Benedetti",
        "address": {
            "street": "Avenida 13",
            "number": "704",
            "neighbourhood": "Centro",
            "city": "Ituiutaba",
            "uf": "MG",
            "complement": "Apt 1101",
            "postal_code": "38300-140"
        },
        "phone": {
            "international_dial_code": "55",
            "area_code": "16",
            "number": "981610077",
            "type": "mobile"
        },
        "email": "mailto@qitech.com.br",
        "sales_channel": "inbound_sales",
        "segment": "Personalité"
    },
    "source_account": {
        "participant": "17315359",
        "branch": "0000",
        "account_number": "10442",
        "account_digit": "6",
        "owner": {
            "type": "legal_person",
            "document_number": "07.487.735/0001-69",
            "name": "Gioconda Pizzaria e Rotisseria LTDA."
        },
        "account_type": "CACC",
        "opening_date": "2020-01-15T18:00:00-03:00"
    },
    "destination_account": {
        "participant": "60701190",
        "branch": "3675",
        "account_number": "10442",
        "account_digit": "6",
        "owner": {
            "type": "natural_person",
            "document_number": "056.966.649-03",
            "name": "Francisco Oliveira Benedetti"
        },
        "account_type": "SLRY",
        "opening_date": "2020-01-15T18:00:00-03:00"
    },
    "source": {
        "channel": "internet_banking",
        "platform": "android",
        "ip": "198.185.065.098",
        "session_id": "7839jdqd9a8wd9"
    }
}
```

Uma transferência deve ser enviado para a API antes de ser encaminhada para o sistema de processamento, a fim de realizar uma validação prévia de fraude.

O status da transferência representa a decisão retornada pelo modelo sobre aquela transferência. Os seguintes status são utilizados na flag **analysis_status**:

* `automatically_approved`
* `automatically_reproved`
* `in_manual_analysis`
* `pending`

Abaixo estão listados os significados de cada uma das decisões, devolvida na flag analysis_status:

status | descrição
:----: | ---------
automatically_approved      | Recomenda-se que esta transferência seja aprovada.
automatically_reproved      | Recomenda-se que esta transferência seja reprovada.
in_manual_analysis          | Recomenda-se que a transferência seja analisada manualmente por um analista.
pending                     | A transferência está sendo processada.

nome | tipo | descrição
:----:  | :----:  | ---------
id | string | Identificador da transação no sistema do cliente. **É essencial que este número seja único para cada transferência**
wire_transfer_direction | enumerador                | Modalidade da transferência cadastrada. Define se o cliente está recebendo ou enviando dinheiro.
wire_transfer_type      | enumerador                | Tipo da transferência realizada, podendo ser uma TED, um DOC ou uma transferência interna entre contas da mesma instituição.
amount                  | inteiro                   | O valor da transferência em centavos - conforme descrição da seção "Padrões".
wire_transfer_date      | datetime                  | A data e hora de início da transferência, com fuso horário.
face_recognition_key    | string                    | Chave de reconhecimento facial, caso tenha sido feito reconhecimento facial pela nossa API de reconhecimento facial.
validation_key          | string                    | Chave de validação, caso tenha sido feita algum teste de validação do cliente em nossa API de validações.
client                  | *client*                  | Objeto que representa os dados do cliente, seja ele o cliente que está efetuando a transferência ou o recebedor.
source_account          | *source_account*          | Objeto que representa os dados da conta debitada.
destination_account     | *destination_account*     | Objeto que representa os dados da conta creditada.
source                  | *source* | Objeto do tipo Source que descreve as informações provenientes da aplicação utilizada para envio da transferência

Existem os seguintes enumeradores para *wire_transfer_direction*: `sent` e `received`.

Existem os seguintes enumeradores para *wire_transfer_type*: `ted`, `doc`, `internal_transfer`.

## Enviar uma Transferência

Request Body

```json
  {
    "id": "12345",
    ...
  }
```

Response Body

```json
  {
    "wire_transfer_key": "13d680ef-4b72-4cb2-a63d-cf3d790abaaf",
    "status": "automatically_approved",
    "reason": "rule_decision_enum"
  }
```

Para realizar a avaliação de uma transferência, basta enviar um objeto do tipo Wire Transfer ao seguinte endpoint:

`POST https://api.caas.qitech.app/wire_transfer/wire_transfer`

## Recuperar uma Transferência

Response Body

```json
  {
    "id": "082373263",
    "wire_transfer_direction": "received",
    ...
  }
```

Para recuperar os dados de uma transferência, basta enviar uma requisição ao seguinte endpoint:

`GET https://api.caas.qitech.app/wire_transfer/wire_transfer/{wire_transfer_id}`

Onde *wire_transfer_id* é o identificador da transação no sistema do cliente utilizado no envio da transferência.

## Atualizar uma transferência

Request Body

```json
  {
    "wire_transfer_status": "completed",
    "event_date": "2020-10-07T15:06:25-03:00"
  }
```

Response Body

```json
  {
    "wire_transfer_key": "13d680ef-4b72-4cb2-a63d-cf3d790abaaf",
    "wire_transfer_status": "completed"
  }
```

Após uma transferência ser criada e analisada, ela será enviado à câmara de compensação para ser processada. Deste modo, é necessário que seja informada a atualizações de status da transferência quando esta for enviada, através do endpoint:

`PUT https://api.caas.qitech.app/wire_transfer/wire_transfer/{wire_transfer_id}`

Deste modo, garante-se que nossa base de dados seja atualizada e sejamos capazes de identificar as transferências que estejam realmente sucetíveis a fraude.

---

# Saques

URL: /documentation/caas/banking/withdrawals

No momento em que um usuário efetuar um saque, os dados do saque deverão ser enviados para a QI Tech. Deste modo, será possível realizar uma análise do risco envolvido na operação, baseado naquele conjunto de dados.

## Definição do Objeto de Saque

Request Body

```json
{
    "id": "082373263",
    "amount": 12979,
    "withdrawal_date": "2020-10-07T15:06:25-03:00",
    "service_description": "SAQUE EM CAIXA 24H",
    "source_account": {
        "participant": "17315359",
        "branch": "0000",
        "account_number": "10442",
        "account_digit": "6",
        "account_type": "CACC",
        "opening_date": "2020-01-15T18:00:00-03:00"
    },
    "client": {
        "id": "182373263",
        "type": "natural_person",
        "document_number": "023.456.789-01",
        "name": "John Payer",
        "email": "john@payer.com",
        "address": {
            "street": "Av. Eng. Luis Carlos Berrini",
            "number": "105",
            "neighbourhood": "Brooklin",
            "city": "São Paulo",
            "uf": "SP",
            "complement": "Cj 303",
            "postal_code": "04501-140"
        },
        "phone": {
            "international_dial_code": "55",
            "area_code": "11",
            "number": "998861708",
            "type": "mobile"
        },
        "sales_channel": "inbound_sales",
        "segment": "Personalité"
    },
    "terminal": {
        "id": "1234566",
        "latitude": -45.2753548,
        "longitude": -15.24587,
        "address": { 
            "street": "Av. Eng. Luis Carlos Berrini",
            "number": "105",
            "neighbourhood": "Brooklin",
            "city": "São Paulo",
            "uf": "SP",
            "complement": "Cj 303",
            "postal_code": "04501-140"
        },
        "type": "atm"
    },
    "authentication": {
        "used_password": true,
        "used_card": true,
        "used_fingerprint": true,
        "typed_account_number": false
    }
}
```

Um saque deve ser enviado para a API antes de ser encaminhada para o sistema de processamento, a fim de realizar uma validação prévia de fraude.

O status do saque representa a decisão retornada pelo modelo sobre aquela conta. Os seguintes status são utilizados na flag **analysis_status**:

* `automatically_approved`
* `automatically_reproved`

Abaixo estão listados os significados de cada uma das decisões, devolvida na flag analysis_status:

status | descrição
:----: | ---------
automatically_approved      | Recomenda-se que este saque seja aprovado.
automatically_reproved      | Recomenda-se que este saque seja reprovado.

nome | tipo | descrição
:----:  | :----:  | ---------
id | string | Identificador do saque no sistema do cliente. **É essencial que este número seja único para cada saque**
amount                      | inteiro                   | Valor do saque em centavos - conforme descrição da seção "Padrões".
withdrawal_date             | datetime                  | Data e hora da realização do saque - conforme descrição da seção "Padrões"
source_account              | *account*                 | Objeto que determina a conta de origem do recurso a ser sacado
client                      | *client*                  | Objeto com os dados do cliente detentor da conta de origem
terminal                    | *terminal*                | Objeto com os dados do terminal onde o saque está sendo realizado
authentication              | *authentication*          | Objeto com as informações de autenticação

## Objetos do Saque

### Objeto Terminal

Request Body

```json
{
    "id": "1234566",
    "latitude": -45.2753548,
    "longitude": -15.24587,
    "address": { 
        "street": "Av. Eng. Luis Carlos Berrini",
        "number": "105",
        "neighbourhood": "Brooklin",
        "city": "São Paulo",
        "uf": "SP",
        "complement": "Cj 303",
        "postal_code": "04501-140"
    },
    "type": "atm"
}
```

Objeto que representa o terminal que foi utilizado para o saque.

nome | tipo | descrição
:----:  | :----:  | ---------
id                          | string                    | Identificador do terminal no sistema do cliente
latitude                    | number                    | Latitude, em graus, da localização do terminal
longitude                   | number                    | Longitude, em graus, da localização do terminal
address                     | *address*                 | Endereço do terminal
type                        | enum                      | Tipo do terminal, possíveis valores: "atm", "counter"

### Objeto Authentication

Request Body

```json
{
    "used_password": true,
    "used_card": true,
    "used_fingerprint": true,
    "typed_account_number": false
}
```

Objeto que define os parâmetros da autenticação utilizada no momento do saque.

nome | tipo | descrição
:----: | :----: | -----------
used_password               | boolean                           | Determina se o usuário utilizou senha
used_card                   | boolean                           | Determina se o usuário está com o cartão presente na autenticação
used_card_chip_and_pin      | boolean                           | Determina se o usuário utilizou o chip e senha do cartão
used_card_magnetic_stripe   | boolean                           | Determina se o usuário utilizou a tarja magnética do cartão
used_fingerprint            | boolean                           | Determina se o usuário utilizou fingerprint
typed_account_number        | boolean                           | Determina se o usuário digitou os dados da conta

## Enviar um Saque

Request Body

```json
  {
    "id": "12345",
    ...
  }
```

Response Body

```json
  {
    "withdrawal_key": "13d680ef-4b72-4cb2-a63d-cf3d790abaaf",
    "status": "automatically_approved",
    "reason": "rule_decision_enum"
  }
```

Para realizar a avaliação de um pagamento de conta, basta enviar um objeto do tipo withdrawal ao seguinte endpoint:

`POST https://api.caas.qitech.app/withdrawal/withdrawal`

## Recuperar um Saque

Request Body

```json
  {
    "id": "082373263",
    "amount": 12979,
    ...
  }
```

Para recuperar os dados de um saque, basta enviar uma requisição ao seguinte endpoint:

`GET https://api.caas.qitech.app/withdrawal/withdrawal/{withdrawal_id}`

Onde *withdrawal_id* é o identificador da transação no sistema do cliente utilizado no envio do saque.

## Atualizar um saque

Request Body

```json
  {
    "withdrawal_status": "completed",
    "event_date": "2020-10-07T15:06:25-03:00"
  }
```

Response Body

```json
  {
    "withdrawal_key": "13d680ef-4b72-4cb2-a63d-cf3d790abaaf",
    "withdrawal_status": "completed"
  }
```

Após um saque ser criada e analisada, o dinheiro será disponibilizado ao usuário. Este processo pode ser interrompido por alguma outra regra de negócio. Deste modo, é necessário que seja informada a atualizações de status do saque quando este for finalizado, através do endpoint:

`PUT https://api.caas.qitech.app/withdrawal/withdrawal/{withdrawal_id}`

Deste modo, garante-se que nossa base de dados seja atualizada e sejamos capazes de identificar os saques que estejam realmente sucetíveis a fraude.

---

# Status HTTP

URL: /documentation/caas/car_rental/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o [RFC 7231](https://tools.ietf.org/html/rfc7231):

| Status HTTP | Significado | Descrição |
| ---------- | ------- | --------------------------------- |
| 400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro. |
| 401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação. |
| 403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key. |
| 404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado. |
| 405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado. |
| 406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido. |
| 409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor. |
| 500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente. |
| 503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores. |

---

# Imagens

URL: /documentation/caas/car_rental/image

Em várias situações é necessário enviar imagens para a nossa API, a fim de realizar operações de OCR, FaceMatch e validação de documentos. Para tanto, é preciso inicialmente realizar o upload da imagem para depois enviá-la para análise.

Ao enviar uma imagem utilizando o endpoint /image uma GUID (Globally Unique Identifier) é retornada. Este valor deverá ser utilizado nas chamadas subsequentes para referenciar esta imagem.

:::warning
O tamanho máximo de uma imagem aceita é de 10MB.
:::

:::warning
Neste momento, somente imagens com formato jpg são aceitas.
:::

## Envio

Exemplo de envio utilizando o cUrl:

```shell
curl -F "data=@path/to/local/file" \
     -H "Authorization: TESTETESTETESTE" \
     -H "DocumentNumber: 000.000.000-00" \
     "https://api.caas.qitech.app/car_rental/image?type=face"
```

Exemplo de retorno:

```json
{
  "image_key": "f1c0d2e1-f950-4360-896d-36588e443fc9",
  "file_name": "05696664903.jpg",
  "file_size": 47407,
  "width_px": 0,
  "height_px": 0,
  "type": "face",
  "created_at": "2020-07-29T18:40:57Z"
}
```

Para enviar uma imagem, basta realizar o envio da imagem no formato .jpg em `multipart/form-data` com uma requisição POST no endpoint:

`POST https://api.caas.qitech.app/car_rental/image?type=$type`

Onde $type é a classificação da imagem e deve ser enviado conforme um dos seguintes enumeradores (Caso a imagem sendo enviada não se enquadre em nenhuma das classificações, entrar em contato com o [suporte](mailto:suporte.caas@qitech.com.br) para que providenciem a adição):

- `face`
- `driver_license`
- `id`
- `contract`

Após o envio, será retornado um objeto JSON com a GUID que aponta para a imagem que foi enviada.

## Análise da Imagem para App

Ao utilizar a api_key do App, o resultado contará com um valor adicional, chamado de `result` que pode receber os seguintes valores:

- `registration_approved`
- `registration_reproved`

Que indica se o cadastro da foto foi aprovado ou reprovado.

Neste momento, a qualidade da foto também é avaliada, podendo receber um resultado 400, conforme descrito no próximo item.

Exemplo de retorno para o App:

```json
{
  "image_key": "f1c0d2e1-f950-4360-896d-36588e443fc9",
  "file_name": "05696664903.jpg",
  "file_size": 47407,
  "width_px": 0,
  "height_px": 0,
  "type": "face",
  "result": "registration_approved",
  "created_at": "2020-07-29T18:40:57Z"
}
```

## Validação de qualidade da imagem

Exemplo de retorno em caso de imagem inválida:

```json
{
  "title": "image_quality",
  "description": "A imagem enviada não possui uma face"
}
```

Ao realizar um post no endpoint de imagem, caso a imagem não seja suficiente para validação, um HTTP Status Code 400 será retornado, como pode ser visto no exemplo acima.

O valor do campo description é a mensagem que explica o motivo da imagem ser inválida.

:::info
Existem outros motivos pelos quais retornaremos 400 (Todos relacionados a dados inválidos). Somente os retornos com title "image_quality" são resultantes da validação de qualidade da imagem e portanto devem ser repassados ao usuário.
:::

## Recuperação dos Arquivos

Leitura de imagem:

```shell
curl "https://api.caas.qitech.app/car_rental/image/{image_key}/file" \
     -H "Authorization: TESTETESTETESTE"
```

Após o envio de uma imagem para a API, é possível recuperá-la por meio de uma requisição GET adequadamente autenticada no endpoint:

`GET https://api.caas.qitech.app/car_rental/image/{image_key}/file`

Onde image_key é o valor retornado durante o envio da imagem.

## Recuperação dos meta-dados do arquivo

Leitura de meta dados:

```shell
curl "https://api.caas.qitech.app/car_rental/image/{image_key}" \
     -H "Authorization: TESTETESTETESTE"
```

Após o envio de uma imagem para a API, é possível recuperar os meta-dados da imagem utilizando o endpoint:

`GET https://api.caas.qitech.app/car_rental/image/{image_key}`

Onde image_key é o valor retornado durante o envio da imagem.

---

# Introdução

URL: /documentation/caas/car_rental/introduction

Bem vindo à API de Prevenção a Fraudes em aluguel de veículos da QI Tech! Você pode utilizar a nossa API para acessar os endpoints, a fim de receber a resposta de um contrato de aluguel, além de utilizar para atualizar a situação de um contrato.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso [suporte](mailto:suporte.caas@qitech.com.br) e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. A URL base das APIs são:

- Produção - `https://api.caas.qitech.app/car_rental/`
- Sandbox - `https://api.sandbox.caas.qitech.app/car_rental/`

No ambiente de Sandbox, as análises enviadas não são cobradas e são respondidas de acordo com a seguinte regra **baseada no valor total do aluguel**:

| Mínimo | Máximo | Decisão |
| ------ | ------ | ------- |
| 10000 | -- | Pendente (Em análise Manual) - Sem Decisão da Mesa |
| 8000 | 9999 | Aprovado Automaticamente |
| 6000 | 7999 | Reprovado Automaticamente |
| 5000 | 5999 | Derivado para Análise Manual - Com aprovação posterior |
| 4000 | 4999 | Derivado para Análise Manual - Com reprovação posterior |
| 3000 | 3999 | Derivado para Análise Manual - Com Desafio Manual |
| 0 | 2999 | Pendente (Em análise Manual) - Sem Decisão da Mesa |

As análises de upgrade em ambiente de Sandbox seguirão as decisões de análise abaixo:

| Grupos | upgrade_status |
| ------ | -------------- |
| ('C', 'CX', 'SV', 'SU') | 'automatically_approved' |
| ('IE', 'J', 'SG') | 'automatically_reproved' |

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech devem ser realizadas utilizando a comunicação HTTPS. Para garantir que, por desatenção ou qualquer outro motivo, não ocorram chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

## Autenticação

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: API-KEY-EXAMPLE"
```

:::info
Substitua a API key `API-KEY-EXAMPLE` com a sua chave adquirida com o nosso suporte.
:::

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para [suporte.caas@qitech.com.br](mailto:suporte.caas@qitech.com.br).

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: API-KEY-EXAMPLE`

:::note
Você deve substituir `API-KEY-EXAMPLE` com a API Key recebida do suporte.
:::

---

# Troca de Mensagens

URL: /documentation/caas/car_rental/messages

Para a troca de mensagens entre a mesa de análise manual e o atendente da loja, são disponibilizados dois endpoints:

- `POST https://api.caas.qitech.app/car_rental/rental_agreement/{rental_agreement_id}/message`
- `GET https://api.caas.qitech.app/car_rental/rental_agreement/{rental_agreement_id}/messages`

Todas as mensagens são vinculadas a uma análise, utilizando o id enviado no momento do envio da análise.

## Envio de Mensagem

Para que seja realizado o envio de uma mensagem, é necessário realizar a requisição utilizando o método POST no endpoint message, com uma payload que possui os seguintes campos:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| author_document_number | string | CPF formatado de quem está enviando a mensagem |
| author_name | string | Nome de quem está enviando a mensagem |
| message | string | Mensagem sendo enviada |

Exemplo de payload para envio de uma mensagem:

```json
{
  "author_name": "John Sample",
  "author_document_number": "000.000.000-00",
  "message": "Alerta de fraude"
}
```

## Recebimento de Mensagens

Para que as mensagens possam ser exibidas para o atendente, basta realizar a recuperação das mensagens trocadas por meio do endpoint de GET. O endpoint pode receber um query parameter chamado `only_messages_to_show`, que ao receber o valor `true` retorna somente as mensagens que devem ser exibidas na tela do atendente.

Os dados do autor somente são devolvidos quando a mensagem foi produzida por um ser humano.

Retorno no endpoint de recuperação de mensagens:

```json
[
  {
    "author_name": "John Sample",
    "author_document_number": "000.000.000-00",
    "source": "analysis_screen",
    "message": "Análise finalizada",
    "message_date": "2019-11-05T13:34:12-03:00"
  },
  {...}
]
```

---

# Objetos Compartilhados

URL: /documentation/caas/car_rental/objects

Boa parte dos dados são compartilhados entre Reservation e RentalAgreement. Abaixo as definições destes objetos podem ser localizadas de maneira facilitada.

## Objeto *reservation*

```json
{
  "id": "0",
  "channel": "reservation_central",
  "reservation_date": "2020-03-31T08:15:00-03:00",
  "sales_channel" : "PARCERIA TELEFONICA"
}
```

O objeto *reservation* é utilizado no endpoint de *rental_agreement* para representar a reserva que deu origem ao aluguel que será analisado. Este campo é necessário para que um rental_agreement seja vinculado à reserva. Representada da seguinte maneira:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| id | inteiro | Identificador da reserva que deu origem ao aluguel. |
| channel | enumerador | Canal pelo qual foi feito a reserva para este aluguel. |
| reservation_date | DateTime | Data e Hora com fuso-horário do momento em que ocorreu a reserva para este aluguel. |
| sales_channel | string | Canal de vendas pelo qual a reserva foi realizada (ex.: PARCERIA MASTERCARD) |

Existem os seguintes enumeradores para o campo *channel*: `walkin`, `reservation_central`, `app`, `website_mobile`, `website_desktop`, `partnerships` e `third_parties`.

## Objeto *car*

```json
{
  "model_group": "C",
  "upgrade_model_group": "SV",
  "group_description": "Sedan Médio 1.4",
  "rental_daily_price": 48496
}
```

O objeto *car* representa um veículo que está sendo reservado (endpoint de *reservation*) ou retirado (endpoint de *rental_agreement*). Os dados enviados são:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| **model_group** | string | O grupo do veículo, em letras maiúsculas. *(obrigatório)* |
| upgrade_model_group | string | O grupo do veículo do upgrade, em letras maiúsculas. |
| group_description | string | Uma descrição do grupo do veículo |
| rental_daily_price | inteiro | O valor da diária cobrado |

## Objeto *client*

O objeto de *client* representa os dados referentes ao cliente que está fazendo a reserva ou retirada do veículo.

### Objeto *client (v1)*

O exemplo "v1" representa o payload de exemplo **antes da migração da scoragem principal para a reserva**. Tanto para reservas quanto para rental_agreements.

```json
{
  "type": "natural_person",
  "document_number": "123.456.789-00",
  "name": "John Sample",
  "gender": "female",
  "birthdate": "2001-01-15",
  "mother_name": "Mary Sample",
  "email": "john.sample@sample.com.br",
  "allowed_information_on_email": true,
  "face_picture": "c77d1925-0e72-4634-8393-395dbbce498d",
  "additional_pictures": [
    "718b8caa-8ef5-446c-b101-2dbf6c7e401f",
    "9c67f365-1427-4889-b963-d3729d437ff3",
    "8006f82c-3a80-4371-914e-e88c91507711",
    "42c6909e-51aa-4b6d-972f-f4684a047993",
    "b7a88947-96bd-4557-81e9-a69a3c84f428"
  ],
  "total_rents": 6,
  "fidelity_points": 1200,
  "documents": {
    "rg": {
      "document_number": "00000000",
      "issuer": "SSP"
    },
    "cnh": {
      "document_number": "000000000",
      "security_code": "00000",
      "first_issuance": "2015-07-20",
      "expiration_date": "2030-07-26",
      "state": "SP"
    }
  },
  "residential_address": {
    "street": "Av Brigadeiro Faria Lima",
    "number": "2391",
    "neighborhood": "Jardins",
    "city": "SÃO PAULO",
    "uf": "SP",
    "complement": "",
    "postal_code": "00000-000"
  },
  "commercial_address": {
    "street": "Av Brigadeiro Faria Lima",
    "number": "2391",
    "neighborhood": "Jardins",
    "city": "SÃO PAULO",
    "uf": "SP",
    "complement": "",
    "postal_code": "00000-000"
  },
  "phones": [
    {
      "international_dial_code": "55",
      "area_code": "11",
      "number": "00000-0000",
      "type": "mobile"
    },
    {
      "international_dial_code": "55",
      "area_code": "11",
      "number": "00000-0000",
      "type": "residential"
    }
  ]
}
```

| nome | tipo | descrição |
| ---- | :----: | --------- |
| **type** | enum | Enumerador que define tipo do cliente. *(obrigatório)* |
| **document_number** | string | O CPF ou Passaporte do cliente. *(obrigatório)* |
| **name** | string | O nome completo do cliente. *(obrigatório)* |
| **gender** | enum | O gênero do cliente. *(obrigatório)* |
| birthdate | date | Data de nascimento do cliente. |
| mother_name | string | O nome completo da mãe do cliente. |
| **email** | string | O email informado pelo cliente. *(obrigatório)* |
| **allowed_information_on_email** | booleano | Flag que indica se o cliente permitiu o envio de e-mails de marketing no momento do cadastro. *(obrigatório)* |
| face_picture | GUID | GUID da imagem previamente enviada cujo conteúdo é uma foto do rosto do cliente. |
| additional_pictures | List of GUIDs | Lista de GUIDs das imagens adicionais enviadas de rostos e documentos dos clientes. |
| total_rents | integer | Quantidade total de aluguéis do cliente. |
| fidelity_points | integer | Quantidade de pontos de fidelidade do cliente. |
| **documents** | *documents* | Objeto que contém o detalhamento dos documentos do cliente. *(obrigatório)* |
| residential_address | *address* | Endereço residencial do cliente. |
| commercial_address | *address* | Endereço comercial do cliente. |
| **phones** | List of *phone* | Lista com os telefones do cliente. *(obrigatório)* |

Existem os seguintes enumeradores para o campo *type*: `natural_person`, `legal_person`, `replacement`, `fleet`, `uber`, `enterprise` e `agencia`.

Existem os seguintes enumeradores para o campo *gender*: `male`, `female` e `undefined`.

### Objeto *client (v2)*

Esta seção diz respeito às informações necessárias para o fluxo de análise de fraude primariamente na reserva.

O exemplo do objeto de "client (v2)" representa o payload de exemplo **posterior à migração da scoragem principal para a reserva**. Tanto para reservas quanto para rental_agreements.

```json
{
  "type": "natural_person",
  "document_number": "123.456.789-00",
  "name": "John Sample",
  "gender": "female",
  "birthdate": "2001-01-15",
  "mother_name": "Mary Sample",
  "email": "john.sample@sample.com.br",
  "allowed_information_on_email": true,
  "face_picture": "c77d1925-0e72-4634-8393-395dbbce498d",
  "additional_pictures": [
    "718b8caa-8ef5-446c-b101-2dbf6c7e401f",
    "9c67f365-1427-4889-b963-d3729d437ff3",
    "8006f82c-3a80-4371-914e-e88c91507711",
    "42c6909e-51aa-4b6d-972f-f4684a047993",
    "b7a88947-96bd-4557-81e9-a69a3c84f428"
  ],
  "total_rents": 6,
  "fidelity_points": 1200,
  "documents": {
    "rg": {
      "document_number": "00000000",
      "issuer": "SSP"
    },
    "cnh": {
      "document_number": "000000000",
      "security_code": "00000",
      "first_issuance": "2015-07-20",
      "expiration_date": "2030-07-26",
      "state": "SP"
    }
  },
  "residential_address": {
    "street": "Av Brigadeiro Faria Lima",
    "number": "2391",
    "neighborhood": "Jardins",
    "city": "SÃO PAULO",
    "uf": "SP",
    "complement": "",
    "postal_code": "00000-000"
  },
  "commercial_address": {
    "street": "Av Brigadeiro Faria Lima",
    "number": "2391",
    "neighborhood": "Jardins",
    "city": "SÃO PAULO",
    "uf": "SP",
    "complement": "",
    "postal_code": "00000-000"
  },
  "phones": [
    {
      "international_dial_code": "55",
      "area_code": "11",
      "number": "00000-0000",
      "type": "mobile"
    },
    {
      "international_dial_code": "55",
      "area_code": "11",
      "number": "00000-0000",
      "type": "residential"
    }
  ]
}
```

| nome | tipo | descrição |
| ---- | :----: | --------- |
| **type** | enum | Enumerador que define tipo do cliente. - type esperados: "natural_person", "legal_person", "replacement", "fleet", "uber", "agencia", "uber_semanal" *(obrigatório)* |
| **document_number** | string | O CPF ou Passaporte do cliente. *(obrigatório)* |
| name | string | O nome completo do cliente. |
| **gender** | enum | O gênero do cliente. *(obrigatório)* |
| birthdate | date | Data de nascimento do cliente. |
| mother_name | string | O nome completo da mãe do cliente. |
| email | string | O email informado pelo cliente. |
| allowed_information_on_email | booleano | Flag que indica se o cliente permitiu o envio de e-mails de marketing no momento do cadastro. *(obrigatório)* |
| face_picture | GUID | GUID da imagem previamente enviada cujo conteúdo é uma foto do rosto do cliente. |
| additional_pictures | List of GUIDs | Lista de GUIDs das imagens adicionais enviadas de rostos e documentos dos clientes. |
| total_rents | integer | Quantidade total de aluguéis do cliente. |
| fidelity_points | integer | Quantidade de pontos de fidelidade do cliente. |
| **documents** | *documents* | Objeto que contém o detalhamento dos documentos do cliente. *(obrigatório)* |
| residential_address | *address* | Endereço residencial do cliente. |
| commercial_address | *address* | Endereço comercial do cliente. |
| **phones** | List of *phone* | Lista com os telefones do cliente. *(obrigatório)* |

Existem os seguintes enumeradores para o campo *type*: `natural_person`, `legal_person`, `replacement`, `fleet`, `uber`, `enterprise` e `agencia`.

Existem os seguintes enumeradores para o campo *gender*: `male`, `female` e `undefined`.

## Objeto *participant*

O objeto *participant* representa uma pessoa envolvida no aluguel que não é o locatário principal, isto é, um **motorista adicional** ou o **responsável financeiro**. É a definição utilizada tanto na lista `additional_drivers` quanto no campo `financial_manager` de um RentalAgreement.

Sua estrutura é a mesma do objeto *client*, de maneira que a mesma implementação de serialização pode ser reaproveitada.

:::note
Cada participante enviado passa pela mesma análise antifraude aplicada ao locatário principal, porém o resultado destas análises **não altera o fraud_status** do RentalAgreement.
:::

```json
{
  "type": "natural_person",
  "segment": "ota",
  "document_number": "987.654.321-00",
  "name": "Jane Sample",
  "gender": "female",
  "birthdate": "1998-05-22",
  "mother_name": "Mary Sample",
  "email": "jane.sample@sample.com.br",
  "allowed_information_on_email": true,
  "face_picture": "e3b0c442-98fc-1c14-9afb-f4c8996fb924",
  "additional_pictures": [
    "718b8caa-8ef5-446c-b101-2dbf6c7e401f"
  ],
  "total_rents": 2,
  "fidelity_points": 0,
  "documents": {
    "rg": {
      "document_number": "00000000",
      "issuer": "SSP"
    },
    "cnh": {
      "document_number": "000000000",
      "security_code": "00000",
      "first_issuance": "2018-03-10",
      "expiration_date": "2028-03-10",
      "state": "SP"
    }
  },
  "residential_address": {
    "street": "Av Brigadeiro Faria Lima",
    "number": "2391",
    "neighborhood": "Jardins",
    "city": "SÃO PAULO",
    "uf": "SP",
    "complement": "",
    "postal_code": "00000-000",
    "country": "BRA"
  },
  "phones": [
    {
      "international_dial_code": "55",
      "area_code": "11",
      "number": "00000-0000",
      "type": "mobile"
    }
  ]
}
```

| nome | tipo | descrição |
| ---- | :----: | --------- |
| **type** | enum | Enumerador que define o tipo do participante. *(obrigatório)* |
| segment | string | Segmento ao qual o participante pertence. |
| **document_number** | string | O CPF, CNPJ ou Passaporte do participante. *(obrigatório)* |
| **name** | string | O nome completo do participante. *(obrigatório)* |
| **gender** | enum | O gênero do participante. *(obrigatório)* |
| birthdate | date | Data de nascimento do participante. |
| mother_name | string | O nome completo da mãe do participante. |
| **email** | string | O email informado pelo participante. *(obrigatório)* |
| **allowed_information_on_email** | booleano | Flag que indica se o participante permitiu o envio de e-mails de marketing no momento do cadastro. *(obrigatório)* |
| face_picture | GUID | GUID da imagem previamente enviada cujo conteúdo é uma foto do rosto do participante. |
| additional_pictures | List of GUIDs | Lista de GUIDs das imagens adicionais enviadas de rostos e documentos do participante. |
| total_rents | integer | Quantidade total de aluguéis do participante. |
| fidelity_points | integer | Quantidade de pontos de fidelidade do participante. |
| **documents** | *documents* | Objeto que contém o detalhamento dos documentos do participante. *(obrigatório)* |
| residential_address | *address* | Endereço residencial do participante. |
| commercial_address | *address* | Endereço comercial do participante. |
| **phones** | List of *phone* | Lista com os telefones do participante. *(obrigatório)* |

Existem os seguintes enumeradores para o campo *type*: `natural_person`, `legal_person`, `replacement`, `fleet`, `uber`, `enterprise`, `agencia` e `uber_semanal`.

Existem os seguintes enumeradores para o campo *gender*: `male`, `female` e `undefined`.

## Objeto *billing*

```json
{
  "name": "Agência AAA",
  "document_number": "00.000.000/0001-00",
  "voucher_type":"ABCD75",
  "voucher_description": "Pagamento pela Agência"
}
```

O objeto *billing* é utilizado para representar quem é o responsável pelo pagamento do aluguel, e é representado da seguinte maneira:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| name | string | Nome da pessoa ou empresa responsável pelo pagamento do aluguel. |
| document_number | string | CPF, CNPJ ou Passaporte da pessoa ou empresa responsável pelo pagamento do aluguel. |
| voucher_type | string | Código alfanumérico que representa o tipo do voucher utilizado. |
| voucher_description | string | Descrição do tipo de voucher utilizado. |

## Objeto *address*

```json
{
  "street": "Rua do Exemplo",
  "number": "111",
  "neighborhood": "Bairro do Teste",
  "city": "Aparecida de Goiânia",
  "uf": "GO",
  "complement": "",
  "postal_code": "00000-000"
}
```

O objeto *address* é utilizado para representar endereços em toda a API, endereços no território brasileiro são representados da seguinte maneira:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| street | string | Rua do endereço, incluindo o logradouro, evitando, se possível, abreviações. |
| number | string | Número do imóvel, incluindo letras caso possua. |
| neighborhood | string | Bairro, sem abreviações. **e.g.: Santa Felicidade** |
| city | string | Nome completo da cidade, sem abreviações |
| uf | string | A unidade federativa, com duas letras maiúsculas. **e.g.: SP** |
| complement | string | Quaisquer complementos para localizar o imóvel. **e.g.: Apartamento 101, Conjunto 12** |
| postal_code | string | O código postal da localidade, contendo o hífen. |
| country | string | Código ISO 3166-1 alfa-3 do país do endereço. |

No caso dos endereços cujo país não seja Brasil ("BRA"), o postal_code e a unidade federativa poderão ser preenchidos livremente.

## Objeto *documents*

O objeto *documents* é utilizado para representar o detalhamento dos dados dos documentos informados pelo cliente. O objeto é representado da seguinte maneira:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| rg | *rg* | Objeto que descreve as informações do RG do cliente. |
| cnh | *cnh* | Objeto que descreve as informações da CNH do cliente. |
| foreign_document | *foreign_document* | Objeto que descreve as informações do documento estrangeiro do cliente. |

## Objeto *rg*

O objeto *rg* é utilizado para representar o detalhamento dos dados do RG informados pelo cliente. O objeto é representado da seguinte maneira:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| document_number | string | Número do RG do cliente. |
| issuer | string | Órgão emissor e estado de emissão do RG do cliente. |

## Objeto *cnh*

O objeto *cnh* é utilizado para representar o detalhamento dos dados da CNH informados pelo cliente. O objeto é representado da seguinte maneira:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| document_number | string | Número de Registro da CNH do cliente. |
| security_code | string | Código de segurança da CNH do cliente. |
| first_issuance | date | Data da primeira emissão da CNH do cliente |
| expiration_date | string | Data de validade da CNH do cliente |
| state | string | Estado de emissão da CNH do cliente. |

## Objeto *foreign_document*

O objeto *foreign_document* é utilizado para representar o documento estrangeiro informado pelo cliente. O objeto é representado da seguinte maneira:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| document_number | string | Número do documento estrangeiro do cliente. |
| document_type | enum | Tipo do documento estrangeiro. Aceita os valores `passport` e `other`. |
| issuer_country | string | Código ISO 3166-1 alfa-3 do país emissor do documento. |

## Objeto *phone*

```json
{
  "international_dial_code": "1",
  "area_code": "11",
  "number": "99999-9999",
  "type": "mobile"
}
```

Um objeto phone representa um número telefônico, dentro ou fora do Brasil e sua classificação. Para isso, os campos são:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| **international_dial_code** | string | Código de discagem internacional, sem zero ou +, somente números. *(obrigatório)* |
| **area_code** | string | Código de área, sem zero, somente números. *(obrigatório)* |
| **number** | string | Número do telefone, sem o hífen. *(obrigatório)* |
| **type** | enum | Tipo de número: celular, residencial, comercial, etc. *(obrigatório)* |

Existem os seguintes enumeradores para tipo de telefone: `residential`, `commercial`, `mobile`.

## Objeto *coverage*

```json
{
  "description": "S/ PROTEÇÃO AMERICAN PLATINUM",
  "price": 0
}
```

Um objeto coverage está relacionado a uma cobertura contratada pelo locatário.

| nome | tipo | descrição |
| :----: | :----: | --------- |
| **description** | string | Descrição da cobertura contratada. *(obrigatório)* |
| **price** | integer | Preço diário da cobertura. *(obrigatório)* |

---

# Envio de Resultado Quiz

URL: /documentation/caas/car_rental/quiz

Para o envio do resultado Quiz, para que apareça na interface gráfica, o seguinte endpoint deve ser utilizado:

`POST https://api.caas.qitech.app/car_rental/rental_agreement/{rental_agreement_id}/quiz_result`

O resultado do quiz é vinculado a uma análise, utilizando o id enviado no momento do envio da análise.

## Envio do Quiz

Para que seja enviado o resultado do Quiz, é necessário realizar a requisição utilizando o método POST no endpoint quiz_result, com uma payload que possui os seguintes campos:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| score | number | Valor numérico do score do Quiz |
| result_enum | string | Enumerador do resultado do quiz: `low_risk`, `medium_risk`, `high_risk` |
| result_description | string | Descrição do resultado do quiz: "Baixo Risco", "Médio Risco", "Alto Risco" e outros |

Exemplo de payload para envio do resultado do Quiz:

```json
{
  "score": 950,
  "result_enum": "low_risk",
  "result_description": "Baixo Risco"
}
```

---

# RentalAgreement-v1

URL: /documentation/caas/car_rental/rental_agreement

Ao realizar a retirada de um veículo na loja, o locatário dá início ao seu processo de anti-fraude. Os dados enviados deverão ser os dados finais, que não serão alterados. Isto é importante para garantir dois pontos:

- Consistência dos dados na base de dados do Antifraude
- Avaliação realista do risco

O processo de análise consiste em enviar um RentalAgreement no endpoint adequado e esperar a resposta. Existem oito resultados possíveis, devolvido na flag **fraud_status**:

| Resultado | Descrição |
| :---------: | --------- |
| Aprovado Automaticamente | Recomenda-se que este aluguel seja aprovado |
| Negado Automaticamente | Recomenda-se que este aluguel seja reprovado |
| Derivado para análise manual | Nossas regras ou modelos não estão confiantes da decisão e decidiram enviar este aluguel para a análise manual. |
| Aprovado Manualmente | Após análise manual, o analista escolheu aprovar o aluguel |
| Reprovado Manualmente | Após análise manual, o analista escolheu reprovar o aluguel |
| Desafiado Manualmente | Após análise manual, o analista retorna para a loja que a CNH e/ou Selfie estão incorretas e/ou com baixa qualidade |
| Pendente | As consultas estão demorando mais do que o esperado, este aluguel entrou em uma fila de análise automática e será respondido por meio de Webhook |
| Não analisado | A consulta foi enviada com a flag de análise falsa, o que significa que nossos sistemas não deverão retornar parecer |

### Dinâmica dos Status

Ao recuperar um objeto do tipo RentalAgreement os status estão disponíveis. Além dos status, um histórico de modificações também são retornados para que possa ser consultado no futuro. Estas modificações são entituladas events e possuem, além do novo status, as datas de modificação.

### Dinâmica dos Status - **car_status**

O status **car_status** relacionado a um RentalAgreement indica a situação do carro relacionado a este aluguel, isto é, se o carro foi devolvido ou não. Os seguintes enumeradores existem para este status:

- `rented`
- `returned`
- `recovered`
- `written_off`

### Dinâmica dos Status - **fraud_status**

O status **fraud_status** indica o status da decisão do motor de fraude e possui uma máquina de estados bastante simples:

- `created`
- `automatically_approved`
- `automatically_reproved`
- `in_manual_analysis`
- `manually_approved`
- `manually_reproved`
- `manually_challenged`
- `pending`
- `not_analyzed`

Além disso, o upgrade_status também possui os mesmos enumeradores.

### Motoristas adicionais e responsáveis financeiros

Além do locatário principal, enviado em `client`, um RentalAgreement pode carregar outras pessoas envolvidas no aluguel:

- **Motoristas adicionais** (`additional_drivers`): lista de pessoas autorizadas a conduzir o veículo além do locatário principal.
- **Responsável financeiro** (`financial_manager`): pessoa física ou jurídica indicada como responsável pelo pagamento do aluguel. Existe no máximo um responsável financeiro por aluguel.

Ambos os campos utilizam a definição do objeto *participant*, cuja estrutura é idêntica à do objeto *client*.

Cada participante enviado passa pelas **mesmas consultas e análises antifraude** aplicadas ao locatário principal, de maneira que estes dados também alimentam a base de dados do Antifraude. O resultado individual de cada participante é devolvido na resposta da análise, conforme descrito em [Enviar um RentalAgreement](#enviar-um-rentalagreement). No entanto, este resultado **não altera o fraud_status do RentalAgreement**, que continua sendo determinado pela avaliação do locatário principal.

Ambos os campos são opcionais e podem ser omitidos quando não houver participantes além do locatário principal.

## Definição do Objeto

```json
{
  "id": "bca6268e-918a-4658-9161-a10b00a631ab",
  "rental_agreement_code" : "12345678",
  "rental_agreement_date": "2020-03-31T10:30:00-03:00",
  "car_rental_estimated_final_date":  "2020-04-01T10:28:00-03:00",
  "reservation": {
    "id": "0",
    "channel": "reservation_central",
    "reservation_date": "2020-03-31T08:15:00-03:00",
    "sales_channel" : "PARCERIA TELEFONICA"
  },
  "rental_store": "SAOP",
  "rental_store_group": "GSP",
  "rental_store_type": "LOJA DE RUA",
  "devolution_store": "SAOP",
  "risky_antecedence": true,
  "car": {
    "model_group": "AM",
    "upgrade_model_group": "SV",
    "rental_daily_price" : 48496,
    "risky_model_group": true,
    "risky_upgrade_model_group": true
  },
  "client": {
    "type": "natural_person",
    "segment": "ota",
    "document_number": "123.456.789-00",
    "name": "John Sample",
    "gender": "female",
    "birthdate": "2001-01-15",
    "mother_name": "Mary Sample",
    "email": "john.sample@sample.com.br",
    "allowed_information_on_email": true,
    "face_picture": "c77d1925-0e72-4634-8393-395dbbce498d",
    "additional_pictures": [
      "718b8caa-8ef5-446c-b101-2dbf6c7e401f",
      "9c67f365-1427-4889-b963-d3729d437ff3",
      "8006f82c-3a80-4371-914e-e88c91507711",
      "42c6909e-51aa-4b6d-972f-f4684a047993",
      "b7a88947-96bd-4557-81e9-a69a3c84f428"
    ],
    "total_rents": 6,
    "fidelity_points": 1200,
    "documents": {
      "rg": {
        "document_number": "00000000",
        "issuer": "SSP"
      },
      "cnh": {
        "document_number": "000000000",
        "security_code": "00000",
        "first_issuance": "2015-07-20",
        "expiration_date": "2030-07-26",
        "state": "SP"
      }
    },
    "residential_address": {
      "street": "Av Brigadeiro Faria Lima",
      "number": "2391",
      "neighborhood": "Jardins",
      "city": "SÃO PAULO",
      "uf": "SP",
      "complement": "",
      "postal_code": "00000-000"
    },
    "commercial_address": {
      "street": "Av Brigadeiro Faria Lima",
      "number": "2391",
      "neighborhood": "Jardins",
      "city": "SÃO PAULO",
      "uf": "SP",
      "complement": "",
      "postal_code": "00000-000"
    },
    "phones": [
      {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "00000-0000",
        "type": "mobile"
      },
      {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "00000-0000",
        "type": "residential"
      }
    ]
  },
  "additional_drivers": [
    {
      "type": "natural_person",
      "document_number": "987.654.321-00",
      "name": "Jane Sample",
      "gender": "female",
      "email": "jane.sample@sample.com.br",
      "allowed_information_on_email": true,
      "face_picture": "e3b0c442-98fc-1c14-9afb-f4c8996fb924",
      "documents": {
        "cnh": {
          "document_number": "000000000",
          "security_code": "00000",
          "first_issuance": "2018-03-10",
          "expiration_date": "2028-03-10",
          "state": "SP"
        }
      },
      "phones": [
        {
          "international_dial_code": "55",
          "area_code": "11",
          "number": "00000-0000",
          "type": "mobile"
        }
      ]
    }
  ],
  "financial_manager": {
    "type": "legal_person",
    "document_number": "00.000.000/0001-00",
    "name": "Empresa Sample LTDA",
    "gender": "undefined",
    "email": "financeiro@sample.com.br",
    "allowed_information_on_email": false,
    "documents": {},
    "phones": [
      {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "00000-0000",
        "type": "commercial"
      }
    ]
  },
  "coverages": [
    {
      "description": "S/ PROTEÇÃO AMERICAN PLATINUM",
      "price": 0
    },
    {
      "description": "PROTEÇÃO OCUPANTES E TERCEIROS",
      "price": 1668
    }
  ],
  "billing": {
    "name": "Agência AAA",
    "document_number": "00.000.000/0001-00",
    "voucher_type": "ABCD75",
    "voucher_description": "Pagamento pela agência"
  },
  "fare_name": "Mensal",
  "rental_price": 43300,
  "extra_hours": 0,
  "extra_hours_price": 0,
  "discount": 0,
  "prepayment_discount": 100,
  "extra_kms": 0,
  "extra_kms_price": 0,
  "third_party_coverage_price": 1490,
  "coverage_price": 0,
  "additional_driver_price": 1000,
  "driver_service_price": 1000,
  "additional_expenses": 1000,
  "devolution_fee": 0,
  "administration_fee": 5374,
  "discount_partial_coverage": 50,
  "free_day_discount": 20000,
  "final_price": 50165,
  "pre_authorization_amount": 0,
  "coverage_deductible_amount": 0,
  "upgrade_reason": "granted"
}
```

Todas as trocas de informação de um RentalAgreement utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

| nome | tipo | descrição |
| :----: | :----: | --------- |
| **id** | string | Identificador da requisição de análise no sistema do cliente. **É essencial que este número seja único para cada aluguel.** *(obrigatório)* |
| **rental_agreement_code** | string | Identificador do RentalAgreement no sistema do cliente. *(obrigatório)* |
| **rental_agreement_date** | DateTime | Data e Hora com fuso-horário da retirada do veículo do aluguel que está ocorrendo. *(obrigatório)* |
| **car_rental_estimated_final_date** | DateTime | Data e Hora com fuso-horário de quando o carro deve ser resolvido. *(obrigatório)* |
| **reservation** | *reservation* | Objeto que carrega as propriedades da reserva que deu origem a esse aluguel. *(obrigatório)* |
| **rental_store** | *store* | Loja onde o carro está sendo retirado. *(obrigatório)* |
| rental_store_group | *store* | Filial da loja onde o carro está sendo retirado |
| rental_store_type | *store* | Tipo da loja onde o carro será retirado |
| **devolution_store** | *store* | Loja onde o carro será devolvido, pode ou não ser a mesma loja de retirada. *(obrigatório)* |
| **car** | *car* | Carro que está sendo retirado - é importante que este valor seja, de fato, o carro sendo retirado. *(obrigatório)* |
| **client** | *client* | Objeto que carrega as informações do cliente que está retirando o veículo. *(obrigatório)* |
| additional_drivers | List of *participant* | Lista com os motoristas adicionais autorizados a conduzir o veículo neste aluguel. |
| financial_manager | *participant* | Pessoa física ou jurídica indicada como responsável financeiro deste aluguel. |
| **coverages** | List of *coverage* | Lista de objetos coverage que descrevem as coberturas de seguro contratadas pelo cliente. *(obrigatório)* |
| **billing** | *billing* | Objeto que descreve os detalhes da pessoa ou empresa responsável pelo pagamento do aluguel. *(obrigatório)* |
| **rental_price** | integer | Preço do aluguel, em centavos. *(obrigatório)* |
| **extra_hours** | integer | Quantidade de horas extras contratadas. *(obrigatório)* |
| **extra_hours_price** | integer | Preço das horas extras contratadas, em centavos. *(obrigatório)* |
| **discount** | inteiro | Desconto concedido por quaisquer motivos, em centavos. *(obrigatório)* |
| **prepayment_discount** | inteiro | Desconto por pagamento antecipado. |
| **extra_kms** | integer | Quantidade de kilômetros extras contratados. *(obrigatório)* |
| **extra_kms_price** | integer | Preço de kilômetros extras contratados, em centavos. *(obrigatório)* |
| **third_party_coverage_price** | integer | Preço do seguro de terceiros, em centavos. *(obrigatório)* |
| **coverage_price** | integer | Preço do seguro contratado, em centavos. *(obrigatório)* |
| additional_driver_price | integer | Preço total do(s) motoristas adicionais contratados, em centavos. |
| driver_service_price | integer | Preço total do serviço de motorista contratado, em centavos. |
| additional_expenses | integer | Despesas adicionais, em centavos |
| **devolution_fee** | integer | Preço da taxa de devolução, em centavos. *(obrigatório)* |
| **administration_fee** | integer | Preço da taxa de administração, em centavos. *(obrigatório)* |
| **discount_partial_coverage** | integer | Desconto de proteção parcial, em centavos. |
| **free_day_discount** | integer | Desconto de Free Day, em centavos. |
| **final_price** | integer | Preço final do aluguel, em centavos. *(obrigatório)* |
| pre_authorization_amount | integer | Valor da pré-autorização, em centavos. |
| **coverage_deductible_amount** | integer | Valor dedutível da cobertura, em centavos. *(obrigatório)* |
| upgrade_reason | enum | Tipo de upgrade (Concedido ou Comprado) - Aceita os valores `granted` e `bought` respectivamente |

## Enviar um RentalAgreement

Exemplo de Request:

```json
{
  "id": "bca6268e-918a-4658-9161-a10b00a631ab",
  ...
}
```

Exemplo de Retorno:

```json
{
  "id": "bca6268e-918a-4658-9161-a10b00a631ab",
  "fraud_status": "automatically_approved",
  "financial_manager": {
    "fraud_status": "automatically_approved"
  },
  "additional_drivers": [
    {
      "id": "1111111",
      "fraud_status": "automatically_approved"
    }
  ],
  "pre_authorization_amount": 100000,
  "block_document_number": true,
  "upgrade_status": "automatically_approved",
  "highest_allowed_car_group": "SV",
  "score": 870
}
```

Caso o aluguel tenha sido enviado com motoristas adicionais e/ou responsável financeiro, o resultado individual da análise de cada um deles também é retornado:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| financial_manager.fraud_status | enum | Resultado da análise antifraude do responsável financeiro. Utiliza os mesmos enumeradores do **fraud_status** do RentalAgreement. |
| additional_drivers[].id | string | Identificador do motorista adicional analisado. |
| additional_drivers[].fraud_status | enum | Resultado da análise antifraude daquele motorista adicional. Utiliza os mesmos enumeradores do **fraud_status** do RentalAgreement. |

:::note
Estes status são informativos e independentes: um motorista adicional ou responsável financeiro reprovado **não altera** o **fraud_status** do RentalAgreement. Cabe à locadora decidir o que fazer com o participante reprovado, como recusar a inclusão daquele motorista no aluguel.
:::

Para realizar a avaliação de um aluguel, basta enviar um objeto do tipo RentalAgreement ao seguinte endpoint com a flag setada adequadamente:

`POST https://api.caas.qitech.app/car_rental/rental_agreement?analyze=true`

Além do status do retorno, também é retornado, caso haja, o valor da pré autorização desejada. Caso nenhuma majoração de pré autorização seja identificada, o valor retornado é nulo e não deve ser utilizado.

O grupo máximo que pode ser fornecido naquele RA é disponibilizado na variável `highest_allowed_car_group`. Este valor é configurado na regra de avaliação do RA.

O parâmetro *analyze* existe para evitar que transações que não precisam ser analisadas passem pelos motores de fraude, sujando a base de dados. O valor padrão deste parâmetro é **true**, de maneira que somente alugueis que forem explícitamente retirados da análise não serão analisados.

## Atualizar o status de um RentalAgreement

Corpo da requisição - Na efetivação de um aluguel de um carro:

```json
{
  "car_status": "rented",
  "event_date": "2019-11-05T13:34:12-03:00"
}
```

Corpo da requisição - Na devolução sem incidentes de um carro:

```json
{
  "car_status": "returned",
  "event_date": "2019-11-05T13:34:12-03:00"
}
```

Corpo da requisição - Na devolução mediante recuperação por roubo:

```json
{
  "car_status": "recovered",
  "incident": "theft",
  "event_date": "2019-11-05T13:34:12-03:00"
}
```

Corpo da requisição - Write-off com fraude confirmada:

```json
{
  "car_status": "written_off",
  "incident": "misappropriation",
  "event_date": "2019-11-05T13:34:12-03:00"
}
```

Para garantir a retroalimentação das regras e do modelo de inteligência artificial implementado, é necessário informar ao sistema quando os carros são alugados, devolvidos, ou quando são jogados a perda por fraude. Para isso, requisições com o método PUT devem ser utilizadas, passando-se como referência o id enviado na criação do *rental_agreement*, autenticadas normalmente:

`PUT https://api.caas.qitech.app/car_rental/rental_agreement/{rental_agreement_id}`

Caso o novo status seja *written_off*, os seguintes valores podem ser utilizados no campo **incident**, enviado no body da requisição, que indica o tipo de incidente do aluguel:

| Enumerador | Descrição |
| --------- | ----------- |
| theft | RAs que sofreram um roubo |
| misappropriation | RAs que foram classificados como apropriação indébita |

## Atualizar o veículo de um RentalAgreement

Corpo da requisição - Atualização de um veículo no aluguel:

```json
{
  "car_plate": "ABC1B34",
  "car_model": "Chevrolet Onix",
  "model_group": "B",
  "event_date": "2020-10-15T13:34:12-03:00"
}
```

Para garantir a consistência entre as ocorrências de fraude e os aluguéis e garantir o retreinamento do modelo de score, é necessário informar ao sistema os dados de cada carro quando ele é atrelado ao aluguel. Para isso, requisições com o método POST devem ser utilizadas, passando-se como referência o id enviado na criação do *rental_agreement*, autenticadas normalmente:

`POST https://api.caas.qitech.app/car_rental/rental_agreement/{rental_agreement_id}/car`

No body da requisição devem ser enviados os dados do veículo que está sendo atrelado àquele aluguel:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| car_plate | string | Placa do veículo. |
| car_model | string | Modelo do veículo, incluindo sua marca e modelo (ex.: Jeep Renegade). |
| model_group | string | O grupo do veículo, em letras maiúsculas. |
| event_date | DateTime | Data e Hora com fuso-horário do momento em que ocorreu a associação do carro ao aluguel. |

## Recuperar um RentalAgreement

A fim de recuperar um RentalAgreement específico, basta realizar uma requisição GET. O resultado retornado é o json mais atualizado do RentalAgreement em questão. Caso este identificador não esteja relacionado a nenhum objeto, o HTTP Status 404 é retornado.

`GET https://api.caas.qitech.app/car_rental/rental_agreements/{rental_agreement_id}`

```shell
curl "https://api.caas.qitech.app/car_rental/rental_agreements/{rental_agreement_id}"
  -H "Authorization: TESTETESTETESTE"
```

## Buscar RentalAgreements

Retorno - uma lista de objetos RentalAgreement:

```json
[
  {
    "id": "bca6268e-918a-4658-9161-a10b00a631ab",
    ...
  },
  {
    "id": "13a91409-9793-49b6-8583-9ba575075831",
    ...
  }
]
```

Caso seja necessário buscar um RentalAgreement, um GET com parâmetros de query poderá ser utilizado. O resultado retornado é um JSON que representa uma lista de RentalAgreements. Caso nenhum objeto seja encontrado com os parâmetros enviados, o HTTP Status 200 é retornado com uma lista vazia no corpo da resposta.

`GET https://api.caas.qitech.app/car_rental/rental_agreements?initial_date=2019-10-01&final_date=2019-10-05&page_number=2&page_rows=20`

Os seguintes parâmetros podem ser utilizados para buscar objetos de RentalAgreement:

| Parâmetro | Padrão | Descrição |
| --------- | ----------- | -------------- |
| initial_date | null | Primeira data que deve ser retornada a partir do campo rental_agreement_date |
| final_date | null | Última data que deve ser retornada a partir do campo rental_agreement_date |
| store_code | null | Código da loja de onde os resultados devem ser retornados |
| page_number | 1 | Número da página de resultados desejada |
| page_rows | 50 | Número de objetos máximo a ser retornados em uma consulta |

---

# RentalAgreement-v2

URL: /documentation/caas/car_rental/rental_agreement_v2

Esta seção diz respeito ao fluxo de análise de fraude com a scoragem principal ocorrendo na reserva.

Ao realizar a retirada de um veículo na loja, o locatário dá início ao seu processo de anti-fraude. Os dados enviados deverão ser os dados finais, que não serão alterados. Isto é importante para garantir dois pontos:

- Consistência dos dados na base de dados do Antifraude
- Avaliação realista do risco

O processo de análise consiste em enviar um RentalAgreement no endpoint adequado e esperar a resposta. Existem oito resultados possíveis, devolvido na flag **fraud_status**:

| Resultado | Descrição |
| :---------: | --------- |
| Aprovado Automaticamente | Recomenda-se que este aluguel seja aprovado |
| Negado Automaticamente | Recomenda-se que este aluguel seja reprovado |
| Derivado para análise manual | Nossas regras ou modelos não estão confiantes da decisão e decidiram enviar este aluguel para a análise manual. |
| Aprovado Manualmente | Após análise manual, o analista escolheu aprovar o aluguel |
| Reprovado Manualmente | Após análise manual, o analista escolheu reprovar o aluguel |
| Desafiado Manualmente | Após análise manual, o analista retorna para a loja que a CNH e/ou Selfie estão incorretas e/ou com baixa qualidade |
| Pendente | As consultas estão demorando mais do que o esperado, este aluguel entrou em uma fila de análise automática e será respondido por meio de Webhook |
| Não analisado | A consulta foi enviada com a flag de análise falsa, o que significa que nossos sistemas não deverão retornar parecer |

### Dinâmica dos Status

Ao recuperar um objeto do tipo RentalAgreement os status estão disponíveis. Além dos status, um histórico de modificações também são retornados para que possa ser consultado no futuro. Estas modificações são entituladas events e possuem, além do novo status, as datas de modificação.

### Dinâmica dos Status - **car_status**

O status **car_status** relacionado a um RentalAgreement indica a situação do carro relacionado a este aluguel, isto é, se o carro foi devolvido ou não. Os seguintes enumeradores existem para este status:

- `rented`
- `returned`
- `recovered`
- `written_off`

### Dinâmica dos Status - **fraud_status**

O status **fraud_status** indica o status da decisão do motor de fraude e possui uma máquina de estados bastante simples:

- `created`
- `automatically_approved`
- `automatically_reproved`
- `in_manual_analysis`
- `manually_approved`
- `manually_reproved`
- `manually_challenged`
- `pending`
- `not_analyzed`

Além disso, o upgrade_status também possui os mesmos enumeradores.

## Definição do Objeto

```json
{
  "id": "bca6268e-918a-4658-9161-a10b00a631ab",
  "rental_agreement_code" : "12345678",
  "rental_agreement_date": "2020-03-31T10:30:00-03:00",
  "car_rental_estimated_final_date":  "2020-04-01T10:28:00-03:00",
  "reservation": {
    "id": "0",
    "channel": "reservation_central",
    "reservation_date": "2020-03-31T08:15:00-03:00",
    "sales_channel" : "PARCERIA TELEFONICA"
  },
  "rental_store": "SAOP",
  "rental_store_group": "GSP",
  "rental_store_type": "LOJA DE RUA",
  "devolution_store": "SAOP",
  "risky_antecedence": true,
  "car": {
    "model_group": "AM",
    "upgrade_model_group": "SV",
    "rental_daily_price" : 48496,
    "risky_model_group": true,
    "risky_upgrade_model_group": true
  },
  "client": {
    "type": "natural_person",
    "segment": "ota",
    "document_number": "123.456.789-00",
    "name": "John Sample",
    "gender": "female",
    "birthdate": "2001-01-15",
    "mother_name": "Mary Sample",
    "email": "john.sample@sample.com.br",
    "allowed_information_on_email": true,
    "face_picture": "c77d1925-0e72-4634-8393-395dbbce498d",
    "additional_pictures": [
      "718b8caa-8ef5-446c-b101-2dbf6c7e401f",
      "9c67f365-1427-4889-b963-d3729d437ff3",
      "8006f82c-3a80-4371-914e-e88c91507711",
      "42c6909e-51aa-4b6d-972f-f4684a047993",
      "b7a88947-96bd-4557-81e9-a69a3c84f428"
    ],
    "total_rents": 6,
    "fidelity_points": 1200,
    "documents": {
      "rg": {
        "document_number": "00000000",
        "issuer": "SSP"
      },
      "cnh": {
        "document_number": "000000000",
        "security_code": "00000",
        "first_issuance": "2015-07-20",
        "expiration_date": "2030-07-26",
        "state": "SP"
      }
    },
    "residential_address": {
      "street": "Av Brigadeiro Faria Lima",
      "number": "2391",
      "neighborhood": "Jardins",
      "city": "SÃO PAULO",
      "uf": "SP",
      "complement": "",
      "postal_code": "00000-000"
    },
    "commercial_address": {
      "street": "Av Brigadeiro Faria Lima",
      "number": "2391",
      "neighborhood": "Jardins",
      "city": "SÃO PAULO",
      "uf": "SP",
      "complement": "",
      "postal_code": "00000-000"
    },
    "phones": [
      {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "00000-0000",
        "type": "mobile"
      },
      {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "00000-0000",
        "type": "residential"
      }
    ]
  },
  "coverages": [
    {
      "description": "S/ PROTEÇÃO AMERICAN PLATINUM",
      "price": 0
    },
    {
      "description": "PROTEÇÃO OCUPANTES E TERCEIROS",
      "price": 1668
    }
  ],
  "billing": {
    "name": "Agência AAA",
    "document_number": "00.000.000/0001-00",
    "voucher_type": "ABCD75",
    "voucher_description": "Pagamento pela agência"
  },
  "fare_name": "Mensal",
  "rental_price": 43300,
  "extra_hours": 0,
  "extra_hours_price": 0,
  "discount": 0,
  "prepayment_discount": 100,
  "extra_kms": 0,
  "extra_kms_price": 0,
  "third_party_coverage_price": 1490,
  "coverage_price": 0,
  "additional_driver_price": 1000,
  "driver_service_price": 1000,
  "additional_expenses": 1000,
  "devolution_fee": 0,
  "administration_fee": 5374,
  "discount_partial_coverage": 50,
  "free_day_discount": 20000,
  "final_price": 50165,
  "pre_authorization_amount": 0,
  "coverage_deductible_amount": 0,
  "upgrade_reason": "granted"
}
```

Todas as trocas de informação de um RentalAgreement utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

| nome | tipo | descrição |
| :----: | :----: | --------- |
| **id** | string | Identificador da requisição de análise no sistema do cliente. **É essencial que este número seja único para cada aluguel.** *(obrigatório)* |
| **rental_agreement_code** | string | Identificador do RentalAgreement no sistema do cliente. *(obrigatório)* |
| **rental_agreement_date** | DateTime | Data e Hora com fuso-horário da retirada do veículo do aluguel que está ocorrendo. *(obrigatório)* |
| **car_rental_estimated_final_date** | DateTime | Data e Hora com fuso-horário de quando o carro deve ser resolvido. *(obrigatório)* |
| **reservation** | *reservation* | Objeto que carrega as propriedades da reserva que deu origem a esse aluguel. *(obrigatório)* |
| **rental_store** | *store* | Loja onde o carro está sendo retirado. *(obrigatório)* |
| rental_store_group | *store* | Filial da loja onde o carro está sendo retirado |
| rental_store_type | *store* | Tipo da loja onde o carro será retirado |
| **devolution_store** | *store* | Loja onde o carro será devolvido, pode ou não ser a mesma loja de retirada. *(obrigatório)* |
| **car** | *car* | Carro que está sendo retirado - é importante que este valor seja, de fato, o carro sendo retirado. *(obrigatório)* |
| **client** | *client* | Objeto que carrega as informações do cliente que está retirando o veículo. *(obrigatório)* |
| **coverages** | List of *coverage* | Lista de objetos coverage que descrevem as coberturas de seguro contratadas pelo cliente. *(obrigatório)* |
| **billing** | *billing* | Objeto que descreve os detalhes da pessoa ou empresa responsável pelo pagamento do aluguel. *(obrigatório)* |
| **rental_price** | integer | Preço do aluguel, em centavos. *(obrigatório)* |
| **extra_hours** | integer | Quantidade de horas extras contratadas. *(obrigatório)* |
| **extra_hours_price** | integer | Preço das horas extras contratadas, em centavos. *(obrigatório)* |
| **discount** | inteiro | Desconto concedido por quaisquer motivos, em centavos. *(obrigatório)* |
| **prepayment_discount** | inteiro | Desconto por pagamento antecipado. |
| **extra_kms** | integer | Quantidade de kilômetros extras contratados. *(obrigatório)* |
| **extra_kms_price** | integer | Preço de kilômetros extras contratados, em centavos. *(obrigatório)* |
| **third_party_coverage_price** | integer | Preço do seguro de terceiros, em centavos. *(obrigatório)* |
| **coverage_price** | integer | Preço do seguro contratado, em centavos. *(obrigatório)* |
| additional_driver_price | integer | Preço total do(s) motoristas adicionais contratados, em centavos. |
| driver_service_price | integer | Preço total do serviço de motorista contratado, em centavos. |
| additional_expenses | integer | Despesas adicionais, em centavos |
| **devolution_fee** | integer | Preço da taxa de devolução, em centavos. *(obrigatório)* |
| **administration_fee** | integer | Preço da taxa de administração, em centavos. *(obrigatório)* |
| **discount_partial_coverage** | integer | Desconto de proteção parcial, em centavos. |
| **free_day_discount** | integer | Desconto de Free Day, em centavos. |
| **final_price** | integer | Preço final do aluguel, em centavos. *(obrigatório)* |
| pre_authorization_amount | integer | Valor da pré-autorização, em centavos. |
| **coverage_deductible_amount** | integer | Valor dedutível da cobertura, em centavos. *(obrigatório)* |
| upgrade_reason | enum | Tipo de upgrade (Concedido ou Comprado) - Aceita os valores `granted` e `bought` respectivamente |

## Enviar um RentalAgreement

Exemplo de Request:

```json
{
  "id": "bca6268e-918a-4658-9161-a10b00a631ab",
  ...
}
```

Exemplo de Retorno:

```json
{
  "id": "bca6268e-918a-4658-9161-a10b00a631ab",
  "fraud_status": "automatically_approved",
  "pre_authorization_amount": 100000,
  "block_document_number": true,
  "upgrade_status": "automatically_approved",
  "highest_allowed_car_group": "SV",
  "score": 870
}
```

Para realizar a avaliação de um aluguel, basta enviar um objeto do tipo RentalAgreement ao seguinte endpoint com a flag setada adequadamente:

`POST https://api.caas.qitech.app/car_rental/rental_agreement?analyze=true`

Além do status do retorno, também é retornado, caso haja, o valor da pré autorização desejada. Caso nenhuma majoração de pré autorização seja identificada, o valor retornado é nulo e não deve ser utilizado.

O grupo máximo que pode ser fornecido naquele RA é disponibilizado na variável `highest_allowed_car_group`. Este valor é configurado na regra de avaliação do RA.

O parâmetro *analyze* existe para evitar que transações que não precisam ser analisadas passem pelos motores de fraude, sujando a base de dados. O valor padrão deste parâmetro é **true**, de maneira que somente alugueis que forem explícitamente retirados da análise não serão analisados.

## Atualizar o status de um RentalAgreement

Corpo da requisição - Na efetivação de um aluguel de um carro:

```json
{
  "car_status": "rented",
  "event_date": "2019-11-05T13:34:12-03:00"
}
```

Corpo da requisição - Na devolução sem incidentes de um carro:

```json
{
  "car_status": "returned",
  "event_date": "2019-11-05T13:34:12-03:00"
}
```

Corpo da requisição - Na devolução mediante recuperação por roubo:

```json
{
  "car_status": "recovered",
  "incident": "theft",
  "event_date": "2019-11-05T13:34:12-03:00"
}
```

Corpo da requisição - Write-off com fraude confirmada:

```json
{
  "car_status": "written_off",
  "incident": "misappropriation",
  "event_date": "2019-11-05T13:34:12-03:00"
}
```

Para garantir a retroalimentação das regras e do modelo de inteligência artificial implementado, é necessário informar ao sistema quando os carros são alugados, devolvidos, ou quando são jogados a perda por fraude. Para isso, requisições com o método PUT devem ser utilizadas, passando-se como referência o id enviado na criação do *rental_agreement*, autenticadas normalmente:

`PUT https://api.caas.qitech.app/car_rental/rental_agreement/{rental_agreement_id}`

Caso o novo status seja *written_off*, os seguintes valores podem ser utilizados no campo **incident**, enviado no body da requisição, que indica o tipo de incidente do aluguel:

| Enumerador | Descrição |
| --------- | ----------- |
| theft | RAs que sofreram um roubo |
| misappropriation | RAs que foram classificados como apropriação indébita |

## Atualizar o veículo de um RentalAgreement

Corpo da requisição - Atualização de um veículo no aluguel:

```json
{
  "car_plate": "ABC1B34",
  "car_model": "Chevrolet Onix",
  "model_group": "B",
  "event_date": "2020-10-15T13:34:12-03:00"
}
```

Para garantir a consistência entre as ocorrências de fraude e os aluguéis e garantir o retreinamento do modelo de score, é necessário informar ao sistema os dados de cada carro quando ele é atrelado ao aluguel. Para isso, requisições com o método POST devem ser utilizadas, passando-se como referência o id enviado na criação do *rental_agreement*, autenticadas normalmente:

`POST https://api.caas.qitech.app/car_rental/rental_agreement/{rental_agreement_id}/car`

No body da requisição devem ser enviados os dados do veículo que está sendo atrelado àquele aluguel:

| nome | tipo | descrição |
| ---- | :----: | --------- |
| car_plate | string | Placa do veículo. |
| car_model | string | Modelo do veículo, incluindo sua marca e modelo (ex.: Jeep Renegade). |
| model_group | string | O grupo do veículo, em letras maiúsculas. |
| event_date | DateTime | Data e Hora com fuso-horário do momento em que ocorreu a associação do carro ao aluguel. |

## Recuperar um RentalAgreement

A fim de recuperar um RentalAgreement específico, basta realizar uma requisição GET. O resultado retornado é o json mais atualizado do RentalAgreement em questão. Caso este identificador não esteja relacionado a nenhum objeto, o HTTP Status 404 é retornado.

`GET https://api.caas.qitech.app/car_rental/rental_agreements/{rental_agreement_id}`

```shell
curl "https://api.caas.qitech.app/car_rental/rental_agreements/{rental_agreement_id}"
  -H "Authorization: TESTETESTETESTE"
```

## Buscar RentalAgreements

Retorno - uma lista de objetos RentalAgreement:

```json
[
  {
    "id": "bca6268e-918a-4658-9161-a10b00a631ab",
    ...
  },
  {
    "id": "13a91409-9793-49b6-8583-9ba575075831",
    ...
  }
]
```

Caso seja necessário buscar um RentalAgreement, um GET com parâmetros de query poderá ser utilizado. O resultado retornado é um JSON que representa uma lista de RentalAgreements. Caso nenhum objeto seja encontrado com os parâmetros enviados, o HTTP Status 200 é retornado com uma lista vazia no corpo da resposta.

`GET https://api.caas.qitech.app/car_rental/rental_agreements?initial_date=2019-10-01&final_date=2019-10-05&page_number=2&page_rows=20`

Os seguintes parâmetros podem ser utilizados para buscar objetos de RentalAgreement:

| Parâmetro | Padrão | Descrição |
| --------- | ----------- | -------------- |
| initial_date | null | Primeira data que deve ser retornada a partir do campo rental_agreement_date |
| final_date | null | Última data que deve ser retornada a partir do campo rental_agreement_date |
| store_code | null | Código da loja de onde os resultados devem ser retornados |
| page_number | 1 | Número da página de resultados desejada |
| page_rows | 50 | Número de objetos máximo a ser retornados em uma consulta |

---

# Reservation-v1

URL: /documentation/caas/car_rental/reservation

Ao realizar a reserva de um veículo, o locatário dá início ao seu processo de anti-fraude. Os dados enviados deverão ser os dados finais da reserva, que não serão alterados. Isto é importante para garantir dois pontos:

- Consistência dos dados na base de dados do Antifraude
- Avaliação realista do risco

O processo de análise consiste em enviar uma Reservation no endpoint adequado e esperar a resposta. Existem oito resultados possíveis, devolvido na flag **fraud_status**:

| Resultado | Descrição |
| :---------: | --------- |
| Aprovado Automaticamente | Recomenda-se que este aluguel seja aprovado |
| Negado Automaticamente | Recomenda-se que este aluguel seja reprovado |
| Derivado para análise manual | Nossas regras ou modelos não estão confiantes da decisão e decidiram enviar este aluguel para a análise manual. |
| Aprovado Manualmente | Após análise manual, o analista escolheu aprovar o aluguel |
| Reprovado Manualmente | Após análise manual, o analista escolheu reprovar o aluguel |
| Desafiado Manualmente | Após análise manual, o analista retorna para a loja que a CNH e/ou Selfie estão incorretas e/ou com baixa qualidade |
| Pendente | As consultas estão demorando mais do que o esperado, este aluguel entrou em uma fila de análise automática e será respondido por meio de Webhook |
| Não analisado | A consulta foi enviada com a flag de análise falsa, o que significa que nossos sistemas não deverão retornar parecer |

### Dinâmica dos Status

Ao recuperar um objeto do tipo Reservation os status estão disponíveis. Além dos status, um histórico de modificações também são retornados para que possa ser consultado no futuro. Estas modificações são entituladas events e possuem, além do novo status, as datas de modificação.

### Dinâmica dos Status - **fraud_status**

O status **fraud_status** indica o status da decisão do motor de fraude e possui uma máquina de estados bastante simples:

- `created`
- `automatically_approved`
- `automatically_reproved`
- `in_manual_analysis`
- `manually_approved`
- `manually_reproved`
- `pending`
- `not_analyzed`

## Definição do Objeto

```json
{
  "id": "bca6268e-918a-4658-9161-a10b00a631ab",
  "reservation_code": "211034324",
  "reservation_date": "2020-03-31T08:15:00-03:00",
  "rental_agreement_date": "2020-03-31T10:30:00-03:00",
  "car_rental_estimated_final_date":  "2020-04-01T10:28:00-03:00",
  "channel": "reservation_central",
  "sales_channel" : "PARCERIA TELEFONICA",
  "rental_store": "SAOP",
  "rental_store_group": "GSP",
  "rental_store_type": "LOJA DE RUA",
  "devolution_store": "SAOP",
  "car": {
    "model_group": "SV",
    "rental_daily_price" : 48496
  },
  "client": {
    "type": "natural_person",
    "segment": "ota",
    "document_number": "123.456.789-00",
    "name": "John Sample",
    "gender": "female",
    "birthdate": "2001-01-15",
    "mother_name": "Mary Sample",
    "email": "john.sample@sample.com.br",
    "allowed_information_on_email": true,
    "face_picture": "c77d1925-0e72-4634-8393-395dbbce498d",
    "additional_pictures": [
      "718b8caa-8ef5-446c-b101-2dbf6c7e401f",
      "9c67f365-1427-4889-b963-d3729d437ff3",
      "8006f82c-3a80-4371-914e-e88c91507711",
      "42c6909e-51aa-4b6d-972f-f4684a047993",
      "b7a88947-96bd-4557-81e9-a69a3c84f428"
    ],
    "documents": {
      "rg": {
        "document_number": "00000000",
        "issuer": "SSP"
      },
      "cnh": {
        "document_number": "000000000",
        "security_code": "00000",
        "first_issuance": "2015-07-20",
        "expiration_date": "2030-07-26",
        "state": "SP"
      }
    },
    "residential_address": {
      "street": "Av Brigadeiro Faria Lima",
      "number": "2391",
      "neighborhood": "Jardins",
      "city": "SÃO PAULO",
      "uf": "SP",
      "complement": "",
      "postal_code": "00000-000"
    },
    "commercial_address": {
      "street": "Av Brigadeiro Faria Lima",
      "number": "2391",
      "neighborhood": "Jardins",
      "city": "SÃO PAULO",
      "uf": "SP",
      "complement": "",
      "postal_code": "00000-000"
    },
    "phones": [
      {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "00000-0000",
        "type": "mobile"
      },
      {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "00000-0000",
        "type": "residential"
      }
    ]
  },
  "coverages": [
    {
      "description": "S/ PROTEÇÃO AMERICAN PLATINUM",
      "price": 0
    },
    {
      "description": "PROTEÇÃO OCUPANTES E TERCEIROS",
      "price": 1668
    }
  ],
  "billing": {
    "name": "Agência AAA",
    "document_number": "00.000.000/0001-00",
    "voucher_type": "ABCD75",
    "voucher_description": "Pagamento pela agência"
  },
  "rental_price": 43300,
  "extra_hours": 0,
  "extra_hours_price": 0,
  "discount": 0,
  "prepayment_discount": 100,
  "extra_kms": 0,
  "extra_kms_price": 0,
  "third_party_coverage_price": 1490,
  "coverage_price": 0,
  "additional_driver_price": 1000,
  "driver_service_price": 1000,
  "additional_expenses": 1000,
  "devolution_fee": 0,
  "administration_fee": 5374,
  "discount_partial_coverage": 50,
  "final_price": 50165,
  "pre_authorization_amount": 0,
  "coverage_deductible_amount": 0
}
```

Todas as trocas de informação de uma Reservation utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

| nome | tipo | descrição |
| :----: | :----: | --------- |
| **id** | string | Identificador da requisição de análise no sistema do cliente. **É essencial que este número seja único para cada análise.** *(obrigatório)* |
| reservation_code | string | Identificador da Reserva no sistema do cliente. - Este campo é opcional e pode ser definido utilizando o método PUT |
| **reservation_date** | DateTime | Data e Hora com fuso-horário do momento em que ocorreu a reserva para este aluguel. *(obrigatório)* |
| **rental_agreement_date** | DateTime | Data e Hora com fuso-horário da retirada do veículo do aluguel. *(obrigatório)* |
| **car_rental_estimated_final_date** | DateTime | Data e Hora com fuso-horário de quando o carro deve ser resolvido. *(obrigatório)* |
| **rental_store** | *store* | Loja onde o carro será retirado. *(obrigatório)* |
| rental_store_group | *store* | Filial da loja onde o carro será retirado |
| rental_store_type | *store* | Tipo da loja onde o carro será retirado |
| **devolution_store** | *store* | Loja onde o carro será devolvido, pode ou não ser a mesma loja de retirada. *(obrigatório)* |
| reservation_channel | string | Canal pelo qual foi feito a reserva para este aluguel. |
| **sales_channel** | string | Canal de vendas pelo qual a reserva foi realizada (ex.: PARCERIA MASTERCARD). *(obrigatório)* |
| **car** | *car* | Carro que será retirado. *(obrigatório)* |
| **client** | *client* | Objeto que carrega as informações do cliente que fará a retirada do veículo. *(obrigatório)* |
| **coverages** | List of *coverage* | Lista de objetos coverage que descrevem as coberturas de seguro contratadas pelo cliente. *(obrigatório)* |
| billing | *billing* | Objeto que descreve os detalhes da pessoa ou empresa responsável pelo pagamento do aluguel. |
| **rental_price** | integer | Preço do aluguel, em centavos. *(obrigatório)* |
| **extra_hours** | integer | Quantidade de horas extras contratadas. *(obrigatório)* |
| **extra_hours_price** | integer | Preço das horas extras contratadas, em centavos. *(obrigatório)* |
| **discount** | inteiro | Desconto concedido por quaisquer motivos, em centavos. *(obrigatório)* |
| **prepayment_discount** | inteiro | Desconto por pagamento antecipado. *(obrigatório)* |
| **extra_kms** | integer | Quantidade de kilômetros extras contratados. *(obrigatório)* |
| **extra_kms_price** | integer | Preço de kilômetros extras contratados, em centavos. *(obrigatório)* |
| **third_party_coverage_price** | integer | Preço do seguro de terceiros, em centavos. *(obrigatório)* |
| coverage_price | integer | Preço do seguro contratado, em centavos. |
| **additional_driver_price** | integer | Preço total do(s) motoristas adicionais contratados, em centavos. *(obrigatório)* |
| **driver_service_price** | integer | Preço total do serviço de motorista contratado, em centavos. *(obrigatório)* |
| **additional_expenses** | integer | Despesas adicionais, em centavos. *(obrigatório)* |
| **devolution_fee** | integer | Preço da taxa de devolução, em centavos. *(obrigatório)* |
| **administration_fee** | integer | Preço da taxa de administração, em centavos. *(obrigatório)* |
| **discount_partial_coverage** | integer | Desconto de proteção parcial, em centavos. *(obrigatório)* |
| **final_price** | integer | Preço final do aluguel, em centavos. *(obrigatório)* |
| **pre_authorization_amount** | integer | Valor da pré-autorização, em centavos. *(obrigatório)* |
| **coverage_deductible_amount** | integer | Valor dedutível da cobertura, em centavos. *(obrigatório)* |

## Enviar uma Reserva

Exemplo de Request:

```json
{
  "id": "bca6268e-918a-4658-9161-a10b00a631ab",
  ...
}
```

Exemplo de Retorno:

```json
{
  "reservation_key": "bca6268e-918a-4658-9161-a10b00a631ab",
  "fraud_status": "automatically_approved",
  "pre_authorization_amount": 10000
}
```

Para realizar a avaliação de uma reserva, basta enviar um objeto do tipo Reservation ao seguinte endpoint:

`POST https://api.caas.qitech.app/car_rental/reservation`

Além do status do retorno, também é retornado, caso haja, o valor da pré autorização desejada. Caso nenhuma majoração de pré autorização seja identificada, o valor retornado é nulo e não deve ser utilizado.

## Definir o código de uma Reserva

A QI Tech possibilita a definição do código da reserva após a análise inicial. Isto é útil em alguns fluxos operacionais. Nestes casos, basta realizar um PUT no endpoint a seguir, com o código da reserva definido no corpo:

`PUT https://api.caas.qitech.app/car_rental/reservation/{reservation_id}`

:::note
Caso o código da reserva tenha sido definido anteriormente, na requisição de POST ou utilizando um PUT, não é possível redefinir o código da reserva. Neste caso, a API retornará 409 - Conflito.
:::

```json
{
  "reservation_code": "123456789"
}
```

## Recuperar uma Reserva

A fim de recuperar uma Reserva específica, basta realizar uma requisição GET. O resultado retornado é o json mais atualizado da Reserva em questão. Caso este identificador não esteja relacionado a nenhum objeto, o HTTP Status 404 é retornado.

`GET https://api.caas.qitech.app/car_rental/reservation/{reservation_id}`

```shell
curl "https://api.caas.qitech.app/car_rental/reservation/{reservation_id}"
  -H "Authorization: TESTETESTETESTE"
```

---

# Reservation-v2

URL: /documentation/caas/car_rental/reservation_v2

Esta seção diz respeito às informações necessárias para o fluxo de análise de fraude primariamente na reserva.

Ao realizar a reserva de um veículo, o locatário dá início ao seu processo de anti-fraude. Os dados enviados deverão ser os dados finais da reserva, que não serão alterados. Isto é importante para garantir dois pontos:

- Consistência dos dados na base de dados do Antifraude
- Avaliação realista do risco

O processo de análise consiste em enviar uma Reservation no endpoint adequado e esperar a resposta. Existem oito resultados possíveis, devolvido na flag **fraud_status**:

| Resultado | Descrição |
| :---------: | --------- |
| Aprovado Automaticamente | Recomenda-se que este aluguel seja aprovado |
| Negado Automaticamente | Recomenda-se que este aluguel seja reprovado |
| Derivado para análise manual | Nossas regras ou modelos não estão confiantes da decisão e decidiram enviar este aluguel para a análise manual. |
| Aprovado Manualmente | Após análise manual, o analista escolheu aprovar o aluguel |
| Reprovado Manualmente | Após análise manual, o analista escolheu reprovar o aluguel |
| Desafiado Manualmente | Após análise manual, o analista retorna para a loja que a CNH e/ou Selfie estão incorretas e/ou com baixa qualidade |
| Pendente | As consultas estão demorando mais do que o esperado, este aluguel entrou em uma fila de análise automática e será respondido por meio de Webhook |
| Não analisado | A consulta foi enviada com a flag de análise falsa, o que significa que nossos sistemas não deverão retornar parecer |

### Dinâmica dos Status

Ao recuperar um objeto do tipo Reservation os status estão disponíveis. Além dos status, um histórico de modificações também são retornados para que possa ser consultado no futuro. Estas modificações são entituladas events e possuem, além do novo status, as datas de modificação.

### Dinâmica dos Status - **fraud_status**

O status **fraud_status** indica o status da decisão do motor de fraude e possui uma máquina de estados bastante simples:

- `created`
- `automatically_approved`
- `automatically_reproved`
- `in_manual_analysis`
- `manually_approved`
- `manually_reproved`
- `pending`
- `not_analyzed`

## Definição do Objeto

```json
{
  "id": "bca6268e-918a-4658-9161-a10b00a631ab",
  "reservation_code": "211034324",
  "reservation_date": "2024-03-19T10:30:00-03:00",
  "rental_agreement_date": "2024-03-25T10:30:00-03:00",
  "car_rental_estimated_final_date":  "2024-03-30T10:28:00-03:00",
  "channel": "reservation_central",
  "sales_channel" : "PARCERIA TELEFONICA",
  "rental_store": "SAOP",
  "rental_store_group": "GSP",
  "rental_store_type": "LOJA DE RUA",
  "devolution_store": "SAOP",
  "risky_antecedence": true,
  "car": {
    "model_group": "SV",
    "rental_daily_price" : 48496
  },
  "client": {
    "type": "natural_person",
    "segment": "ota",
    "document_number": "123.456.789-00",
    "name": "John Sample",
    "gender": "female",
    "birthdate": "2001-01-15",
    "mother_name": "Mary Sample",
    "email": "john.sample@sample.com.br",
    "allowed_information_on_email": true,
    "face_picture": "c77d1925-0e72-4634-8393-395dbbce498d",
    "additional_pictures": [
      "718b8caa-8ef5-446c-b101-2dbf6c7e401f",
      "9c67f365-1427-4889-b963-d3729d437ff3",
      "8006f82c-3a80-4371-914e-e88c91507711",
      "42c6909e-51aa-4b6d-972f-f4684a047993",
      "b7a88947-96bd-4557-81e9-a69a3c84f428"
    ],
    "total_rents": 6,
    "fidelity_points": 1200,
    "documents": {
      "rg": {
        "document_number": "00000000",
        "issuer": "SSP"
      },
      "cnh": {
        "document_number": "000000000",
        "security_code": "00000",
        "first_issuance": "2015-07-20",
        "expiration_date": "2030-07-26",
        "state": "SP"
      }
    },
    "residential_address": {
      "street": "Av Brigadeiro Faria Lima",
      "number": "2391",
      "neighborhood": "Jardins",
      "city": "SÃO PAULO",
      "uf": "SP",
      "complement": "",
      "postal_code": "00000-000"
    },
    "commercial_address": {
      "street": "Av Brigadeiro Faria Lima",
      "number": "2391",
      "neighborhood": "Jardins",
      "city": "SÃO PAULO",
      "uf": "SP",
      "complement": "",
      "postal_code": "00000-000"
    },
    "phones": [
      {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "00000-0000",
        "type": "mobile"
      },
      {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "00000-0000",
        "type": "residential"
      }
    ]
  },
  "coverages": [
    {
      "description": "S/ PROTEÇÃO AMERICAN PLATINUM",
      "price": 0
    },
    {
      "description": "PROTEÇÃO OCUPANTES E TERCEIROS",
      "price": 1668
    }
  ],
  "billing": {
    "name": "Agência AAA",
    "document_number": "00.000.000/0001-00",
    "voucher_type": "ABCD75",
    "voucher_description": "Pagamento pela agência"
  },
  "fare_name": "MENSAL - 2000KM - PRÓ-RATA",
  "rental_price": 43300,
  "extra_hours": 0,
  "extra_hours_price": 0,
  "discount": 0,
  "prepayment_discount": 100,
  "extra_kms": 0,
  "extra_kms_price": 0,
  "third_party_coverage_price": 1490,
  "coverage_price": 0,
  "additional_driver_price": 1000,
  "driver_service_price": 1000,
  "additional_expenses": 1000,
  "devolution_fee": 0,
  "administration_fee": 5374,
  "discount_partial_coverage": 50,
  "final_price": 50165,
  "pre_authorization_amount": 0,
  "coverage_deductible_amount": 0
}
```

Todas as trocas de informação de uma Reservation utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

| nome | tipo | descrição |
| :----: | :----: | --------- |
| **id** | string | Identificador da requisição de análise no sistema do cliente. **É essencial que este número seja único para cada análise.** *(obrigatório)* |
| reservation_code | string | Identificador da Reserva no sistema do cliente. - Este campo é opcional e pode ser definido utilizando o método PUT. |
| **reservation_date** | DateTime | Data e Hora com fuso-horário do momento em que ocorreu a reserva para este aluguel. *(obrigatório)* |
| **car_rental_estimated_final_date** | DateTime | Data e Hora com fuso-horário de quando o carro deve ser resolvido. *(obrigatório)* |
| **rental_store** | *store* | Loja onde o carro será retirado. *(obrigatório)* |
| rental_store_group | *store* | Filial da loja onde o carro será retirado |
| rental_store_type | *store* | Tipo da loja onde o carro será retirado |
| **devolution_store** | *store* | Loja onde o carro será devolvido, pode ou não ser a mesma loja de retirada. *(obrigatório)* |
| reservation_channel | string | Canal pelo qual foi feito a reserva para este aluguel. |
| **sales_channel** | string | Canal de vendas pelo qual a reserva foi realizada (ex.: PARCERIA MASTERCARD). *(obrigatório)* |
| **car** | *car* | Objeto que carrega as informações do veículo sendo reservado. *(obrigatório)* |
| **client** | *client* | Objeto que carrega as informações do cliente que fará a retirada do veículo. *(obrigatório)* |
| **coverages** | List of *coverage* | Lista de objetos coverage que descrevem as coberturas de seguro contratadas pelo cliente. *(obrigatório)* |
| **billing** | *billing* | Objeto que descreve os detalhes da pessoa ou empresa responsável pelo pagamento do aluguel. *(obrigatório)* |
| **rental_price** | integer | Preço do aluguel, em centavos. *(obrigatório)* |
| **extra_hours** | integer | Quantidade de horas extras contratadas. *(obrigatório)* |
| **extra_hours_price** | integer | Preço das horas extras contratadas, em centavos. *(obrigatório)* |
| **discount** | inteiro | Desconto concedido por quaisquer motivos, em centavos. *(obrigatório)* |
| **prepayment_discount** | inteiro | Desconto por pagamento antecipado. *(obrigatório)* |
| **extra_kms** | integer | Quantidade de kilômetros extras contratados. *(obrigatório)* |
| **extra_kms_price** | integer | Preço de kilômetros extras contratados, em centavos. *(obrigatório)* |
| **third_party_coverage_price** | integer | Preço do seguro de terceiros, em centavos. *(obrigatório)* |
| coverage_price | integer | Preço do seguro contratado, em centavos. |
| **additional_driver_price** | integer | Preço total do(s) motoristas adicionais contratados, em centavos. *(obrigatório)* |
| **driver_service_price** | integer | Preço total do serviço de motorista contratado, em centavos. *(obrigatório)* |
| **additional_expenses** | integer | Despesas adicionais, em centavos. *(obrigatório)* |
| **devolution_fee** | integer | Preço da taxa de devolução, em centavos. *(obrigatório)* |
| **administration_fee** | integer | Preço da taxa de administração, em centavos. *(obrigatório)* |
| **discount_partial_coverage** | integer | Desconto de proteção parcial, em centavos. *(obrigatório)* |
| **final_price** | integer | Preço final do aluguel, em centavos. *(obrigatório)* |
| **pre_authorization_amount** | integer | Valor da pré-autorização, em centavos. *(obrigatório)* |
| **coverage_deductible_amount** | integer | Valor dedutível da cobertura, em centavos. *(obrigatório)* |

## Enviar uma Reserva

Exemplo de Request:

```json
{
  "id": "bca6268e-918a-4658-9161-a10b00a631ab",
  "reservation_code": "211034324",
  ...
}
```

Exemplo de Retorno:

```json
{
  "reservation_key": "bca6268e-918a-4658-9161-a10b00a631ab",
  "fraud_status": "automatically_approved",
  "pre_authorization_amount": 10000
}
```

Para realizar a avaliação de uma reserva, basta enviar um objeto do tipo Reservation ao seguinte endpoint:

`POST https://api.caas.qitech.app/car_rental/reservation`

Além do status do retorno, também é retornado, caso haja, o valor da pré autorização desejada. Caso nenhuma majoração de pré autorização seja identificada, o valor retornado é nulo e não deve ser utilizado.

## Definir o código de uma Reserva

A QI Tech possibilita a definição do código da reserva após a análise inicial. Isto é útil em alguns fluxos operacionais. Nestes casos, basta realizar um PUT no endpoint a seguir, com o código da reserva definido no corpo:

`PUT https://api.caas.qitech.app/car_rental/reservation/{reservation_id}`

:::note
Caso o código da reserva tenha sido definido anteriormente, na requisição de POST ou utilizando um PUT, não é possível redefinir o código da reserva. Neste caso, a API retornará 409 - Conflito.
:::

```json
{
  "reservation_code": "123456789"
}
```

## Recuperar uma Reserva

A fim de recuperar uma Reserva específica, basta realizar uma requisição GET. O resultado retornado é o json mais atualizado da Reserva em questão. Caso este identificador não esteja relacionado a nenhum objeto, o HTTP Status 404 é retornado.

`GET https://api.caas.qitech.app/car_rental/reservation/{reservation_id}`

```shell
curl "https://api.caas.qitech.app/car_rental/reservation/{reservation_id}"
  -H "Authorization: TESTETESTETESTE"
```

---

# Padrões

URL: /documentation/caas/car_rental/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões que são seguidos em toda a API.

## Valores Monetários

Exemplos:

```
10000
12345
98741
1223
1
0
```

As APIs assumem que todos os valores monetários enviados são em Reais Brasileiros. Os valores devem ser enviados como inteiro em centavos.

## Data e Hora com Fuso Horário

Alguns exemplos:

```
2019-10-15T22:35:12-03:00
2018-05-01T13:32:11+00:00
2019-05-01T00:00:00+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será válido. Por exemplo, se um aluguel estiver marcado para começar às 09:30 no aeroporto de Brasília, o horário enviado deverá ser representado por 09:30-03:00, se o aluguel estiver marcado para começar às 09:30 em Manaus, deverá ser representado por 09:30-04:00.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss±hh:mm`

## Data e Hora sem Fuso Horário

Alguns exemplos:

```
2019-10-15T22:35:12Z
2018-05-01T13:32:11Z
2019-05-01T00:00:00Z
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão ser enviados sem ele, sempre em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ssZ`

## Data

Alguns exemplos:

```
2019-10-15
2019-01-01
2017-03-20
```

No caso de campos que recebem somente data, uma data de nascimento, por exemplo, somente a data, sem nenhum horário deve ser enviada com o seguinte formato:

`YYYY-MM-dd`

## Documentos

Uma vez que os números de documento são bastante variados e muitos deles possuem caracteres que não se enquadram como numéricos, definem-se todos os números de documento como string. Outro bom motivo para defini-los como string é evitar que os zeros à esquerda desapareçam. Documentos previstos nesta página possuem uma máscara bem definida e estarão sujeitos a validação. O restante dos documentos, como RG, dada sua falta de padronização, não serão validados.

## CPF

Exemplos de CPFs válidos contra a máscara definida:

```
123.456.789-12
321.987.543-23
111.283.333-00
```

Exemplos de CPFs inválidos contra a máscara definida:

```
8.577.477-8
08.104.627/0001-23
123.456.789-1
23.456.789-01
```

O CPF é sempre definido como uma string e será validado contra a máscara:

`###.###.###-##`

## CNPJ

Exemplos de CNPJs válidos contra a máscara definida:

```
08.104.627/0001-02
01.079.210/0114-67
32.402.502/0001-35
```

Exemplos de CNPJs inválidos contra a máscara definida:

```
8.577.477-8
123.456.789-12
321.987.543-23
32.402.502/0001-3
032.402.502/0001-3
```

O CNPJ é sempre definido como uma string e será validado contra a máscara:

`##.###.###/####-##`

---

# Webhook

URL: /documentation/caas/car_rental/webhook

Webhook

Atualizações no status de fraude (Para RentalAgreements que sejam derivados para análise manual ou que sejam respondidos como Pendente), são notificados por meio de Webhook. Para tanto, é necessário, por meio da equipe do [suporte](mailto:suporte.caas@qitech.com.br), configurar um endereço do endpoint por onde vamos notificar as atualizações e também um *secret_token* que será utilizado para assinar a requisição.

O cliente pode, apesar de não recomendável, também utilizar a técnica de [polling](https://en.wikipedia.org/wiki/Polling_(computer_science)). Neste caso, basta não configurar o endpoint de webhook e utilizar os endpoints de recuperação de RentalAgreement para proceder com o polling.

## Assinatura do Webhook

## Requisição

Exemplo de requisição:

```json
{
  "rental_agreement_id": "123456",
  "fraud_status": "automatically_approved",
  "upgrade_status": "automatically_approved",
  "event_date": "2019-10-01T10:37:25-03:00"
}
```

A requisição possui o formato acima e notifica a mudança no status de fraude.

## Retentativas

A notificação é considerada realizada quando recebe como resposta um HTTP Status 200. Caso as notificações falhem, serão feitas retentativas, com os seguintes intervalos, até que um 200 seja retornado ou as tentativas terminem:

- 10 segundos
- 30 segundos
- 60 segundos
- 120 segundos
- 120 segundos
- 3600 segundos
- 7200 segundos
- 36000 segundos

---

# Alertas de Portadores

URL: /documentation/caas/card_issuance/alerts

Alertas de Portadores

Os alertas gerados pela ferramenta antifraude são notificados por meio de Webhook. Para tanto, é necessário, por meio da equipe do [suporte](mailto:suporte.caas@qitech.com.br), configurar um endereço do endpoint por onde vamos notificar as notificações e também um *secret_token* que será utilizado para assinar a requisição.

Nesta notificação enviaremos informações dos alertas gerados, bem como de qual portador se trata, para que o cliente possa tomar alguma ação, por exemplo, enviar um *push notification* para o portador.

## Requisição

Request Body

```json
    {
        "alert_key": "123456",
        "cardholder_id": "ef47bc3f-61ac-4b85-ad67-0cfa3a422201",
        "company_name": "Cliente 1",
        "irregularity_type" : "fraud",
        "risk_level": "critical"
    }
```

A requisição possui o formato acima e notifica a abertura de um novo alerta para um Portador - descrito pelo *cardholder_id*

## Assinatura do Webhook

Para garantir que a requisição recebida no seu endpoint partiu dos nossos servidores, enviamos uma assinatura HMAC no header `Signature`. Você recalcula essa assinatura do seu lado e compara com a recebida — se forem iguais, a requisição é confiável.

### Como a assinatura é calculada

```text
Signature = HMAC-SHA1(signature_key, endpoint + method + payload)  →  hexadecimal
```

Os três componentes são concatenados **nesta ordem, sem separador**:

| Componente | O que é |
| --- | --- |
| `endpoint` | A URL completa do seu webhook, exatamente como foi configurada com o suporte (incluindo `https://` e eventual query string). |
| `method` | O verbo HTTP em **letras maiúsculas** — sempre `POST` nas notificações de alerta. |
| `payload` | O corpo da requisição **exatamente como recebido**, byte a byte. |
| `signature_key` | O `secret_token` que você combinou com o suporte. É a chave do HMAC, não parte da mensagem. |

:::danger Use o corpo bruto, nunca o JSON reserializado
A assinatura é calculada sobre os bytes exatos do corpo. Se você desserializar o JSON e serializar de novo antes de validar, a ordem das chaves e o espaçamento mudam, e a assinatura **nunca** vai bater.

Leia o corpo como string/bytes brutos primeiro, valide a assinatura, e só depois faça o parse. Nos exemplos abaixo isso aparece como `request.data`, `file_get_contents('php://input')`, `req.rawBody` etc.
:::

:::caution Acentuação no payload
Nós serializamos o corpo com `ensure_ascii=False`, ou seja, caracteres acentuados vão como UTF-8 literal (`"João"`), e não escapados (`"João"`). Trate o corpo como UTF-8 ao calcular o HMAC — é o comportamento padrão em todas as linguagens abaixo, mas é a causa mais comum de assinatura divergente quando o `company_name` tem acento.
:::

### Exemplos de validação

**Python**

```python
import hashlib
import hmac

SIGNATURE_KEY = "YOUR_SECRET_TOKEN"
WEBHOOK_URL = "https://seu-dominio.com/webhooks/qitech/alertas"

def calculate_signature(endpoint: str, method: str, payload: str) -> str:
    hmac_obj = hmac.new(
        SIGNATURE_KEY.encode("utf-8"),
        (endpoint + method + payload).encode("utf-8"),
        hashlib.sha1,
    )
    return hmac_obj.hexdigest()

def is_valid(received_signature: str, raw_body: str) -> bool:
    expected = calculate_signature(WEBHOOK_URL, "POST", raw_body)
    # compare_digest evita ataques de temporização
    return hmac.compare_digest(expected, received_signature)

# Exemplo com Flask
from flask import Flask, request

app = Flask(__name__)

@app.route("/webhooks/qitech/alertas", methods=["POST"])
def receive_alert():
    raw_body = request.get_data(as_text=True)  # corpo bruto, sem parse
    received = request.headers.get("Signature", "")

    if not is_valid(received, raw_body):
        return "", 401

    alert = request.get_json()  # parse só depois de validar
    print(alert["cardholder_id"], alert["risk_level"])
    return "", 200
```

**PHP**

```php
<?php

const SIGNATURE_KEY = 'YOUR_SECRET_TOKEN';
const WEBHOOK_URL   = 'https://seu-dominio.com/webhooks/qitech/alertas';

function calculateSignature(string $endpoint, string $method, string $payload): string
{
    return hash_hmac('sha1', $endpoint . $method . $payload, SIGNATURE_KEY);
}

function isValid(string $receivedSignature, string $rawBody): bool
{
    $expected = calculateSignature(WEBHOOK_URL, 'POST', $rawBody);
    // hash_equals evita ataques de temporização
    return hash_equals($expected, $receivedSignature);
}

// Recebendo a notificação
$rawBody  = file_get_contents('php://input');           // corpo bruto, sem parse
$received = $_SERVER['HTTP_SIGNATURE'] ?? '';

if (!isValid($received, $rawBody)) {
    http_response_code(401);
    exit;
}

$alert = json_decode($rawBody, true);                   // parse só depois de validar
error_log($alert['cardholder_id'] . ' - ' . $alert['risk_level']);

http_response_code(200);
```

**Node.js**

```javascript
const crypto = require("crypto");
const express = require("express");

const SIGNATURE_KEY = "YOUR_SECRET_TOKEN";
const WEBHOOK_URL = "https://seu-dominio.com/webhooks/qitech/alertas";

function calculateSignature(endpoint, method, payload) {
  return crypto
    .createHmac("sha1", SIGNATURE_KEY)
    .update(endpoint + method + payload, "utf8")
    .digest("hex");
}

function isValid(receivedSignature, rawBody) {
  const expected = calculateSignature(WEBHOOK_URL, "POST", rawBody);
  const a = Buffer.from(expected, "utf8");
  const b = Buffer.from(receivedSignature, "utf8");
  // timingSafeEqual exige buffers de mesmo tamanho
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

const app = express();

// express.raw preserva o corpo bruto — NÃO use express.json() nesta rota
app.post(
  "/webhooks/qitech/alertas",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const rawBody = req.body.toString("utf8");
    const received = req.get("Signature") || "";

    if (!isValid(received, rawBody)) {
      return res.sendStatus(401);
    }

    const alert = JSON.parse(rawBody); // parse só depois de validar
    console.log(alert.cardholder_id, alert.risk_level);
    res.sendStatus(200);
  },
);

app.listen(3000);
```

**Java**

```java
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class WebhookSignature {

    private static final String SIGNATURE_KEY = "YOUR_SECRET_TOKEN";
    private static final String WEBHOOK_URL =
            "https://seu-dominio.com/webhooks/qitech/alertas";

    public static String calculateSignature(String endpoint, String method, String payload)
            throws Exception {
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(new SecretKeySpec(
                SIGNATURE_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));

        byte[] digest = mac.doFinal(
                (endpoint + method + payload).getBytes(StandardCharsets.UTF_8));

        StringBuilder hex = new StringBuilder(digest.length * 2);
        for (byte b : digest) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }

    public static boolean isValid(String receivedSignature, String rawBody)
            throws Exception {
        String expected = calculateSignature(WEBHOOK_URL, "POST", rawBody);
        // MessageDigest.isEqual evita ataques de temporização
        return MessageDigest.isEqual(
                expected.getBytes(StandardCharsets.UTF_8),
                receivedSignature.getBytes(StandardCharsets.UTF_8));
    }
}
```

Em Spring Boot, receba o corpo como `String` para preservar os bytes originais:

```java
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
public class AlertController {

    @PostMapping("/webhooks/qitech/alertas")
    public ResponseEntity<Void> receiveAlert(
            @RequestBody String rawBody,                       // corpo bruto, sem parse
            @RequestHeader(value = "Signature", required = false) String signature)
            throws Exception {

        if (signature == null || !WebhookSignature.isValid(signature, rawBody)) {
            return ResponseEntity.status(401).build();
        }

        // parse só depois de validar (ex.: com Jackson)
        return ResponseEntity.ok().build();
    }
}
```

**C#**

```csharp
using System;
using System.Security.Cryptography;
using System.Text;

public static class WebhookSignature
{
    private const string SignatureKey = "YOUR_SECRET_TOKEN";
    private const string WebhookUrl =
        "https://seu-dominio.com/webhooks/qitech/alertas";

    public static string CalculateSignature(string endpoint, string method, string payload)
    {
        using var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(SignatureKey));
        var digest = hmac.ComputeHash(Encoding.UTF8.GetBytes(endpoint + method + payload));
        return Convert.ToHexString(digest).ToLowerInvariant();
    }

    public static bool IsValid(string receivedSignature, string rawBody)
    {
        var expected = CalculateSignature(WebhookUrl, "POST", rawBody);
        // FixedTimeEquals evita ataques de temporização
        return CryptographicOperations.FixedTimeEquals(
            Encoding.UTF8.GetBytes(expected),
            Encoding.UTF8.GetBytes(receivedSignature));
    }
}
```

Em ASP.NET Core, leia o corpo bruto antes de qualquer desserialização:

```csharp
app.MapPost("/webhooks/qitech/alertas", async (HttpRequest request) =>
{
    using var reader = new StreamReader(request.Body, Encoding.UTF8);
    var rawBody = await reader.ReadToEndAsync();          // corpo bruto, sem parse

    var received = request.Headers["Signature"].ToString();

    if (!WebhookSignature.IsValid(received, rawBody))
    {
        return Results.Unauthorized();
    }

    // parse só depois de validar
    return Results.Ok();
});
```

:::tip Assinatura não bate? Verifique nesta ordem
1. **O corpo foi reserializado?** É a causa mais frequente. Use o corpo bruto.
2. **A URL está idêntica?** Uma barra final a mais ou a menos (`/alertas` vs `/alertas/`) muda a assinatura. Use exatamente a URL configurada com o suporte.
3. **O método está em maiúsculas?** Deve ser `POST`, não `post`.
4. **A ordem da concatenação está certa?** É `endpoint + method + payload`, nessa ordem.
5. **O digest está em hexadecimal minúsculo?** Não é Base64.
:::

## Retentativas

A notificação é considerada realizada quando recebe como resposta um HTTP Status 200. Caso as notificações falhem, serão feitas 5 retentativas, com os seguintes intervalos, até que um 200 seja retornado ou as tentativas terminem:

* 30 segundos
* 60 segundos
* 120 segundos
* 240 segundos
* 360 segundos

---

# Status HTTP

URL: /documentation/caas/card_issuance/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/card_issuance/introduction

Bem vindo à API de Prevenção a Fraudes em emissão de cartões da QI Tech! Você pode utilizar a nossa API para acessar os endpoints, a fim de receber a resposta de uma transação, além de utilizar para atualizar a situação de uma transação.

:::info **Atenção**

Atenção, esta API é direcionada para emissores de cartão, ou seja, empresas que dão o cartão na mão do portador para que ele possa transacionar. Ela tem como objetivo realizar toda a análise de segurança nas transações do seu cliente, evitando fraudes e outros tipos de incidentes (Transações decorrentes de assaltos, por exemplo).
:::

## Como funciona

A integração tem três chamadas. Todas usam a mesma API Key no header `Authorization`.

| Passo | Chamada | O que faz |
| --- | --- | --- |
| 1 | `POST /card_issuance/transaction` | Envia a transação **antes da autorização** e devolve a recomendação em `fraud_status`. |
| 2 | `PUT /card_issuance/transaction/{id}` | Informa o desfecho real (capturada, cancelada, chargeback). Retroalimenta o modelo. |
| 3 | `GET /card_issuance/transaction/{id}` | Consulta o estado atual e o histórico de eventos. |

Além disso, alertas comportamentais sobre o portador são entregues por [Webhook](/documentation/caas/card_issuance/alerts).

O `fraud_status` devolvido no passo 1 assume um destes valores:

| Valor | Ação recomendada |
| --- | --- |
| `automatically_approved` | Gerar o código de autorização. |
| `automatically_declined` | Negar a autorização. |
| `not_analyzed` | A requisição usou `analyze=false`; siga a sua própria decisão. |

:::tip Integre em minutos
A página [Transaction](/documentation/caas/card_issuance/transaction) abre com um **payload mínimo** de 13 campos e traz exemplos prontos em Python, PHP, Node.js, Java, C# e curl.
:::

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/card_issuance/`
* Sandbox - `https://api.sandbox.caas.qitech.app/card_issuance/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

No ambiente de Sandbox, as análises enviadas não são cobradas e são respondidas de acordo com regras pré estabelecidas.

Para a análise de uma transação, a seguinte regra é aplicada sobre o valor da transação:

Mínimo | Máximo | Decisão
------ | ------ | -------
10000 | - | automatically_approved
0 | 9999 | automatically_declined

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

## Autenticação

> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> Substitua a API key 'EXAMPLE-OF-API-KEY' com a sua chave adquirida com o nosso suporte.

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE-OF-API-KEY`

:::info **Atenção**

Você deve substituir EXAMPLE-OF-API-KEY com a API Key recebida do suporte.
:::

---

# Padrões

URL: /documentation/caas/card_issuance/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões que são seguidos em toda a API.

## Valores Monetários
> Exemplos:

```
10000
12345
98741
1223
1
0
```

Os valores devem ser enviados como inteiro em centavos.

## Data e Hora com Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12-03:00
2018-05-01T13:32:11+00:00
2019-05-01T00:00:00+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será valido. Por exemplo, se um aluguel estiver marcado para começar às 09:30 no aeroporto de Brasília, o horário enviado deverá ser representado por 09:30-03:00, se o aluguel estiver marcado para começar às 09:30 em Manaus, deverá ser representado por 09:30-04:00.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss±hh:mm`

## Data e Hora sem Fuso Horario
> Alguns exemplos:

```
2019-10-15T22:35:12Z
2018-05-01T13:32:11Z
2019-05-01T00:00:00Z
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão ser enviados sem ele, sempre em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ssZ`

## Data
> Alguns exemplos

``` 
2019-10-15
2019-01-01
2017-03-20
```

---

# Transaction

URL: /documentation/caas/card_issuance/transaction

Transaction

O recurso `Transaction` é o coração da API de antifraude transacional de cartão. Você envia os dados da transação **antes de autorizá-la** e recebe de volta uma recomendação (`fraud_status`) para decidir se gera ou não o código de autorização.

O fluxo completo de integração tem três passos:

1. **`POST /card_issuance/transaction`** — envia a transação para análise e recebe a recomendação.
2. **`PUT /card_issuance/transaction/{id}`** — informa o desfecho real (capturada, cancelada, chargeback). Esse retorno alimenta o modelo e é o que mantém a qualidade das decisões ao longo do tempo.
3. **`GET /card_issuance/transaction/{id}`** — consulta o estado atual e o histórico de eventos de uma transação.

:::tip Comece pelo payload mínimo
Se você quer subir uma integração rápida, vá direto para [Payload mínimo](#payload-minimo). São 13 campos obrigatórios. Todo o resto é opcional e serve para aumentar a acurácia do modelo.
:::

---

## Payload mínimo

Este é o menor corpo aceito pelo `POST /card_issuance/transaction`. Ele contém **apenas** os campos obrigatórios e é suficiente para receber uma decisão.

```json title="Payload mínimo — 13 campos obrigatórios"
{
  "id": "678",
  "cardholder_id": "b812da2e-e6be-4712-8e57-6f3f2791625b",
  "amount": 13725,
  "currency": "BRL",
  "installments": 1,
  "authorization_date": "2026-08-07T13:25:42-03:00",
  "authorization_type": "authorization",
  "transaction_type": "credit",
  "pan_entry_mode": "chip",
  "pin_sent": true,
  "terminal": {
    "country_code": "BRA"
  },
  "merchant": {
    "acquirer_id": "250",
    "merchant_id": "123456",
    "mcc": "5411"
  },
  "card": {
    "brand": "visa",
    "category": "black",
    "bin": "498406",
    "last4": "1234",
    "issuer_country_code": "BRA"
  }
}
```

Resposta:

```json
{
  "id": "678",
  "fraud_status": "automatically_approved"
}
```

:::info Quanto mais dados, melhor a decisão
Os campos opcionais (localização, capacidades do terminal, limites do cartão, endereço do lojista) não são exigidos pela validação, mas alimentam diretamente os modelos e as regras. Uma integração que envia apenas o mínimo funciona, mas tende a produzir mais falsos positivos.
:::

---

## Enviar uma transação para análise

ENDPOINT /card_issuance/transaction
MÉTODO POST

### Query parameters

analyze
boolean
opcional — padrão true
Quando true , a transação passa pelos motores de fraude e a resposta traz uma recomendação. Quando false , a transação é apenas registrada no histórico do portador (sem custo de análise) e a resposta retorna not_analyzed . Use analyze=false para transações que você já decidiu por outros meios, mas que devem compor o comportamento histórico do portador.

:::caution Ao usar `analyze=false`
Envie também `transaction_status` e `response_code` no corpo, informando o desfeito que você já aplicou. Sem isso, a transação fica registrada como `pending` e o histórico do portador perde informação.
:::

### Exemplos de requisição

**Python**

```python
import requests

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

payload = {
    "id": "678",
    "cardholder_id": "b812da2e-e6be-4712-8e57-6f3f2791625b",
    "amount": 13725,
    "currency": "BRL",
    "installments": 1,
    "authorization_date": "2026-08-07T13:25:42-03:00",
    "authorization_type": "authorization",
    "transaction_type": "credit",
    "pan_entry_mode": "chip",
    "pin_sent": True,
    "terminal": {"country_code": "BRA"},
    "merchant": {"acquirer_id": "250", "merchant_id": "123456", "mcc": "5411"},
    "card": {
        "brand": "visa",
        "category": "black",
        "bin": "498406",
        "last4": "1234",
        "issuer_country_code": "BRA",
    },
}

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

response.raise_for_status()
print(response.json())  # {'id': '678', 'fraud_status': 'automatically_approved'}
```

**PHP**

```php
<?php

$baseUrl = 'https://api.sandbox.caas.qitech.app';
$apiKey  = 'YOUR_API_KEY';

$payload = [
    'id'                 => '678',
    'cardholder_id'      => 'b812da2e-e6be-4712-8e57-6f3f2791625b',
    'amount'             => 13725,
    'currency'           => 'BRL',
    'installments'       => 1,
    'authorization_date' => '2026-08-07T13:25:42-03:00',
    'authorization_type' => 'authorization',
    'transaction_type'   => 'credit',
    'pan_entry_mode'     => 'chip',
    'pin_sent'           => true,
    'terminal'           => ['country_code' => 'BRA'],
    'merchant'           => [
        'acquirer_id' => '250',
        'merchant_id' => '123456',
        'mcc'         => '5411',
    ],
    'card' => [
        'brand'               => 'visa',
        'category'            => 'black',
        'bin'                 => '498406',
        'last4'               => '1234',
        'issuer_country_code' => 'BRA',
    ],
];

$ch = curl_init($baseUrl . '/card_issuance/transaction?analyze=true');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 5,
    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("Antifraude retornou HTTP {$status}: {$body}");
}

$result = json_decode($body, true);
echo $result['fraud_status'];  // automatically_approved
```

**Node.js**

```javascript
const BASE_URL = "https://api.sandbox.caas.qitech.app";
const API_KEY = "YOUR_API_KEY";

const payload = {
  id: "678",
  cardholder_id: "b812da2e-e6be-4712-8e57-6f3f2791625b",
  amount: 13725,
  currency: "BRL",
  installments: 1,
  authorization_date: "2026-08-07T13:25:42-03:00",
  authorization_type: "authorization",
  transaction_type: "credit",
  pan_entry_mode: "chip",
  pin_sent: true,
  terminal: { country_code: "BRA" },
  merchant: { acquirer_id: "250", merchant_id: "123456", mcc: "5411" },
  card: {
    brand: "visa",
    category: "black",
    bin: "498406",
    last4: "1234",
    issuer_country_code: "BRA",
  },
};

async function analyzeTransaction() {
  const response = await fetch(
    `${BASE_URL}/card_issuance/transaction?analyze=true`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: API_KEY,
      },
      body: JSON.stringify(payload),
      signal: AbortSignal.timeout(5000),
    },
  );

  if (!response.ok) {
    throw new Error(`Antifraude retornou HTTP ${response.status}`);
  }

  const result = await response.json();
  console.log(result.fraud_status); // automatically_approved
  return result;
}

analyzeTransaction();
```

**Java**

```java
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 AnalyzeTransaction {

    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": "678",
              "cardholder_id": "b812da2e-e6be-4712-8e57-6f3f2791625b",
              "amount": 13725,
              "currency": "BRL",
              "installments": 1,
              "authorization_date": "2026-08-07T13:25:42-03:00",
              "authorization_type": "authorization",
              "transaction_type": "credit",
              "pan_entry_mode": "chip",
              "pin_sent": true,
              "terminal": { "country_code": "BRA" },
              "merchant": {
                "acquirer_id": "250",
                "merchant_id": "123456",
                "mcc": "5411"
              },
              "card": {
                "brand": "visa",
                "category": "black",
                "bin": "498406",
                "last4": "1234",
                "issuer_country_code": "BRA"
              }
            }
            """;

        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(5))
                .build();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(BASE_URL + "/card_issuance/transaction?analyze=true"))
                .header("Content-Type", "application/json")
                .header("Authorization", API_KEY)
                .timeout(Duration.ofSeconds(5))
                .POST(HttpRequest.BodyPublishers.ofString(payload))
                .build();

        HttpResponse<String> response =
                client.send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 200) {
            throw new IllegalStateException(
                    "Antifraude retornou HTTP " + response.statusCode() + ": " + response.body());
        }

        System.out.println(response.body());
        // {"id":"678","fraud_status":"automatically_approved"}
    }
}
```

**C#**

```csharp
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class AnalyzeTransaction
{
    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 = "678",
            cardholder_id = "b812da2e-e6be-4712-8e57-6f3f2791625b",
            amount = 13725,
            currency = "BRL",
            installments = 1,
            authorization_date = "2026-08-07T13:25:42-03:00",
            authorization_type = "authorization",
            transaction_type = "credit",
            pan_entry_mode = "chip",
            pin_sent = true,
            terminal = new { country_code = "BRA" },
            merchant = new { acquirer_id = "250", merchant_id = "123456", mcc = "5411" },
            card = new
            {
                brand = "visa",
                category = "black",
                bin = "498406",
                last4 = "1234",
                issuer_country_code = "BRA"
            }
        };

        using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
        client.DefaultRequestHeaders.Add("Authorization", ApiKey);

        var content = new StringContent(
            JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");

        var response = await client.PostAsync(
            $"{BaseUrl}/card_issuance/transaction?analyze=true", content);

        var body = await response.Content.ReadAsStringAsync();

        if (!response.IsSuccessStatusCode)
        {
            throw new InvalidOperationException(
                $"Antifraude retornou HTTP {(int)response.StatusCode}: {body}");
        }

        Console.WriteLine(body);
        // {"id":"678","fraud_status":"automatically_approved"}
    }
}
```

**curl**

```bash
curl -X POST \
  'https://api.sandbox.caas.qitech.app/card_issuance/transaction?analyze=true' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: YOUR_API_KEY' \
  -d '{
    "id": "678",
    "cardholder_id": "b812da2e-e6be-4712-8e57-6f3f2791625b",
    "amount": 13725,
    "currency": "BRL",
    "installments": 1,
    "authorization_date": "2026-08-07T13:25:42-03:00",
    "authorization_type": "authorization",
    "transaction_type": "credit",
    "pan_entry_mode": "chip",
    "pin_sent": true,
    "terminal": { "country_code": "BRA" },
    "merchant": { "acquirer_id": "250", "merchant_id": "123456", "mcc": "5411" },
    "card": {
      "brand": "visa",
      "category": "black",
      "bin": "498406",
      "last4": "1234",
      "issuer_country_code": "BRA"
    }
  }'
```

### Resposta

id
string
O mesmo id que você enviou na requisição.

fraud_status
enum
A recomendação do motor antifraude. Veja fraud_status .

```json
{
  "id": "678",
  "fraud_status": "automatically_approved"
}
```

:::caution Comportamento em caso de indisponibilidade interna
Se os motores de decisão ficarem indisponíveis, a API retorna `automatically_approved` em vez de erro. Isso é intencional: o antifraude nunca deve derrubar a autorização do cartão. Ainda assim, trate timeouts do seu lado com uma política de fallback definida.
:::

---

## Objeto Transaction

### Campos raiz

id
string
obrigatório
Identificador da transação no seu sistema. Máximo de 36 caracteres. Deve ser único por processo de autorização — um id repetido retorna HTTP 409.

cardholder_id
string
obrigatório
Identificador do portador no seu sistema. Máximo de 200 caracteres. É a chave que agrupa o histórico comportamental — use sempre o mesmo valor para o mesmo portador.

amount
integer
obrigatório
Valor da transação em centavos, na moeda de currency . Entre 0 e 1000000000 .

currency
enum
obrigatório
Moeda da transação em ISO 4217 ( BRL , USD , EUR …), correspondente ao ApplicationCurrencyCode da ISO 8583.

installments
integer
obrigatório
Número de parcelas. Entre 0 e 24 . Use 1 para transações à vista.

authorization_date
datetime
obrigatório
Data e hora de início da transação, com fuso horário , no formato YYYY-MM-DDThh:mm:ss±hh:mm . Veja a nota sobre o formato .

authorization_type
enum
obrigatório
Tipo de autorização. Veja authorization_type .

transaction_type
enum
obrigatório
Função utilizada: credit , debit ou prepaid .

pan_entry_mode
enum
obrigatório
Modo de entrada do PAN, derivado do DE 22 (Sub Field 1) da ISO 8583. Veja pan_entry_mode .

pin_sent
boolean
obrigatório
Indica se uma senha foi inserida no terminal.

terminal
object
obrigatório
Dados do terminal. Veja Objeto terminal .

merchant
object
obrigatório
Dados do estabelecimento. Veja Objeto merchant .

card
object
obrigatório
Dados do cartão. Veja Objeto card .

accountholder_id
string
opcional
Identificador do titular da conta, quando diferente do portador do cartão (cartões adicionais, cartões corporativos). Máximo de 200 caracteres.

group_id
string
opcional
Grupo ou categoria a que o portador pertence no seu sistema. Máximo de 200 caracteres. Útil para segmentar regras por carteira.

brl_converted_amount
integer
opcional
Valor da transação convertido para reais, em centavos. Você não precisa enviar este campo — quando currency é diferente de BRL , a QI Tech calcula a conversão internamente; quando é BRL , o valor é igual a amount . Se enviado, é sobrescrito.

location
object
opcional
Localização geográfica da transação. Veja Objeto location .

authentication_type
string
opcional
Método de autenticação aplicado à transação (por exemplo, o resultado de um 3-D Secure). Máximo de 200 caracteres.

risk_assessment
enum
opcional
Classificação de risco atribuída pela bandeira ou pelo adquirente na mensageria. Veja risk_assessment .

cvv_presence
boolean
opcional
Indica se o CVV foi informado na transação. Sinal relevante em transações de e-commerce.

transaction_status
enum
opcional
Situação da transação. Envie no POST apenas quando usar analyze=false e a decisão de autorização já tiver sido tomada. Veja transaction_status .

response_code
string
opcional
Response code da transação conforme o campo Response Code da ISO 8583. Exatamente 1 ou 2 caracteres. Assim como transaction_status , faz sentido no POST apenas com analyze=false .

```json title="Payload completo"
{
  "id": "678",
  "cardholder_id": "b812da2e-e6be-4712-8e57-6f3f2791625b",
  "accountholder_id": "0f5e2d1c-4a3b-4c6d-9e8f-1a2b3c4d5e6f",
  "group_id": "8507884b-c30f-4b45-951c-f0bf366926fc",
  "amount": 13725,
  "currency": "BRL",
  "installments": 6,
  "authorization_date": "2026-08-07T13:25:42-03:00",
  "authorization_type": "authorization",
  "transaction_type": "credit",
  "pan_entry_mode": "chip",
  "pin_sent": true,
  "source_account": "credit_facility",
  "authentication_type": "3ds_authenticated",
  "risk_assessment": "low_risk",
  "cvv_presence": true,
  "location": {
    "latitude": -23.5613,
    "longitude": -46.6565,
    "altitude": 760
  },
  "terminal": {
    "id": "12345678",
    "country_code": "BRA",
    "terminal_type": "5",
    "pin_entry_capability": true,
    "magnetic_stripe_capability": true,
    "contactless_capability": true,
    "chip_capability": true
  },
  "merchant": {
    "acquirer_id": "250",
    "merchant_id": "123456",
    "payment_facilitator": "PAGSEGURO",
    "sub_merchant": "LOJA 042",
    "name": "SUPERMERCADO EXEMPLO",
    "street": "RUA CMDTE X, 127",
    "city": "SAO PAULO",
    "region": "SP",
    "postal_code": "04570-140",
    "mcc": "5411"
  },
  "card": {
    "brand": "visa",
    "category": "black",
    "holder_id": "b812da2e-e6be-4712-8e57-6f3f2791625b",
    "issuing_date": "2025-10-08T07:13:12-03:00",
    "unblock_date": "2025-10-12T07:13:12-03:00",
    "expiration_date": "2030-12-31",
    "bin": "498406",
    "last4": "1234",
    "total_credit_limit": 2500000,
    "used_credit_limit": 732625,
    "issuer_country_code": "BRA"
  }
}
```

:::warning Campos não previstos são rejeitados
O schema usa `additionalProperties: false` em todos os objetos. Qualquer campo fora dos listados aqui faz a requisição retornar **HTTP 400**, mesmo que o restante do payload esteja correto.
:::

#### Formato de `authorization_date`

O validador aceita apenas offsets de fuso terminados em `:00` ou `:30` (por exemplo `-03:00`, `+05:30`, `-04:00`). Sufixo `Z` e offsets como `-03:15` são rejeitados com HTTP 400. Fração de segundo é opcional e aceita de 1 a 6 dígitos:

```text
2026-08-07T13:25:42-03:00          ✅
2026-08-07T13:25:42.123456-03:00   ✅
2026-08-07T13:25:42Z               ❌  use -00:00
2026-08-07T13:25:42-03:15          ❌  offset não permitido
```

A mesma regra vale para `card.issuing_date` e `card.unblock_date`.

---

### Objeto `terminal`

country_code
enum
obrigatório
País do terminal em ISO 3166-1 alpha-3 ( BRA , USA , PRT …). Campo Terminal Country Code da ISO 8583.

id
string
opcional
Identificador do terminal enviado pela adquirente. Máximo de 8 caracteres. String vazia é tratada como ausente.

terminal_type
string
opcional
Tipo de terminal conforme TerminalType da ISO 8583. Máximo de 10 caracteres. Veja terminal_type .

pin_entry_capability
boolean
opcional
O terminal permite inserir senha? Campo TerminalPINEntryCapability da ISO 8583.

magnetic_stripe_capability
boolean
opcional
O terminal lê tarja magnética? Campo TerminalPANEntryCapability (DE 123).

contactless_capability
boolean
opcional
O terminal aceita transações por aproximação? Campo TerminalPANEntryCapability (DE 123).

chip_capability
boolean
opcional
O terminal lê chip EMV? Campo TerminalPANEntryCapability (DE 123).

```json
{
  "terminal": {
    "id": "12345678",
    "country_code": "BRA",
    "terminal_type": "5",
    "pin_entry_capability": true,
    "magnetic_stripe_capability": true,
    "contactless_capability": true,
    "chip_capability": true
  }
}
```

:::info Mudança em relação à versão anterior desta documentação
Apenas `country_code` é obrigatório dentro de `terminal`. As versões antigas desta página listavam `terminal_type`, `pin_entry_capability` e `chip_capability` como obrigatórios — eles são opcionais.
:::

---

### Objeto `merchant`

acquirer_id
string
obrigatório
Identificador da adquirente. Máximo de 11 caracteres. Campo Acquirer Identifier (DE 32) da ISO 8583.

merchant_id
string
obrigatório
Identificador do lojista na adquirente. Máximo de 15 caracteres. Campo Merchant Identifier da ISO 8583.

mcc
enum
obrigatório
Merchant Category Code de 4 dígitos, conforme ISO 18245. Aceita apenas MCCs válidos da lista oficial — um código fora da lista retorna HTTP 400.

name
string
opcional
Nome do lojista conforme a mensageria. Máximo de 200 caracteres.

payment_facilitator
string
opcional
Facilitador de pagamento (subadquirente) envolvido na transação. Máximo de 200 caracteres.

sub_merchant
string
opcional
Sublojista, quando a transação passa por um facilitador. Máximo de 200 caracteres.

street
string
opcional
Logradouro do lojista. Campo Card Acceptor Street Address .

city
string
opcional
Cidade do lojista. Campo Card Acceptor City .

region
string
opcional
Região/estado do lojista. Campo Card Acceptor Region Code .

postal_code
string
opcional
CEP do lojista. Campo Card Acceptor Postal Code .

```json
{
  "merchant": {
    "acquirer_id": "250",
    "merchant_id": "123456",
    "payment_facilitator": "PAGSEGURO",
    "sub_merchant": "LOJA 042",
    "name": "SUPERMERCADO EXEMPLO",
    "street": "RUA CMDTE X, 127",
    "city": "SAO PAULO",
    "region": "SP",
    "postal_code": "04570-140",
    "mcc": "5411"
  }
}
```

---

### Objeto `card`

brand
enum
obrigatório
Bandeira do cartão. Veja brand .

category
enum
obrigatório
Categoria do cartão. Veja category .

bin
string
obrigatório
BIN do cartão. Exatamente 6 dígitos numéricos.

last4
string
obrigatório
Quatro últimos dígitos do cartão. Exatamente 4 dígitos numéricos.

issuer_country_code
enum
obrigatório
País do emissor em ISO 3166-1 alpha-3.

holder_id
string
opcional
Identificador do portador vinculado a este plástico específico, útil quando um mesmo cardholder_id possui múltiplos cartões. Máximo de 200 caracteres.

issuing_date
datetime
opcional
Data e hora de emissão do cartão, com fuso horário. Cartões recém-emitidos são um sinal de risco relevante.

unblock_date
datetime
opcional
Data e hora em que o portador desbloqueou o cartão, com fuso horário.

expiration_date
date
opcional
Data de vencimento do cartão no formato YYYY-MM-DD (use o último dia do mês).

total_credit_limit
integer
opcional
Limite total de crédito do portador, em centavos. Para cartões pré-pagos, o saldo disponível.

used_credit_limit
integer
opcional
Limite já utilizado, em centavos, antes da transação em análise.

```json
{
  "card": {
    "brand": "visa",
    "category": "black",
    "holder_id": "b812da2e-e6be-4712-8e57-6f3f2791625b",
    "issuing_date": "2025-10-08T07:13:12-03:00",
    "unblock_date": "2025-10-12T07:13:12-03:00",
    "expiration_date": "2030-12-31",
    "bin": "498406",
    "last4": "1234",
    "total_credit_limit": 2500000,
    "used_credit_limit": 732625,
    "issuer_country_code": "BRA"
  }
}
```

:::info Mudança em relação à versão anterior desta documentação
`issuing_date` e `expiration_date` **não** são obrigatórios, ao contrário do que a versão anterior desta página indicava. Os obrigatórios em `card` são apenas `brand`, `category`, `bin`, `last4` e `issuer_country_code`.
:::

---

### Objeto `location`

latitude
number
obrigatório se location for enviado
Latitude da transação, entre -90 e 90 .

longitude
number
obrigatório se location for enviado
Longitude da transação, entre -180 e 180 .

altitude
number
opcional
Altitude em metros, entre 0 e 100000 .

```json
{
  "location": {
    "latitude": -23.5613,
    "longitude": -46.6565,
    "altitude": 760
  }
}
```

:::caution Objeto opcional com campos obrigatórios
`location` como um todo é opcional. Mas se você enviar o objeto, `latitude` e `longitude` passam a ser obrigatórios dentro dele. Se não tiver a coordenada, omita o objeto inteiro em vez de enviá-lo vazio.
:::

---

## Enumeradores

### `authorization_type`

| Valor | Significado |
| --- | --- |
| `authorization` | Autorização de compra — MTI x1xx (DMS) e x2xx (SMS). |
| `pre_authorization` | Pré-autorização para reserva de limite (hotel, locação de veículos, postos de combustível) — MTI x1xx (DMS) e *Transaction Type* `60` nos dois primeiros dígitos do Processing Code. |
| `reversal` | Cancelamento de autorização, para liberar limite antes do Clearing/BASE II — MTI x4xx. |

### `transaction_type`

| Valor | Significado |
| --- | --- |
| `credit` | Transação na função crédito. |
| `debit` | Transação na função débito. |
| `prepaid` | Transação na função pré-pago. |

### `pan_entry_mode`

Derivado do DE 22 (Sub Field 1) da ISO 8583.

| Valor | ISO 8583 | Significado |
| --- | --- | --- |
| `unknown` | 00 | Modo de entrada desconhecido. |
| `typed` | 01 | PAN digitado manualmente. |
| `bar_code` | 03 | PAN lido por código de barras. |
| `ocr` | 04 | PAN lido por OCR. |
| `chip` | 05 | PAN lido pelo chip EMV. |
| `track_1` | 06 | PAN lido pela Track 1 da tarja. |
| `contactless` | 07 | PAN lido por aproximação (Contactless EMV). |
| `fallback_typed` | 79 | Falha na leitura de chip/tarja e o PAN foi digitado. Também usado quando a adquirente não está homologada para chip ou tarja. |
| `fallback_magnetic_stripe` | 80 | Falha na leitura do chip e a transação prosseguiu pela tarja magnética. |
| `ecommerce` | 81 | Transação de e-commerce / cartão não presente. |
| `magnetic_stripe` | 90 | Transação por tarja magnética. |
| `manual` | — | Entrada manual dos dados do cartão fora do fluxo de terminal. |
| `stored_credentials` | — | Transação com credenciais armazenadas (assinaturas, cobranças recorrentes, carteiras com cartão tokenizado). |

:::tip `stored_credentials` e recorrências
Transações recorrentes marcadas como `ecommerce` tendem a receber mais recusas do que o esperado, porque o modelo as trata como cartão não presente sem contexto. Use `stored_credentials` sempre que a cobrança usar uma credencial previamente autorizada pelo portador.
:::

### `source_account`

Derivado do Processing Code da ISO 8583. Campo opcional.

| Valor | ISO 8583 | Significado |
| --- | --- | --- |
| `default` | 00 | Padrão ou não especificado. |
| `saving_account` | 10 | Conta poupança. |
| `checking_account` | 20 | Conta corrente. |
| `credit_facility` | 30 | Fatura do cartão. |
| `universal_account` | 40 | Conta universal. |
| `investment_account` | 50 | Conta de investimento. |
| `electronic_purse` | 60 | Saldo armazenado no chip do cartão. |

### `brand`

| Valor | Bandeira |
| --- | --- |
| `visa` | Visa |
| `mastercard` | Mastercard |
| `elo` | Elo |
| `diners_club` | Diners Club |
| `american_express` | American Express |

### `category`

| Valor | Categoria |
| --- | --- |
| `classic` | Classic |
| `gold` | Gold |
| `platinum` | Platinum |
| `black` | Black / Infinite |
| `travel` | Travel |
| `corporate` | Corporate / Business |
| `prepaid` | Pré-pago |
| `postpaid` | Pós-pago |

### `terminal_type`

Conforme *TerminalType* da ISO 8583. Enviado como string.

| Valor | Significado |
| --- | --- |
| `0` | Desconhecido |
| `1` | Nenhum terminal utilizado |
| `2` | Leitor de tarja magnética |
| `3` | Código de barras |
| `4` | OCR |
| `5` | Leitor de tarja magnética e de chip EMV |
| `6` | Apenas entrada por teclado |
| `7` | Leitor de tarja magnética e entrada por teclado |
| `8` | Leitor de tarja, entrada por teclado e chip EMV |
| `9` | Leitor de chip EMV |

### `risk_assessment`

Classificação de risco recebida na mensageria (por exemplo, TRA da PSD2 ou avaliação da bandeira).

| Valor | Significado |
| --- | --- |
| `not_evaluated` | Nenhuma avaliação de risco foi realizada. |
| `low_risk` | A transação foi classificada como de baixo risco. |
| `non_low_risk` | A transação **não** foi classificada como de baixo risco. |

### `transaction_status`

Situação da transação no ciclo de vida da autorização.

| Valor | Significado |
| --- | --- |
| `pending` | Autorização pendente. Estado inicial atribuído automaticamente. |
| `authorized` | Autorizada, aguardando captura. |
| `not_authorized` | Não autorizada pelo emissor. |
| `captured` | Capturada. |
| `cleared` | Recebida no Clearing / BASE II. |
| `cancelled` | Cancelada integralmente. |
| `partially_cancelled` | Cancelada parcialmente. |
| `chargeback` | Recebeu chargeback integral. |
| `partial_chargeback` | Recebeu chargeback parcial. |

:::note `pending` não é enviável
`pending` é atribuído pela própria API quando a transação é criada sem decisão. Ele não é aceito no corpo do `POST` nem do `PUT`.
:::

### `fraud_status`

A recomendação devolvida pelo motor antifraude.

| Valor | Significado | Ação recomendada |
| --- | --- | --- |
| `automatically_approved` | O padrão da transação é compatível com o comportamento do portador. | Gerar o código de autorização. |
| `automatically_declined` | A transação apresenta risco relevante de fraude. | Negar a autorização. |
| `not_analyzed` | A requisição foi enviada com `analyze=false`. Nenhuma análise foi realizada. | Seguir a sua própria decisão. |

---

## Atualizar o status de uma transação

ENDPOINT /card_issuance/transaction/ TRANSACTION_ID
MÉTODO PUT

Informar o desfecho real da transação é o que retroalimenta as regras e o modelo. Sem esse passo, a qualidade das recomendações degrada ao longo do tempo.

O `TRANSACTION_ID` no path é o mesmo `id` que você enviou no `POST`.

### Corpo da requisição

O corpo aceita **duas formas**, escolhidas conforme o status:

**Atualização total**

Para qualquer status que afete a transação por inteiro.

transaction_status
enum
obrigatório
Novo status. Aceita authorized , not_authorized , captured , cleared , cancelled , partially_cancelled , chargeback ou partial_chargeback .

response_code
string
opcional
Response code da ISO 8583. 1 ou 2 caracteres.

```json
{
  "transaction_status": "captured",
  "response_code": "00"
}
```

**Atualização parcial**

Obrigatória para `partially_cancelled` e `partial_chargeback`.

transaction_status
enum
obrigatório
Aceita apenas partially_cancelled ou partial_chargeback .

partial_amount
integer
obrigatório
Valor cancelado/estornado em centavos, de 1 a 1000000000 . Não pode exceder o valor ainda disponível da transação.

response_code
string
opcional
Response code da ISO 8583. 1 ou 2 caracteres.

```json
{
  "transaction_status": "partially_cancelled",
  "partial_amount": 3000,
  "response_code": "00"
}
```

:::danger Status finais não podem ser alterados
Uma transação que já está em `cancelled`, `partially_cancelled`, `chargeback` ou `partial_chargeback` é considerada finalizada. Um novo `PUT` sobre ela retorna **HTTP 400** com o título `Transaction has a final status`.

Consequência prática: você **não** consegue registrar dois cancelamentos parciais em sequência pela API. Planeje enviar o valor consolidado.
:::

Em caso de sucesso, a resposta é **HTTP 200** com corpo vazio (`{}`).

### Exemplos de requisição

**Python**

```python
import requests

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

response = requests.put(
    f"{BASE_URL}/card_issuance/transaction/{TRANSACTION_ID}",
    json={"transaction_status": "captured", "response_code": "00"},
    headers={"Authorization": API_KEY},
    timeout=5,
)

response.raise_for_status()  # 200 com corpo vazio
```

**PHP**

```php
<?php

$baseUrl       = 'https://api.sandbox.caas.qitech.app';
$apiKey        = 'YOUR_API_KEY';
$transactionId = '678';

$payload = [
    'transaction_status' => 'captured',
    'response_code'      => '00',
];

$ch = curl_init("{$baseUrl}/card_issuance/transaction/{$transactionId}");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 5,
    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("Falha ao atualizar status: HTTP {$status} — {$body}");
}
```

**Node.js**

```javascript
const BASE_URL = "https://api.sandbox.caas.qitech.app";
const API_KEY = "YOUR_API_KEY";
const TRANSACTION_ID = "678";

async function updateStatus() {
  const response = await fetch(
    `${BASE_URL}/card_issuance/transaction/${TRANSACTION_ID}`,
    {
      method: "PUT",
      headers: {
        "Content-Type": "application/json",
        Authorization: API_KEY,
      },
      body: JSON.stringify({
        transaction_status: "captured",
        response_code: "00",
      }),
      signal: AbortSignal.timeout(5000),
    },
  );

  if (!response.ok) {
    throw new Error(`Falha ao atualizar status: HTTP ${response.status}`);
  }
}

updateStatus();
```

**Java**

```java
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 UpdateTransactionStatus {

    private static final String BASE_URL = "https://api.sandbox.caas.qitech.app";
    private static final String API_KEY = "YOUR_API_KEY";
    private static final String TRANSACTION_ID = "678";

    public static void main(String[] args) throws Exception {
        String payload = """
            { "transaction_status": "captured", "response_code": "00" }
            """;

        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(BASE_URL + "/card_issuance/transaction/" + TRANSACTION_ID))
                .header("Content-Type", "application/json")
                .header("Authorization", API_KEY)
                .timeout(Duration.ofSeconds(5))
                .PUT(HttpRequest.BodyPublishers.ofString(payload))
                .build();

        HttpResponse<String> response =
                client.send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 200) {
            throw new IllegalStateException(
                    "Falha ao atualizar status: HTTP " + response.statusCode()
                            + " — " + response.body());
        }
    }
}
```

**C#**

```csharp
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class UpdateTransactionStatus
{
    private const string BaseUrl = "https://api.sandbox.caas.qitech.app";
    private const string ApiKey = "YOUR_API_KEY";
    private const string TransactionId = "678";

    public static async Task Main()
    {
        var payload = new { transaction_status = "captured", response_code = "00" };

        using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
        client.DefaultRequestHeaders.Add("Authorization", ApiKey);

        var content = new StringContent(
            JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");

        var response = await client.PutAsync(
            $"{BaseUrl}/card_issuance/transaction/{TransactionId}", content);

        if (!response.IsSuccessStatusCode)
        {
            var body = await response.Content.ReadAsStringAsync();
            throw new InvalidOperationException(
                $"Falha ao atualizar status: HTTP {(int)response.StatusCode} — {body}");
        }
    }
}
```

**curl**

```bash
curl -X PUT \
  'https://api.sandbox.caas.qitech.app/card_issuance/transaction/678' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: YOUR_API_KEY' \
  -d '{ "transaction_status": "captured", "response_code": "00" }'
```

---

## Recuperar uma transação

ENDPOINT /card_issuance/transaction/ TRANSACTION_ID
MÉTODO GET

Retorna o estado atual da transação junto com o histórico completo de eventos. Se o `id` não existir para a sua API Key, a resposta é **HTTP 404**.

**Python**

```python
import requests

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

response = requests.get(
    f"{BASE_URL}/card_issuance/transaction/{TRANSACTION_ID}",
    headers={"Authorization": API_KEY},
    timeout=5,
)

response.raise_for_status()
transaction = response.json()
print(transaction["fraud_status"], transaction["transaction_status"])
```

**PHP**

```php
<?php

$baseUrl       = 'https://api.sandbox.caas.qitech.app';
$apiKey        = 'YOUR_API_KEY';
$transactionId = '678';

$ch = curl_init("{$baseUrl}/card_issuance/transaction/{$transactionId}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 5,
    CURLOPT_HTTPHEADER     => ['Authorization: ' . $apiKey],
]);

$body   = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status === 404) {
    throw new RuntimeException("Transação {$transactionId} não encontrada.");
}

$transaction = json_decode($body, true);
echo $transaction['fraud_status'];
```

**Node.js**

```javascript
const BASE_URL = "https://api.sandbox.caas.qitech.app";
const API_KEY = "YOUR_API_KEY";
const TRANSACTION_ID = "678";

async function getTransaction() {
  const response = await fetch(
    `${BASE_URL}/card_issuance/transaction/${TRANSACTION_ID}`,
    { headers: { Authorization: API_KEY } },
  );

  if (response.status === 404) {
    throw new Error(`Transação ${TRANSACTION_ID} não encontrada.`);
  }

  const transaction = await response.json();
  console.log(transaction.fraud_status, transaction.transaction_status);
  return transaction;
}

getTransaction();
```

**Java**

```java
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 GetTransaction {

    private static final String BASE_URL = "https://api.sandbox.caas.qitech.app";
    private static final String API_KEY = "YOUR_API_KEY";
    private static final String TRANSACTION_ID = "678";

    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(BASE_URL + "/card_issuance/transaction/" + TRANSACTION_ID))
                .header("Authorization", API_KEY)
                .timeout(Duration.ofSeconds(5))
                .GET()
                .build();

        HttpResponse<String> response =
                client.send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() == 404) {
            throw new IllegalStateException("Transação " + TRANSACTION_ID + " não encontrada.");
        }

        System.out.println(response.body());
    }
}
```

**C#**

```csharp
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

public class GetTransaction
{
    private const string BaseUrl = "https://api.sandbox.caas.qitech.app";
    private const string ApiKey = "YOUR_API_KEY";
    private const string TransactionId = "678";

    public static async Task Main()
    {
        using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
        client.DefaultRequestHeaders.Add("Authorization", ApiKey);

        var response = await client.GetAsync(
            $"{BaseUrl}/card_issuance/transaction/{TransactionId}");

        if (response.StatusCode == HttpStatusCode.NotFound)
        {
            throw new InvalidOperationException($"Transação {TransactionId} não encontrada.");
        }

        Console.WriteLine(await response.Content.ReadAsStringAsync());
    }
}
```

**curl**

```bash
curl 'https://api.sandbox.caas.qitech.app/card_issuance/transaction/678' \
  -H 'Authorization: YOUR_API_KEY'
```

### Resposta

A resposta devolve todos os campos que você enviou no `POST`, acrescidos dos campos abaixo.

fraud_status
enum
Recomendação atual do antifraude.

transaction_status
enum
Situação atual da transação.

brl_converted_amount
integer
Valor convertido para reais, em centavos, calculado pela QI Tech.

transaction_events
array
Histórico de mudanças de status da transação, em ordem cronológica.

**Campos de `transaction_events[]`:**

new_status
enum
Status atribuído neste evento.

event_date
datetime
Data e hora do evento, em UTC.

partial_amount
integer
Presente apenas em eventos parciais.

response_code
string
Presente quando informado na atualização.

fraud_events
array
Histórico de decisões do antifraude.

**Campos de `fraud_events[]`:**

new_status
enum
Decisão atribuída neste evento.

event_date
datetime
Data e hora da decisão, em UTC.

decision_metadata
object
Motivo da decisão. Traz reason e reason_description explicando por que a transação foi aprovada ou recusada.

```json
{
  "id": "678",
  "cardholder_id": "b812da2e-e6be-4712-8e57-6f3f2791625b",
  "amount": 13725,
  "brl_converted_amount": 13725,
  "currency": "BRL",
  "installments": 1,
  "authorization_date": "2026-08-07T13:25:42-03:00",
  "authorization_type": "authorization",
  "transaction_type": "credit",
  "pan_entry_mode": "chip",
  "pin_sent": true,
  "terminal": { "country_code": "BRA" },
  "merchant": {
    "acquirer_id": "250",
    "merchant_id": "123456",
    "mcc": "5411"
  },
  "card": {
    "brand": "visa",
    "category": "black",
    "bin": "498406",
    "last4": "1234",
    "issuer_country_code": "BRA"
  },
  "fraud_status": "automatically_approved",
  "transaction_status": "captured",
  "fraud_events": [
    {
      "new_status": "automatically_approved",
      "event_date": "2026-08-07T16:25:43Z",
      "decision_metadata": {
        "reason": "automatically_approved",
        "reason_description": "O padrão transacional foi normal."
      }
    }
  ],
  "transaction_events": [
    {
      "new_status": "authorized",
      "event_date": "2026-08-07T16:25:43Z"
    },
    {
      "new_status": "captured",
      "event_date": "2026-08-07T18:02:10Z",
      "response_code": "00"
    }
  ]
}
```

---

## Erros

Todos os erros retornam um corpo JSON com o mesmo formato:

```json
{
  "title": "Duplicated external_id",
  "description": "id: 678 already exists for company 3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
```

| Status | Situação | Como resolver |
| --- | --- | --- |
| 400 | Payload inválido: campo obrigatório ausente, enum fora da lista, formato de data incorreto ou campo não previsto pelo schema. | Confira a `description`, que aponta o campo com problema. |
| 400 | `Transaction has a final status` no `PUT`. | A transação já está em status final e não aceita novas atualizações. |
| 400 | `partial_amount` maior que o valor disponível. | Envie um valor menor ou igual ao saldo ainda não cancelado. |
| 401 | Header `Authorization` ausente ou API Key desativada. | Verifique o header e o status da sua chave. |
| 403 | API Key inválida ou endpoint de uso interno. | Confirme a chave com o [suporte](mailto:suporte.caas@qitech.com.br). |
| 404 | Transação não encontrada para a sua API Key. | Verifique o `id` usado no path. |
| 406 | Corpo da requisição não é um JSON válido. | Verifique o `Content-Type` e a serialização. |
| 409 | `id` já processado anteriormente. | Gere um `id` único por processo de autorização. |
| 500 | Erro interno. | Nossos especialistas são notificados automaticamente. |
| 503 | Indisponibilidade de infraestrutura. | Aplique retry com backoff. |

A lista completa está em [Status HTTP](/documentation/caas/card_issuance/http_status).

---

## Testando no Sandbox

No Sandbox as análises não são cobradas e a decisão é determinística, baseada apenas no valor da transação:

| `amount` | `fraud_status` retornado |
| --- | --- |
| `>= 10000` (R$ 100,00 ou mais) | `automatically_approved` |
| `<= 9999` (até R$ 99,99) | `automatically_declined` |

Base URL de Sandbox: `https://api.sandbox.caas.qitech.app`

:::danger Aviso importante
Não utilize dados reais de pessoas físicas ou jurídicas no ambiente de Sandbox da QI Tech.
:::

---

## Checklist de integração

- [ ] `POST /card_issuance/transaction` com o payload mínimo retornando `200` no Sandbox.
- [ ] `id` único garantido por processo de autorização (teste o `409` reenviando o mesmo `id`).
- [ ] `cardholder_id` estável para o mesmo portador entre transações.
- [ ] `authorization_date` no formato com offset `:00` ou `:30`.
- [ ] Valores monetários em centavos, como inteiros.
- [ ] Tratamento de timeout com política de fallback definida (aprovar ou negar por conta própria).
- [ ] `PUT` enviado em todos os desfechos: captura, cancelamento, chargeback.
- [ ] Webhook de [Alertas de Portadores](/documentation/caas/card_issuance/alerts) configurado com o suporte.

---

# Status HTTP

URL: /documentation/caas/card_order/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/card_order/introduction

Bem vindo à API de Prevenção a Fraudes em transações de cartões da QI Tech! Você pode utilizar a nossa API para acessar os endpoints, a fim de receber a resposta de uma transação, e enviar transações para a QI Tech gerar alertas de usuários fraudadores ou sellers fraudadores, além de utilizar para atualizar a situação de uma transação.

:::info **Atenção**

Atenção, esta API é direcionada para merchants que recebam transações de cartão não presente, que estão sujeitas a chargeback de fraude, ou seja, empresas que realizam suas vendas por meio de aplicativos ou de website e recebem o pagamento por meio de cartão de crédito ou débito.
:::

Abaixo, você pode observar a implementação da API utilizando cUrl. Com isso você possui exemplos para poder adaptar adequadamente à linguagem de programação da sua preferência.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/card_order/`
* Sandbox - `https://api.sandbox.caas.qitech.app/card_order/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

No ambiente de Sandbox, as análises enviadas não são cobradas e são respondidas de acordo com regras pré estabelecidas.

Para a análise de uma transação, a seguinte regra é aplicada sobre o valor da transação:

Mínimo | Máximo | Decisão
------ | ------ | -------
0 | 1000 | Aprovado Automaticamente
1001 | 2000 | Derivado para análise manual - Posteriormente aprovado
2001 | 3000 | Derivado para análise manual - Posteriormente reprovado
3001 | 4000 | Reprovado Automaticamente
4001 | 5000 | Não analisado
5001 | - | Pendente

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

## Autenticação

> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE_API_KEY"
```

> Substitua a API key 'EXAMPLE_API_KEY' com a sua chave adquirida com o nosso suporte.

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE_API_KEY`

:::info **Atenção**

Você deve substituir EXAMPLE_API_KEY com a API Key recebida do suporte.
:::

---

# Objetos

URL: /documentation/caas/card_order/objects

## Objeto *address*

Request Body

```json
{
  "street": "Rua do Exemplo, 111",
  "neighborhood": "Bairro do Teste",
  "city": "Aparecida de Goiânia",
  "uf": "GO",
  "complement": "",
  "postal_code": "00000-000",
  "country": "BRA"
}
```

O objeto *address* é utilizado para representar endereços em toda a API, endereços no território brasileiro são representados da seguinte maneira:

nome | tipo | descrição
---- | :----: | ---------
street | string | *(obrigatório)* Rua do endereço, incluindo o logradouro, evitando, se possível, abreviações.
number | string | Número do imóvel, incluindo letras caso possua.
neighborhood | string | *(obrigatório)* Bairro, sem abreviações. **e.g.: Santa Felicidade**
city | string | *(obrigatório)* Nome completo da cidade, sem abreviações
uf | string | *(obrigatório)* A unidade federativa, com duas letras maiúsculas. **e.g.: SP**
complement | string | Quaisquer complementos para localizar o imóvel. **e.g.: Apartamento 101, Conjunto 12**
postal_code | string | *(obrigatório)* O código postal da localidade, contendo o hífen.
country | string | *(obrigatório)* Código ISO 3166-1 alfa-3 do país do endereço.

No caso dos endereços cujo país não seja Brasil ("BRA"), o postal_code e a unidade federativa poderão ser preenchidos livremente.

## Objeto *payment*

Request Body

```json
{
  "total_amount": 10000,
  "shipping_amount": 500,
  "currency": "BRL",
  "is_recurrence": false,
  "transactions": [ . . . ]
}
```

Um pagamento é representado pelo objeto *payment*, que possui os seguintes campos:

nome | tipo | descrição
---- | :----: | ---------
total_amount | inteiro | *(obrigatório)* Valor monetário total pago
shipping_amount | inteiro | Valor do frete cobrado para entrega
currency | Enumerador | *(obrigatório)* Moeda de pagamento de acordo com a ISO 4217
is_recurrence | boolean | *(obrigatório)* Caso este seja um pagamento de recorrência, indicar true nesta flag
transactions | Array de Transaction | *(obrigatório)* Lista de transações que foram realizadas para o pagamento do pedido (Pagamento com múltiplos cartões)

## Objeto *transaction* - Cartão de Crédito

Request Body

```json
{
  "id": "124234",
  "amount": 10000,
  "bin": "123456",
  "last_4": "1234",
  "cardholder_name": "JOHN SAMPLE",
  "card_fingerprint": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
  "expiration_date": "2020-11",
  "installments": 6,
  "processor": "stone",
  "payment_type": "credit"
}
```

Uma transação é representada pelo objeto *transaction*, que possui os seguintes campos:

nome | tipo | descrição
---- | :----: | ---------
id | string | *(obrigatório)* Um identificador no sistema do cliente da transação, deve ser único por pedido
amount | integer | *(obrigatório)* Valor monetário que representa o valor pago
bin | string | *(obrigatório)* BIN do cartão utilizado no pagamento
last4 | string | *(obrigatório)* Quatro últimos dígitos do cartão utilizado no pagamento
cardholder_name | string | *(obrigatório)* Nome do portador, como está escrito no cartão
card_fingerprint | string | *(obrigatório)* Identificador do cartão no sistema do cliente ("Token")
expiration_date | string | Data de vencimento definida pelo cartão (YYYY-DD)
installments | integer | *(obrigatório)* Número de parcelas do pagamento
processor | enumerador | *(obrigatório)* Adquirente ou subadquirente responsável pelo processamento da transação
payment_type | enumerador | *(obrigatório)* Tipo de meio de pagamento
status | enumerador | Opcional - Último status da transação no momento do envio para a QI Tech - Útil para envio de transações não autorizadas

Enumeradores disponíveis para processor:
* cielo
* rede
* stone
* getnet
* adyen
* global_payments
* pagseguro

## Objeto *transaction* - PIX

Request Body

```json
{
  "id": "124234",
  "amount": 10000,
  "payment_type": "pix"
}
```

Uma transação é representada pelo objeto *transaction*, que possui os seguintes campos:

nome | tipo | descrição
---- | :----: | ---------
id | string | *(obrigatório)* Um identificador no sistema do cliente da transação, deve ser único por pedido
amount | integer | *(obrigatório)* Valor monetário que representa o valor pago
payment_type | enumerador | *(obrigatório)* Tipo de meio de pagamento

## Objeto *dict_key*

Request Body

```json
  {
    "key_type": "cpf",
    "key_value": "09991222669"
  }
```

O objeto **dict_key**  é utilizado para representar os dados da chave de vínculo no DICT do cliente, seja ele o recebedor ou o pagador da transação. Os campos desse objeto são:

nome | tipo | descrição
:----: | :----: | ---------
key_type        | string | Enumerador que contém o tipo da chave de vinculo no DICT.
key_value       | string | Contém a chave de vínculo cadastrada no DICT.

Os enumeradores para o campo *key_type* são os mesmos definidos na API do DICT: `cpf`,`cnpj`,`email`,`phone` e `evp`.

## Objeto *account*

Request Body

```json
{
    "participant": "17315359",
    "branch": "0000",
    "account_number": "10442",
    "account_digit": "6",
    "account_type": "CACC"
}
```

Objeto que representa os dados de uma conta.

nome | tipo | descrição
:----:  | :----:  | ---------
participant                 | string | ISPB da instituição detentora da conta
branch                      | string | Agência da Conta
account_number              | string | Número da Conta sem o dígito
account_digit               | string | Dígito da conta
account_type                | enum | Tipo da conta de origem, possíveis valores: "CACC", "SLRY" e "SVGS"

## Objeto *phone*

Request Body

```json
{
  "international_dial_code": "1",
  "area_code": "11",
  "number": "999999999",
  "type": "mobile",
  "validated": false
}
```

Um objeto phone representa um número telefônico, dentro ou fora do Brasil e sua classificação. Para isso, os campos são:

nome | tipo | descrição
---- | :----: | ---------
international_dial_code | string | *(obrigatório)* Código de discagem internacional, sem zero ou +, somente números
area_code | string | *(obrigatório)* Código de área, sem zero, somente números
number | string | *(obrigatório)* Número do telefone, sem o hífen
type | enum | *(obrigatório)* Tipo de número: celular, residencial, comercial, etc.
validated | booleano | Caso o número de telefone tenha sido validado (SMS ou Ligação), enviar true neste campo

Existem os seguintes enumeradores para tipo de telefone: `residential`, `commercial`, `mobile`

## Objeto *seller*

Request Body

```json
{
  "id": "COD",
  "name": "Restaurante do Aeroporto de Congonhas",
  "type": "legal_person",
  "document_number": "00.000.000/0001-00",
  "email": "seller@gmail.com",
  "registration_date": "2019-12-20T15:23:12-03:00",
  "url": "https://www.qitech.com.br",
  "phone": {
      "international_dial_code": "1",
      "area_code": "11",
      "number": "999999999",
      "type": "mobile"
  },
  "address": {
    "street": "Rua do Exemplo",
    "neighborhood": "Bairro do Teste",
    "city": "Aparecida de Goiânia",
    "number": "1000",
    "uf": "GO",
    "complement": "Térreo",
    "postal_code": "00000-000"
  }
}
```

O objeto *seller* representa uma loja ou vendedor que realiza a venda ou entrega do pedido. Os dados a serem enviados podem ser vistos abaixo:

nome | tipo | descrição
---- | :----: | ---------
id | string | *(obrigatório)* O código identificador da loja (Ou vendedor em MarketPlace) no cliente
name | string | *(obrigatório)* O nome da loja (Ou vendedor em MarketPlace)
type | enum | Enumerador que representa se o seller é uma pessoa física ou pessoa jurídica
document_number | string | *(obrigatório)* O CNPJ ou CPF do seller
url | string | Endereço para a página do seller na plataforma
email | string | O e-mail do seller
registration_date | date | *(obrigatório)* A data de cadastro do seller
phone | *phone* | O telefone do seller
address | *address* | *(obrigatório)* O endereço da loja, caso seja uma loja física

Enumeradores de type:

* `natural_person`
* `legal_person`

## Objeto *customer*

Request Body

```json
{
  "id": "5ce7fab5-8165-44a5-9b89-bb2d6d61e4f4",
  "name": "Mary Sample",
  "gender": "female",
  "document_number": "000.000.000-00",
  "registration_date": "2019-12-20T15:23:12Z",
  "email": "test@sample.com",
  "birthdate": "1990-01-02",
  "address": { . . . },
  "phone": { . . . }
}
```

O objeto customer representa os dados de quem realizou a compra do pedido, com o próprio cartão de crédito. Ele é composto por:

nome | tipo | descrição
---- | :----: | ---------
id | string | *(obrigatório)* Um identificador único do comprador ou usuário
name | string | *(obrigatório)* Nome completo
gender | enum | O gênero do customer, de acordo com a lista de enumeradores.
document_number | string | *(obrigatório)* O CPF, formatado adequadamente
registration_date | date | A data quando o usuário se cadastrou no sistema do cliente
email | string | *(obrigatório)* O e-mail do usuário
birthdate | date | A data de nascimento do customer
address | *address* | *(obrigatório)* O endereço residencial do comprador/usuário
phone | *phone* | *(obrigatório)* O telefone colhidos do comprador/usuário

Enumeradores de gênero:

* `male`
* `female`

## Objeto *device*

Request Body

```json
{
  "session_id": "595c46c1-b8c2-449d-8a86-6aeba2e5b0da",
  "platform": "android",
  "browser": "chrome",
  "ip": "243.178.100.37"
}
```

O objeto device descreve dados do dispositivo usado para realizar a compra. Os seguintes dados são passados:

nome | tipo | descrição
---- | :----: | ---------
session_id | string | *(obrigatório)* O identificador da sessão, repassada também no device scan
platform | enumerador | Enumerador do sistema operacional em uso
browser | enumerador | Enumerador do browser em uso (Ou aplicativo)
ip | string | O ip de origem da compra, de acordo com a padronização desta documentação. **Atenção, IPs iniciados em 10.* , 172.16.* e 192.168.* em geral são internos e portanto não são aplicáveis para prevenção a fraudes**

Enumeradores de plataforma:
* `android`
* `ios`
* `windows`
* `linux`

Enumeradores de browser:
* `firefox`
* `chrome`
* `safari`
* `app`

---

# Order

URL: /documentation/caas/card_order/order

Antes de realizar a entrega/envio de um produto ou a liberação de créditos para o seu cliente ou seller, você deve enviar os dados do pedido para a nossa API para que possamos lhe responder a nossa recomendação com relação a fraude. É muito importante que os dados enviados sejam os dados finais, que não serão alterados. Isto é muito importante para garantir dois pontos:

* Consistência dos dados na base de dados do Antifraude
* Avaliação realista do risco

O processo de análise consiste em enviar uma Order no endpoint adequado e esperar a resposta. Existem quatro resultados possíveis, devolvido na flag **analysis_status**:

Resultado | Descrição
:---------: | ---------
Aprovado Automaticamente | Recomenda-se que este pedido seja aprovado
Negado Automaticamente | Recomenda-se que este pedido seja reprovado
Derivado para análise manual | Nossas regras ou modelos não estão confiantes da decisão e decidiram enviar este pedido para a análise manual.
Aprovado Manualmente | Após análise manual, o analista escolheu aprovar o pedido
Reprovado Manualmente | Após análise manual, o analista escolheu reprovar o pedido
Pendente | As consultas estão demorando mais do que o esperado, este pedido entrou em uma fila de análise automática e será respondido por meio de Webhook
Não analisado | A consulta foi enviada com a flag de análise falsa, ou trata-se de uma análise exclusivamente para geração de alertas, o que significa que nossos sistemas não deverão retornar recomendação na resposta da Order

:::info **Atenção**
Caso o seu modelo de negócio demande, o motor da QI Tech pode ser configurado para que nenhum pedido seja derivado para análise manual, e nem para o estado Pendente. Assim, o seu usuário poderá receber imediatamente a confirmação da transação.
:::

### Dinâmica dos Status

Ao recuperar um objeto do tipo Order os status estão disponíveis. Além dos status, um histórico de modificações também são retornados para que possa ser consultado no futuro. Estas modificações são entituladas events e possuem, além do novo status, as datas de modificação.

### Dinâmica dos Status - **payment_status**

O status **payment_status** relacionado a um Pedido indica a situação do pagamento relacionado a este pedido, isto é, se a transação foi efetivamente aprovada, se foi cancelada ou se recebeu um chargeback de fraude. Os seguintes status de pagamento estão disponíveis:

* open
* not_authorized
* authorized
* captured
* cancelled
* chargeback

:::info **Atenção**

É de suma importância que o status de pagamento seja enviado para a QI Tech pois ele é utilizado como base para treinamento dos nossos modelos. No caso de chargeback, é muito importante que o reason_code seja enviado corretamente, como será explicado em seguida.
:::

### Dinâmica dos Status - **analysis_status**

O status **analysis_status** indica o status da decisão do motor de fraude e possui uma máquina de estados bastante simples:

* created
* automatically_approved
* automatically_reproved
* in_manual_analysis
* manually_approved
* manually_reproved
* pending
* not_analyzed

## Definição do Objeto

Request Body

```json
{
	"id": "12345678",
	"is_one_dollar_auth": false,
	"seller": {
		"id": "COD",
		"name": "Restaurante do Aeroporto de Congonhas",
		"type": "legal_person",
		"document_number": "00.000.000/0001-00",
		"email": "seller@gmail.com",
		"registration_date": "2019-12-20T15:23:12-03:00",
		"url": "https://www.qitech.com.br",
		"phone": {
			"international_dial_code": "1",
			"area_code": "11",
			"number": "999999999",
			"type": "mobile",
			"validated": true
		},
		"address": {
			"street": "Rua do Exemplo",
			"neighborhood": "Bairro do Teste",
			"city": "Aparecida de Goiânia",
			"number": "1000",
			"uf": "GO",
			"complement": "Térreo",
			"postal_code": "00000-000",
			"country": "BRA"
		}
	},
	"payment": {
		"total_amount": 10000,
		"shipping_amount": 500,
		"currency": "BRL",
		"is_recurrence": false,
		"transactions": [{
			"id": "124234",
			"amount": 8000,
			"bin": "123456",
			"last_4": "1234",
			"cardholder_name": "JOHN SAMPLE",
			"card_fingerprint": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
			"expiration_date": "2020-11",
			"installments": 6,
			"processor": "stone",
			"payment_type": "credit",
			"status": "not_authorized"
		}]
	},
	"shipping": {
		"name": "Mary Sample",
		"gender": "female",
		"document_number": "000.000.000-00",
		"birthdate": "1990-01-02",
		"email": "test@sample.com",
		"address": {
			"street": "Rua do Exemplo, 123",
			"neighborhood": "Bairro do Teste",
			"city": "Aparecida de Goiânia",
			"number": "1000",
			"uf": "GO",
			"complement": "",
			"postal_code": "00000-000",
			"country": "BRA"
		},
		"phone": {
			"international_dial_code": "1",
			"area_code": "11",
			"number": "999999999",
			"type": "mobile",
			"validated": true
		},
		"scheduled_date": "2020-01-10",
		"shipping_method": "regular"
	},
	"customer": {
		"id": "5ce7fab5-8165-44a5-9b89-bb2d6d61e4f4",
		"name": "Mary Sample",
		"gender": "female",
		"document_number": "000.000.000-00",
		"registration_date": "2019-12-20T15:23:12-03:00",
		"email": "test@sample.com",
		"birthdate": "1990-01-02",
		"address": {
			"street": "Rua do Exemplo, 123",
			"neighborhood": "Bairro do Teste",
			"city": "Aparecida de Goiânia",
			"number": "1000",
			"uf": "GO",
			"complement": "",
			"postal_code": "00000-000",
			"country": "BRA"
		},
		"phone": {
			"international_dial_code": "1",
			"area_code": "11",
			"number": "999999999",
			"type": "mobile",
			"validated": true
		}
	},
	"device": {
		"session_id": "595c46c1-b8c2-449d-8a86-6aeba2e5b0da",
		"platform": "android",
		"browser": "chrome",
		"ip": "243.178.100.37"
	},
	"products": [{
		"product_code": "latte-machiatto-30",
		"name": "Latte Machiatto 30cl",
		"description": "Latte Machiatto 30cl para levar, leite integral",
		"sku": "1234",
		"quantity": 2,
		"unit_cost": 5000
	}],
	"order_date": "2020-01-03T15:35:12.454-03:00"
}
```

Todas as trocas de informação de um pedido utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

nome |                  tipo                  | descrição
:----: |:--------------------------------------:| ---------
id | string | Identificador do pedido no sistema do cliente. **É essencial que este valor seja único para cada pedido** (Obrigatório)
is_one_dollar_auth |                booleano                | Se esta for uma transação somente para validação do cartão, enviar com essa flag true (Obrigatório)
seller |             Objeto Seller              | Os dados da loja onde a venda está sendo realizada. No caso de um market place, são os dados do vendedor. No caso de um aplicativo, são os dados da loja de retirada (Obrigatório)
payment |             Objeto Payment             | Dados do pagamento do pedido (Obrigatório)
customer |            Objeto Customer             | Dados do cliente/usuário (Obrigatório)
shipping |            Objeto Shipping             | Dados da entrega do pedido - Deve ser preenchido em casos de produtos de entrega física 
device |             Objeto Device              | Dados do aparelho/navegador onde o pedido é realizado
products |            Array de Product            | Os produtos sendo comprados (Obrigatório)
order_date |          Data Hora            | Data e hora de realização do pedido (Obrigatório)

## Enviar um Pedido

Request Body

```json
  {
    "id": "12345",
    ...
  }
```

Response Body

```json
  {
    "id": "12345",
    "analysis_status": "automatically_approved"
  }
```

Para realizar a avaliação de um pedido, basta enviar um objeto do tipo Order ao seguinte endpoint:

`POST https://api.caas.qitech.app/card_order/order`

## Atualizar o status de um Pedido

Request Body

```json
{
  "transaction_status": "chargeback"
}
```

Para garantir a retroalimentação das regras e do modelo de inteligência artificial implementado, é necessário informar ao sistema quando as transações são autorizadas, capturadas, canceladas ou recebem chargeback. Para isso, requisições com o método PUT devem ser utilizadas, autenticadas normalmente:

`PUT https://api.caas.qitech.app/card_order/order/12345678/transaction/124234`

Existem os seguintes enumeradores para *transaction_status*: `open`, `not_authorized`, `authorized`, `captured`, `cancelled`, `chargeback`

## Recuperar um Pedido

A fim de recuperar um Pedido específico, basta realizar uma requisição GET. O resultado retornado é o json mais atualizado do Pedido em questão. Caso este identificador não esteja relacionado a nenhum objeto, o HTTP Status 404 é retornado.

`GET https://api.caas.qitech.app/card_order/order/12345678`

```shell
curl "https://api.caas.qitech.app/card_order/order/12345678"
  -H "Authorization: EXAMPLE_API_KEY"
```

> O comando acima retorna o JSON que representa um objeto de CardOrder.

## Buscar CardOrders

Response Body

```json
[
  {
    "id": "12345",
    ...
  },
  {
    "id": "12345",
    ...
  }
]
```

> Retorna um JSON que representa uma lista de objetos CardOrder.

Caso seja necessário buscar um CardOrder, um GET com parâmetros de query poderá ser utilizado. O resultado retornado é um JSON que representa uma lista de CardOrders. Caso nenhum objeto seja encontrado com os parâmetros enviados, o HTTP Status 200 é retornado com uma lista vazia no corpo da resposta.

`GET https://api.caas.qitech.app/card_order/order?initial_date=2019-10-01&final_date=2019-10-05&page_number=2&page_rows=20`

Os seguintes parâmetros podem ser utilizados para buscar objetos de CardOrder:

Parâmetro | Padrão | Descrição
--------- | ----------- | --------------
initial_date | null | Primeira data que deve ser retornada a partir do campo order_date
final_date | null | Última data que deve ser retornada a partir do campo order_date
page_number | 1 | Número da página de resultados desejada
page_rows | 50 | Número de objetos máximo a ser retornados em uma consulta

---

# Padrões

URL: /documentation/caas/card_order/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões que são seguidos em toda a API.

## Valores Monetários
> Exemplos:

```
10000
12345
98741
1223
1
0
```

As APIs assumem que todos os valores monetários enviados são em Reais Brasileiros. Os valores devem ser enviados como inteiro em centavos.

## Data e Hora com Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12-03:00
2018-05-01T13:32:11+00:00
2019-05-01T00:00:00+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será valido. Por exemplo, se um aluguel estiver marcado para começar às 09:30 no aeroporto de Brasília, o horário enviado deverá ser representado por 09:30-03:00, se o aluguel estiver marcado para começar às 09:30 em Manaus, deverá ser representado por 09:30-04:00.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss±hh:mm`

## Data e Hora sem Fuso Horario
> Alguns exemplos:

```
2019-10-15T22:35:12Z
2018-05-01T13:32:11Z
2019-05-01T00:00:00Z
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão ser enviados sem ele, sempre em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ssZ`

## Data
> Alguns exemplos

``` 
2019-10-15
2019-01-01
2017-03-20
```

No caso de campos que recebem somente data, uma data de nascimento, por exemplo, somente a data, sem nenhum horário deve ser enviada com o seguinte formato:

`YYYY-MM-dd`
 

## Documentos
Uma vez que os números de documento são bastante variados e muitos deles possuem caracteres que não se enquadram como numéricos, definem-se todos os números de documento como string. Outro bom motivo para definí-los como string é evitar que os zeros à esquerda desapareçam. Documentos previstos nesta página possuem uma máscara bem definida e estarão sujeitos a validação. O restante dos documentos, como RG, dada sua falta de padronização, não serão validados.

## CPF

> Exemplos de CPFs válidos contra a máscara definida:

```
123.456.789-12
321.987.543-23
111.283.333-00
```

> Exemplos de CPFs inválidos contra a máscara definida:

```
8.577.477-8
08.104.627/0001-23
123.456.789-1
23.456.789-01
```

O CPF é sempre definido como uma string e será validado conta a máscara:

`###.###.###-##`

## CNPJ

> Exemplos de CNPJs válidos contra a máscara definida:

```
08.104.627/0001-02
01.079.210/0114-67
32.402.502/0001-35
```

> Exemplos de CNPJs inválidos contra a máscara definida:

```
8.577.477-8
123.456.789-12
321.987.543-23
32.402.502/0001-3
032.402.502/0001-3
```

O CNPJ é sempre definido como uma string e será validado conta a máscara:

`##.###.###/####-##`

## IP

> Exemplos de IPs válidos contra a máscara definida:

```
201.81.161.86
201.081.161.86
201.81.161.086
201.81.0.1
```

> Exemplos de IPs inválidos:

```
201.81..86
358.81.161.86
201.81.161
```

IPs deverão ser enviados sempre em IPv4, zeros à esquerda poderão ou não ser enviados, respeitando a seguinte máscara:

`###.###.###.###`

---

# Webhook

URL: /documentation/caas/card_order/webhook

Webhook

Atualizações no status de fraude (Para Orders que sejam derivados para análise manual ou que sejam respondidos como Pendente) e para Sellers bloqueados, são notificados por meio de Webhook. Para tanto, é necessário, por meio da equipe do [suporte](mailto:suporte.caas@qitech.com.br), configurar um endereço do endpoint por onde vamos notificar as atualizações e também uma *signature_key* que será utilizada para assinar a requisição.

No caso da atualização do status do pedido, o cliente pode também utilizar a técnica de [polling](https://en.wikipedia.org/wiki/Polling_(computer_science)). Neste caso, basta não configurar o endpoint de webhook e utilizar os endpoints de recuperação de Order para proceder com o polling.

:::info **Atenção**

Por questões de segurança, todas as requisições de Webhook serão somente realizadas em endpoints servidos por HTTPS.
:::

## Assinatura do Webhook

## Webhook de Atualização de Order

Request Body

```json
    {
        "order_id": "123456",
        "fraud_status": "automatically_approved",
        "event_date": "2019-10-01T10:37:25-03:00"
    }
```

A requisição de atualização do status de análise de uma order possui o formato acima e notifica a mudança no status de fraude. O método utilizado é um PUT e o endereço do endpoint pode conter também o id do pedido, de acordo com a necessidade do cliente. É importante ressaltar que o corpo da requisição é enviado como texto codificado em UTF-8.

Exemplos de endpoints para atualização de pedido:

* https://apidocliente.com.br/order
* https://apidocliente.com.br/admin/order/1214

O campo event_date indica a data e hora em que a notificação foi criada e pode estar no passado caso envios de notificação anteriores tenham falhado.

## Webhook de Atualização de Seller

> Exemplo de requisição de bloqueio de liquidação

Request Body

```json
    {
        "document_number": "000.000.000-00",
        "settlement_status": "blocked",
        "event_date": "2019-10-01T10:37:25-03:00"
    }
```

> Exemplo de requisição de bloqueio transacional

Request Body

```json
    {
        "document_number": "000.000.000-00",
        "transactional_status": "blocked",
        "event_date": "2019-10-01T10:37:25-03:00"
    }
```

Caso o bloqueio ou desbloqueio de um seller seja necessário, o sistema da QI Tech realizará uma requisição com o formato acima. O método utilizado é um PUT realizado em um endpoint configurável e pode conter, a critério do cliente, o número do documento no endereço do endpoint.

:::info **Atenção**

É a presença do campo settlement_status ou do campo transactional_status que determina o tipo de bloqueio ou desbloqueio que deve ser realizado no seller.
:::

Exemplos de endpoints para atualização de seller:

* https://apidocliente.com.br/seller
* https://apidocliente.com.br/admin/seller/000.000.000-00

Os seguintes status de liquidação podem ser notificados:

enumerador | descrição
---- | ---------:
blocked | A liquidação do seller deve ser bloqueada
unblocked | A liquidação do seller deve ser liberada

O campo event_date indica a data e hora em que a notificação foi criada e pode estar no passado caso envios de notificação anteriores tenham falhado.

## Retentativas

A notificação é considerada realizada quando recebe como resposta um HTTP Status 200. Caso as notificações falhem, serão feitas 7 retentativas, com os seguintes intervalos, até que um 200 seja retornado ou as tentativas terminem:

* 10 segundos
* 40 segundos
* 160 segundos
* 640 segundos
* 2560 segundos
* 10240 segundos
* 40960 segundos

---

# Fluxo de Desafio

URL: /documentation/caas/credit_analysis/challenge_flow

É possível, após a execução da análise, ter como decisão desafiar o usuário para realizar uma nova ação em sua plataforma. Esse fluxo pode ser utilizado para, por exemplo, solicitar um comprovante de renda para um usuário que ainda não se tem certeza que deve ser aprovado ou reprovado na análise de crédito.

Com este fluxo você pode configurar uma regra cuja decisão desafia seu cliente a enviar informações adicionais para o sistema, como uma foto de um holerite ou qualquer outra informação relevante, e, depois de coletadas, utilização essas informações adicionais na execução de uma nova regra para reavaliação do usuário.

Há duas possibilidades de utilização deste fluxo, um deles de maneira automática, e outra fruto da decisão manual de um analista. Para o primeiro, o *analysis_status* retornado será *automatically_challenged* e para o segundo será *manually_challenged*. Abaixo temos a descrição do fluxo.
## Passo-a-passo da execução do fluxo

**1.** Proposta é submetida para análise (ver seção Análise de Crédito - Pessoa Física ou Análise de Crédito - Pessoa Jurídica ), e retornará o status *automatically_challenge* ou *in_manual_analysis*.

Request Body

```json
{
  "id": "12345",
  "registration_id":"12345",
  "credit_request_date": "2021-03-31T10:30:00-03:00",
  "credit_type": "clean",
  "name": "Victor Silva Barbosa",
  "document_number": "199.208.915-92",
  ...
}
```

Response Body

```json
{
  "id": "12345",
  "analysis_status": "automatically_challenge"
}
```

Caso a requisição retorne na resposta o status de *in_manual_analysis*, o analista poderá, através da dashboard, desafiar o usuário. Neste caso o status que será enviado na requisição de webhook é *manually_challenged*.

Response Body

```json
{
  "id": "12345",
  "analysis_status": "manually_challenged"
}
```

**2.** Após a primeira requisição de análise ter retornado um dos dois *analysis_status* de desafio, uma nova requisição deverá ser enviada com as informações adicionais coletadas do cliente, como por exemplo, uma novo imagem de documento enviada. Esta requisição deve conter o mesmo *registration_id* da requisição anterior, uma vez que este campo será utilizado para que a plataforma identifique que ambas as requsições se referem ao mesmo usuário, bem como vincular as informações adicionais coletadas do cliente. 

Request Body: Envio com informações adicionais

```json
{
  "id": "67890",
  "registration_id":"12345",
  "credit_request_date": "2021-03-31T10:30:00-03:00",
  "credit_type": "clean",
  "name": "Victor Silva Barbosa",
  "document_number": "199.208.915-92",
  "documents": {    
    "cnh": {
      "ocr_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76"
    }
  }
  ...
}
```

Response Body

```json
{
  "id": "12345",
  "analysis_status": "automatically_approved"
}
```

Atente-se para utilizar o mesmo registration_id utilizado na sua primeira análise.

---

# Recuperar uma Análise de Crédito

URL: /documentation/caas/credit_analysis/get_credit_analysis

A fim de recuperar uma Análise de Crédito específica, basta realizar uma requisição GET. O resultado retornado é o json mais atualizado da Análise em questão. Caso este identificador não esteja relacionado a nenhum objeto, o HTTP Status 404 é retornado.

* **Natural Person:**

`GET https://api.caas.qitech.app/credit_analysis/natural_person/12345678`

* **Legal Person:**

`GET https://api.caas.qitech.app/credit_analysis/legal_person/12345678`

```shell
curl "https://api.caas.qitech.app/credit_analysis/natural_person/12345678"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> O comando acima retorna o JSON que representa um objeto de Natural Person.

```shell
curl "https://api.caas.qitech.app/credit_analysis/legal_person/12345678"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> O comando acima retorna o JSON que representa um objeto de Legal Person.

---

# Status HTTP

URL: /documentation/caas/credit_analysis/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/credit_analysis/introduction

Bem vindo à API de análise de crédito da QI Tech! Você pode utilizar a nossa API para acessar os endpoints, a fim de executar uma análise de crédito, além de utilizar para atualizar a situação de um crédito concedido.

:::info **Atenção**
Atenção, esta API é direcionada a empresas que concedem crédito para Pessoas Físicas e Jurídicas. Ela tem como objetivo realizar toda a análise de crédito das operações do seu cliente, a partir dos dados enviados, dos dados de bureaus e fontes externas e dos dados do datalake da QI Tech, de maneira a tornar claro o retorno vs risco de cada uma das operações.

Esta API é projetada para pessoas físicas e jurídicas de pequeno porte. Não está preparada para calcular o risco de crédito de pessoas jurídicas de grande porte, onde é necessário um conhecimento aprofundado da operação e do mercado onde a empresa atua.
:::

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/credit_analysis/`
* Sandbox - `https://api.sandbox.caas.qitech.app/credit_analysis/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

No ambiente de Sandbox, as análises enviadas não são cobradas, são respondidas de acordo com regras pré estabelecidas e retornam dados fictícios, com o intuito exclusivo de simular o ambiente de produção para auxiliar o cliente no momento da integração.

Para a análise de uma operação de crédito, no ambiente de Sandbox, a decisão é aplicada sobre o valor total do crédito ( financial.amount ) a ser concedido, de acordo com a tabela abaixo:

Mínimo | Máximo | Decisão
------ | ------ | -------
10001 | - | Reprovado
8001 | 10000 | Análise Manual - Um webhook de reprovação manual é enviado após 1 minuto
6001 | 8000 | Análise Manual - Um webhook de aprovação manual é enviado após 1 minuto
4001 | 6000 | Aguardando Dados - Um webhook de aprovação automática é enviado após 1 minuto
2001 | 4000 | Pendente
0 | 2000 | Aprovado

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

## Autenticação

> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> Substitua a API key 'EXAMPLE-OF-API-KEY' com a sua chave adquirida com o nosso suporte.

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE-OF-API-KEY`

:::info **Atenção**

Você deve substituir EXAMPLE-OF-API-KEY com a API Key recebida do suporte.
:::

---

# Análise de Crédito - Pessoa Jurídica

URL: /documentation/caas/credit_analysis/legal_person

Para realizar a análise de crédito de uma pessoa jurídica, utilize o endpoint de Legal Person.

No momento em que uma análise de crédito de pessoa jurídica for realizada, os seguintes dados deverão ser enviados para o nosso servidor.

## Definição do Objeto Legal Person

Request Body

```json
{
  "id": "12345678",
  "credit_request_date": "2021-03-31T10:30:00-03:00",
  "credit_type": "student_loan",
  "legal_name": "QI Tech Tecnologia LTDA",
  "trading_name": "QI Tech",
  "document_number": "35.472.523/0001-15",
  "constitution_date": "2019-11-11",
  "constitution_type": "llc",
  "email": "suporte.caas@qitech.com.br",
  "monthly_revenue": 50000000,
  "client_category": "Premium User",
  "client_since": "2021-02-11",
  "address": {
    "country": "BRA",
    "street": "Av. Brigadeiro Faria Lima",
    "number": "2391",
    "neighborhood": "Jardim Paulistano",
    "city": "São Paulo",
    "uf": "SP",
    "postal_code": "01452-905"
  },
  "phones": [
    {
      "international_dial_code": "55",
      "area_code": "11",
      "number": "32234611",
      "type": "residential"
    }
  ],
  "shareholders": [
    {
      "name": "Anna Pinto Azevedo",
      "document_number": "261.026.462-31",
      "birthdate": "1972-08-22",
      "email": "annapintoazevedo@sample.com",
      "nationality": "BRA",
      "mother_name": "Beatrice Rodrigues Pinto",
      "father_name": "Luís Azevedo",
      "monthly_income": 800000,
      "declared_assets": 18600000,
      "occupation": "law",
      "gender": "female",
      "address": {
        "country": "BRA",
        "street": "Rua Derviche Djouki",
        "number": "598",
        "complement": "Ap 857",
        "neighborhood": "Chora Menino",
        "city": "São Paulo",
        "uf": "SP",
        "postal_code": "02463-080"
      },
      "phones": [
        {
          "international_dial_code": "55",
          "area_code": "11",
          "number": "55988644",
          "type": "mobile"
        }
      ]
    }
  ],
  "guarantors": [
    {
      "name": "Melissa Lima Melo",
      "document_number": "677.498.846-61",
      "birthdate": "1960-11-21",
      "email": "exemplo2@sample.com",
      "nationality": "BRA",
      "mother_name": "Raíssa Lima",
      "father_name": "Ronaldo Melo",
      "monthly_income": 800000,
      "declared_assets": 18600000,
      "occupation": "law",
      "gender": "female",
      "address": {
        "country": "BRA",
        "street": "Rua Castro Alves",
        "number": "100",
        "complement": "Ap 202",
        "neighborhood": "Parque Estrela Dalva I",
        "city": "Luziânia",
        "uf": "GO",
        "postal_code": "72804-050"
      },
      "phones": [
        {
          "international_dial_code": "55",
          "area_code": "11",
          "number": "21158745",
          "type": "residential"
        }
      ]
    }
  ],
  "financial": {
    "amount": 100000,
    "currency": "BRL",
    "interest_type": "cdi_plus",
    "annual_interest_rate": 2.32,
    "cdi_percentage": 100,
    "number_of_installments": 4
  },
  "warrants": [
    {
      "warrant_type": "real_estate",
      "address": {
        "country": "BRA",
        "street": "Rua Curitiba",
        "number": "150",
        "complement": "Bl 3 apt 122",
        "neighborhood": "Paraíso",
        "city": "São Paulo",
        "uf": "SP",
        "postal_code": "04005-030"
      },
      "property_type": "house",
      "estimated_value": 100000000,
      "forced_selling_value": 60000000
    }
  ],
  "source": {
    "channel": "website",
    "ip": "132.23.161.75",
    "session_id": "2bb684f9-6c00-4993-bcd7-18b9eccd7c9d"
  },
  "scr_parameters" : {
    ...
  }
}
```

Uma análise de crédito deve ser enviada para a API antes do desembolso e pode ser utilizada para se tomar a decisão de conceder ou não o crédito. Os dados enviados também podem, mediante acordo com o cliente, ser utilizados para a prevenção a fraudes.

Os objetos utilizados na composição do objeto CreditProposal e não definidos nesta seção estão disponíveis na seção [Objetos Compartilhados](#objetos-compartilhados).

|                   nome                   |      tipo      | descrição                                                                                                                                                                      |
| :--------------------------------------: | :------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|                    id                    |    string     | Identificador da proposta de crédito no seu sistema. <br /> **É essencial que este número seja único para cada processo de análise de crédito**                                |
|registration_id | string | Identificador do cadastro no sistema do cliente. Para realizar mais de uma análise referente a um mesmo cadastro, |
|           credit_request_date            |    datetime    | A data e hora quando o crédito foi requisitado pelo tomador                                                                                                                    |
|               credit_type                |   enum   | Tipo de crédito sendo concedido. No momento são suportados: **clean**, **student_loan**, **credit_card_limit**                                                                 |
| legal_name        |         string          | Razão social                                                                   |
| trading_name      |         string          | Nome fantasia                                                                  |
| document_number   |         string          | O CNPJ, formatado conforme padrão estabelecido nesta documentação              |
| monthly_revenue   |         integer         | Receita mensal bruta em centavos                                               |
|client_category    |         string          | Categoria do cliente de acordo com a classificação da sua plataforma ou seu programa de fidelidade    |
|client_since    |         date | Data de início da prestação de serviços para este cliente   
| constitution_date |          data           | A data de constituição da companhia, conforme junta comercial                  |
| constitution_type |       enum        | O tipo de constituição da empresa: **LLC**, **corp**                           |
| email             |         string          | O email do representante da empresa                                            |
| address           |        _Address_        | O endereço da matriz da companhia                                              |
| phones            |    list of _Phones_     | Os telefones colhidos da companhia                                             |
| shareholders      | list of _NaturalPerson_ | Os sócios da companhia, no modelo de pessoa física (Objeto **NaturalPerson**) |
|                guarantors                | list of _Person_ | Garantidores da operação, Pessoa física (**NaturalPerson**) ou jurídica (**LegalPerson**)                                                                                       |
|             financial.amount             |    integer     | O valor total sendo requerido pelo tomador, que será liberado em caso de aprovação                                                                                             |
|             financial.currency           |    enum     | A unidade monetária referente ao valor total: **BRL**, **USD**, **EUR**                                                                                          |
|              interest_type               |   enum   | O indexador da dívida que será utilizado: **cdi_plus**, **cdi_percentage**, **price**, **pre_fixed**                                                                           |
|           annual_interest_rate           |     number     | O valor da parte pré-fixada do juros, em percentual ao ano                                                                                                                     |
|              cdi_percentage              |     number     | O percentual do CDI (Pós) do juros a ser cobrado                                                                                                                               |
|          number_of_installments          |    integer     | Número de parcelas                                                                                                                                                             |
|                 warrants                 |     _Warrant_     | Dados de garantias reais oferecidas na operação. Deverá ser acordada antes da entrada em produçao. Atualmente os seguintes tipos são aceitos: **real_estate**                  |
|              source               |     _Source_     | O canal de venda do crédito. Atualmente são aceitos: **website** e **app**                                                                                                     |
| scr_parameters| _ScrParameters_ | Objeto com as informações necessárias para a utilização das informações do SCR na análise de crédito |

## Enviar uma Proposta de Crédito - Pessoa Jurídica

Request Body

```json
  {
    "id": "12345678",
    ...
  }
```

Response Body

```json
{
  "id": "12345678",
  "analysis_status": "automatically_approved",
  "reason": "rule_decision_enum"
}
```

Para realizar a avaliação de uma proposta de crédito, basta enviar um objeto do tipo LegalPerson ao seguinte endpoint:

`POST https://api.caas.qitech.app/credit_analysis/legal_person`

---

# Análise de Crédito - Pessoa Física

URL: /documentation/caas/credit_analysis/natural_person

Para realizar a análise de crédito de uma pessoa física, utilize o endpoint de NaturalPerson.

No momento em que uma análise de crédito de pessoa física for realizada, os seguintes dados abaixo devem ser enviados para o nosso servidor.

## Definição do Objeto Natural Person

Request Body

```json
{
  "id": "12345678",
  "registration_id":"444",
  "credit_request_date": "2021-03-31T10:30:00-03:00",
  "credit_type": "student_loan",
  "name": "Victor Silva Barbosa",
  "document_number": "199.208.915-92",
  "birthdate": "1990-01-01",
  "email": "exemplo@sample.com",
  "nationality": "BRA",
  "gender": "male",
  "mother_name": "Ana Barbosa",
  "father_name": "João Silva",
  "monthly_income": 30000,
  "declared_assets": 7500000,
  "occupation": "pedagogy",
  "address": {
    "country": "BRA",
    "street": "Rua Curitiba",
    "number": "150",
    "complement": "Bl 3 apt 122",
    "neighborhood": "Paraíso",
    "city": "São Paulo",
    "uf": "SP",
    "postal_code": "04005-030"
  },
  "phones": [
    {
      "international_dial_code": "55",
      "area_code": "11",
      "number": "32234611",
      "type": "residential"
    }
  ],
  "guarantors": [
    {
      "name": "Melissa Lima Melo",
      "document_number": "677.498.846-61",
      "birthdate": "1960-11-21",
      "email": "exemplo2@sample.com",
      "nationality": "BRA",
      "mother_name": "Raíssa Lima",
      "father_name": "Ronaldo Melo",
      "monthly_income": 800000,
      "declared_assets": 18600000,
      "occupation": "law",
      "gender": "female",
      "address": {
        "country": "BRA",
        "street": "Rua Castro Alves",
        "number": "100",
        "complement": "Ap 202",
        "neighborhood": "Parque Estrela Dalva I",
        "city": "Luziânia",
        "uf": "GO",
        "postal_code": "72804-050"
      },
      "phones": [
        {
          "international_dial_code": "55",
          "area_code": "11",
          "number": "21158745",
          "type": "residential"
        }
      ]
    }
  ],
  "financial": {
    "amount": 100000,
    "currency": "BRL",
    "interest_type": "cdi_plus",
    "annual_interest_rate": 2.32,
    "cdi_percentage": 100,
    "number_of_installments": 4
  },
  "warrants": [
    {
      "warrant_type": "real_estate",
      "address": {
        "country": "BRA",
        "street": "Rua Curitiba",
        "number": "150",
        "complement": "Bl 3 apt 122",
        "neighborhood": "Paraíso",
        "city": "São Paulo",
        "uf": "SP",
        "postal_code": "04005-030"
      },
      "property_type": "house",
      "estimated_value": 100000000,
      "forced_selling_value": 60000000
    }
  ],
  "source": {
    "channel": "website",
    "ip": "145.25.145.32",
    "session_id": "bec256b3-5265-4dcb-bc55-2e4fb43983e0"
  },
  "scr_parameters" : {
    ...
  }
}
```

Uma análise de crédito deve ser enviada para a API antes do desembolso e pode ser utilizada para se tomar a decisão de conceder ou não o crédito. Os dados enviados também podem, mediante acordo com o cliente, ser utilizados para a prevenção a fraudes.

Os objetos utilizados na composição do objeto **CreditProposal** e não definidos nesta seção estão disponíveis na seção [Objetos Compartilhados](#objetos-compartilhados).

|                   nome                   |      tipo      | descrição                                                                                                                                                                      |
| :--------------------------------------: | :------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|                    id                    |    string     | Identificador da proposta de crédito no seu sistema. <br /> **É essencial que este número seja único para cada processo de análise de crédito** *(obrigatório)*|
|registration_id | string | Identificador do cadastro no sistema do cliente. Para realizar mais de uma análise referente a um mesmo cadastro|
|           credit_request_date            |    datetime    | A data e hora quando o crédito foi requisitado pelo tomador *(obrigatório)*|
|               credit_type                |   enum   | Tipo de crédito sendo concedido. No momento são suportados: **clean**, **student_loan**, **credit_card_limit** |
| name | string | Nome completo do indivíduo sendo cadastrado |
| document_number | string | CPF do indivíduo sendo cadastrado, com pontos e hífens, de acordo com a padronização *(obrigatório)* |
| birthdate | date | Data de nascimento do indivíduo de acordo com a padronização
| gender | enum | Gênero do indivíduo: 'male', 'female' ou 'undefined'
| nationality | string | A nacionalidade do cadastro, em ISO 3166-1 alfa-3
| mother_name | string | Nome completo da mãe
| father_name | string | Nome completo do pai
| monthly_income | integer | Renda mensal bruta em centavos
| declared_assets | integer | Patrimônio declarado em centavos
|client_category    |         string          | Categoria do cliente de acordo com a classificação da sua plataforma ou seu programa de fidelidade
|client_since    |         date | Data de início da prestação de serviços para este cliente   
| occupation | string | Profissão do indivíduo sendo cadastrado
| email | string | O email da pessoa
| documents | Document | Objetos do tipo CNH e RG
| address | _Address_ | Objeto do tipo Address que descreve o endereço da moradia do indivíduo
| phones | Lista de _Phones_ | Lista de objetos do tipo phone que possui a lista de telefones do indivíduo
|                guarantors                | list of _Person_ | Garantidores da operação, Pessoa física (**NaturalPerson**) ou jurídica (**LegalPerson**)                                                                                       |
|             financial.amount             |    integer     | O valor total sendo requerido pelo tomador, que será liberado em caso de aprovação em centavos                                                                                             |
|             financial.currency           |    enum     | A unidade monetária referente ao valor total: **BRL**, **USD**, **EUR**                                                                                          |
|              interest_type               |   enum   | O indexador da dívida que será utilizado: **cdi_plus**, **cdi_percentage**, **price**, **pre_fixed**                                                                           |
|           annual_interest_rate           |     number     | O valor da parte pré-fixada do juros, em percentual ao ano                                                                                                                     |
|              cdi_percentage              |     number     | O percentual do CDI (Pós) do juros a ser cobrado                                                                                                                               |
|          number_of_installments          |    integer     | Número de parcelas                                                                                                                                                             |
|                 warrants                 |     _Warrant_     | Dados de garantias reais oferecidas na operação. Deverá ser acordada antes da entrada em produção. Atualmente os seguintes tipos são aceitos: **real_estate**                  |
|              source               |     _Source_     | O canal de venda do crédito. Atualmente são aceitos: **website** e **app**                                                                                                     |
| scr_parameters| _ScrParameters_ | Objeto com as informações necessárias para a utilização das informações do SCR na análise de crédito |

:::info **Atenção**
A propriedade scr_parameters é obrigatória apenas se o cliente contratou e deseja utilizar a consulta SCR na análise de crédito.
:::

## Enviar uma Proposta de Crédito - Pessoa Física

Request Body

```json
  {
    "id": "12345678",
    ...
  }
```

Response Body

```json
{
  "id": "12345678",
  "analysis_status": "automatically_approved",
  "reason": "rule_decision_enum"
}
```

Para realizar a avaliação de uma proposta de crédito, basta enviar um objeto do tipo **NaturalPerson** ao seguinte endpoint:

`POST https://api.caas.qitech.app/credit_analysis/natural_person`

---

# Objetos Compartilhados

URL: /documentation/caas/credit_analysis/objects

Abaixo as definições de outros objetos utilizados ao longo da documentação.

## Objeto _Address_

Request Body

```json
{
  "street": "Rua do Exemplo",
  "number": "111" ,
  "neighborhood": "Bairro do Teste",
  "city": "Aparecida de Goiânia",
  "uf": "GO",
  "complement": "Apt 903",
  "postal_code": "00000-000"
}
```

O objeto _Address_ é utilizado para representar endereços em toda a API, endereços no território brasileiro são representados da seguinte maneira:

| nome         |  tipo  | descrição                                                                                    |
| ------------ | :----: | -------------------------------------------------------------------------------------------- |
| street       | string | Rua do endereço, incluindo o logradouro, evitando, se possível, abreviações *(obrigatório)*. |
| number       | string | Número do imóvel, incluindo letras caso possua *(obrigatório)*.                              |
| neighborhood | string | Bairro, sem abreviações *(obrigatório)*. <br />**e.g.: Santa Felicidade**                    |
| city         | string | Nome completo da cidade, sem abreviações *(obrigatório)*.                                    |
| uf           | string | A unidade federativa, com duas letras maiúsculas *(obrigatório)*. <br />**e.g.: SP**         |
| complement   | string | Quaisquer complementos para localizar o imóvel. <br />**e.g.: Apartamento 101, Conjunto 12** |
| postal_code  | string | O código postal da localidade, contendo o hífen *(obrigatório)*.                             |
| country      | string | Código ISO 3166-1 alfa-3 do país do endereço *(obrigatório)*.                                |

No caso dos endereços cujo país não seja Brasil ("BRA"), o postal_code e a unidade federativa poderão ser preenchidos livremente.

## Objeto _Phone_

Request Body

```json
{
  "international_dial_code": "1",
  "area_code": "11",
  "number": "999999999",
  "type": "mobile"
}
```

Um objeto _Phone_ representa um número telefônico, dentro ou fora do Brasil e sua classificação. Para isso, os campos são:

| nome                    |  tipo  | descrição                                                        |
| ----------------------- | :----: | ---------------------------------------------------------------- |
| international_dial_code | string | Código de discagem internacional, sem zero ou +, somente números *(obrigatório)*. |
| area_code               | string | Código de área, sem zero, somente números *(obrigatório)*.                        |
| number                  | string | Número do telefone, sem o hífen *(obrigatório)*.                                  |
| type                    |  enum  | Tipo de número: celular, residencial, comercial, etc.            |

Existem os seguintes enumeradores para tipo de telefone: `residential`, `commercial`, `mobile`

## Objeto _cnh_

Request Body

```json
{
  "register_number": "05163811694",
  "issuer_state": "PR",
  "first_issuance_date":"2011-03-21",
  "issuance_date":"2016-06-29",
  "expiration_date":"2021-06-25",
  "category": "AB",
  "validation_type":"zaig_sdk",
  "ocr_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76"
}
```

O objeto *cnh* é utilizado para representar as CNHs em toda a API bem como se foi utilizado algum meio de validação dos mesmos. Eles são representados da seguinte maneira:

nome | tipo | descrição
---- | :----: | ---------
register_number | string | Número do registro da CNH cadastrada.
issuer_state | enum | Enumerador do estado onde a CNH foi emitida
first_issuance_date | date | Data de primeira habilitação.
issuance_date | date | Data de emissão
expiration_date | date | Data de vencimento
category | enum | Categoria da CNH em letras maiúsculas
validation_type | enum | Tipo de validação utilizada durante o cadastro do documento.
ocr_key | guid | Id retornado pela API de [validação de documento da QI Tech](https://docs.zaig.com.br/ocr/#introducao).

Existem os seguintes enumeradores para *validation_type*: `zaig_api` e `zaig_sdk`.

## Objeto _rg_

Request Body

```json
{
  "number": "4.366.477-8",
  "issuer": "II",
  "issuer_state": "PR",
  "issuance_date":"2002-01-12",
  "validation_type":"zaig_sdk",
  "ocr_front_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76",
  "ocr_back_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76"
}
```

O objeto *rg* é utilizado para representar os RGs em toda a API bem como se foi utilizado algum meio de validação dos mesmos. Eles são representados da seguinte maneira:

nome | tipo | descrição
---- | :----: | ---------
number | string | Número do documento cadastrado, incluindo formatação (Pontos, Hífens, Barras e outros).
issuer | string | Órgão emissor do documento (Sigla, e.g.: II, SESP...)
issuer_state | enum | UF emissor do documento.
issuance_date | date | Data de emissão do documento.
validation_type | enum | Tipo de validação utilizada durante o cadastro do documento.
ocr_key | guid | Id retornado pela API de validação de documento da QI Tech.

Existem os seguintes enumeradores para *validation_type*: `zaig_api` e `zaig_sdk`.

## Objeto _NaturalPerson_

Request Body

```json
{
  "name": "Melissa Lima Melo",
  "document_number": "677.498.846-61",
  "birthdate": "1960-11-21",
  "email": "exemplo2@sample.com",
  "nationality": "BRA",
  "gender": "female",
  "mother_name": "Raíssa Lima",
  "father_name": "Ronaldo Melo",
  "monthly_income": 800000,
  "declared_assets": 18600000,
  "occupation": "law",
  "address": {
    "country": "BRA",
    "street": "Rua Castro Alves",
    "number": "100",
    "complement": "Ap 202",
    "neighborhood": "Parque Estrela Dalva I",
    "city": "Luziânia",
    "state": "GO",
    "postal_code": "72804-050"
  },
  "phones": [
    {
      "international_dial_code": "55",
      "area_code": "11",
      "number": "21158745",
      "type": "residential"
    }
  ]
}
```

O objeto _NaturalPerson_ representa os dados de uma pessoa que pode ser o próprio tomador, um garantidor ou um sócio de uma empresa tomadora. Ele é composto por:

| nome             |       tipo       | descrição                                                                                      |
| ---------------- | :--------------: | ---------------------------------------------------------------------------------------------- |
| name             |      string      | Nome completo *(obrigatório)*.                                                                                 |
| document_number  |      string      | O CPF, formatado adequadamente *(obrigatório)*.                                                                |
| birthdate        |       date       | A data de nascimento da pessoa.                                                              |
| email            |      string      | O email da pessoa.                                                                              |
| gender           |       enum       | O gênero da pessoa, de acordo com a lista de enumeradores.                                  |
| address          |    _Address_     | O endereço residencial da pessoa.                                                               |
| phones           | list of _Phone_ | Os telefones colhidos da pessoa.                                                                |

Enumeradores de gênero:

- `male`
- `female`
- `undefined`

## Objeto _LegalPerson_

Request Body

```json
{
  "legal_name": "QI Tech Tecnologia LTDA",
  "trading_name": "QI Tech",
  "document_number": "35.472.523/0001-15",
  "constitution_date": "1990-01-01",
  "constitution_type": "llc",
  "email": "exemplo@sample.com",
  "address": { ... },
  "phones": [ { ... } ],
  "shareholders": [ { ... }]
}
```

O objeto _LegalPerson_ representa os dados de uma empresa que está tomando crédito ou garantindo o crédito (Fiador). Ele é composto por:

| nome              |          tipo           | descrição                                                                      |
| ----------------- | :---------------------: | ------------------------------------------------------------------------------ |
| legal_name        |         string          | Razão social *(obrigatório)*.                                                                   |
| trading_name      |         string          | Nome fantasia                                                                  |
| document_number   |         string          | O CNPJ, formatado conforme padrão estabelecido nesta documentação *(obrigatório)*.              |
| constitution_date |          data           | A data de constituição da companhia, conforme junta comercial                  |
| constitution_type |       enumerador        | O tipo de constituição da empresa: **LLC**, **corp**                           |
| email             |         string          | O email do representante da empresa                                            |
| address           |        _Address_        | O endereço da matriz da companhia                                              |
| phones            |    list of _Phone_     | Os telefones colhidos da companhia                                             |
| shareholders      | list of _NaturalPerson_ | Os sócios da companhia, no modelo de pessoa física (Objeto **NaturalPerson**) |

## Objeto _Source_

Request Body: Pedidos de crédito realizados por meio do site próprio

```json
{
  "channel": "website",
  "ip": "201.81.161.86",
  "session_id": "b8da64db-e8f8-47fc-8d8e-11ce26da499f"
}
```

Request Body: Pedidos de crédito realizados por meio de aplicativo próprio

```json
{
  "channel": "app",
  "platform": "android",
  "ip": "201.81.161.86",
  "session_id": "b8da64db-e8f8-47fc-8d8e-11ce26da499f"
}
```

O objeto source representa o local onde o pedido de crédito foi realizado.

Atenção, caso o canal de venda desejado não se enquadre em nenhuma destas categorias, entrar em contato com a equipe de suporte

## Objeto _Warrant_

> Para análises de crédito que possuam algum tipo de garantia, o objeto warrant pode ser utilizado para informá-lo à nossa API. No momento, somente garantias de imóvel são aceitas e caso seja necessário outro tipo de garantia, basta entrar em contato com o nosso suporte

Request Body

```json
  {
    "warrant_type": "real_estate",
    "address": { ... },
    "property_type": "house",
    "estimated_value": 100000000,
    "forced_selling_value": 60000000
  }
```

Para a garantia do tipo **real_estate**, o objeto é formado pelos seguintes campos:

| nome                 |  tipo   | descrição                                                                                                                 |
| -------------------- | :-----: | ------------------------------------------------------------------------------------------------------------------------- |
| warrant_type         |  enum   | Define o tipo de garantia. No momento somente **real_estate** está implementado.                                          |
| address              | _Address_  | Objeto do tipo Address que identifica o imóvel dado como garantia                                                         |
| property_type        |  enum   | O tipo de imóvel em questão, no momento estão disponíveis: **house**, **commercial_building**, **office**, **appartment** |
| estimated_value      | integer | O valor estimado do imóvel                                                                                                |
| forced_selling_value | integer | O valor de venda forçada estimado do imóvel                                                                               |

Atenção, caso a garantia desejada não se enquadre em nenhuma destas categorias, entrar em contato com a equipe de suporte

## Objeto _ScrParameters_

Request Body

```json
  {
    "scr_parameters": {
      "signers": [
        {
          "document_number": "111.222.333-44",
          "name": "Felipe Marques da Silva",
          "email": "felipe.silva@qitech.com.br",
          "phone": {
            "number": "991722315",
            "area_code": "16",
            "international_dial_code": "55"
          }
        }
      ],
      "signature_evidence": {
        "ip_address": "179.104.42.245",
        "session_id": "ddb1d063-4fdf-4330-af9c-3316e9142ff3",
        "access_token":         "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQSflKxwRJSMeKKF2QT4fwpMeJf36PO6yJV_adQssw5d",
        "additional_data": {
          ...
        },
        "signed_term": {
          "raw_text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas elementum erat et tempus dapibus. Donec eu sapien tortor. Pellentesque 
            et tortor eget erat pulvinar mattis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin ornare diam arcu, sit amet auctor lorem varius quis. Ut pretium venenatis magna sed ultrices. Donec quis tortor odi."
        }
      }
    }
  }
```

| nome                 |  tipo   | descrição                                                                                                                 |
| -------------------- | :-----: | ------------------------------------------------------------------------------------------------------------------------- |
| signers |  Lista de _Signer_ | Lista de pessoas que vão assinar ou assinaram a autorização de consentimento para consulta SCR. Este objeto só deve ser enviado no caso de análises de crédito de pessoas jurídicas. |
| signature_evidence | _SignatureEvidence_  | Objeto que para envio das informações coletadas no momento da autorização de consentimento quando a autorização é solicitada na plataforma do cliente. |

## Objeto *Signer*

Request Body

```json
  {
    "document_number": "111.222.333-44",
    "name": "Felipe Marques da Silva",
    "email": "felipe.silva@qitech.com.br",
    "phone": {
      "number": "991722315",
      "area_code": "16",
      "international_dial_code": "55"
    }
  }
```

| nome                 |  tipo   | descrição                                                                                                                 |
| -------------------- | :-----: | ------------------------------------------------------------------------------------------------------------------------- |
| document_number        |  string   | Número do documento do assinante. |
| name | string | Nome do assinante. |
| email | string | Email do assinante. |
| phone | _Phone_ | Telefone do assinante. |

## Objeto *Signature_Evidence*

Request Body

```json
  {
    "signature_evidence": {
      "ip_address": "179.104.42.245",
      "session_id": "ddb1d063-4fdf-4330-af9c-3316e9142ff3",
      "access_token":         "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQSflKxwRJSMeKKF2QT4fwpMeJf36PO6yJV_adQssw5d",
      "additional_data": {
        ...
      },
      "signed_term": {
        "raw_text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas elementum erat et tempus dapibus. Donec eu sapien tortor. Pellentesque 
          et tortor eget erat pulvinar mattis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin ornare diam arcu, sit amet auctor lorem varius quis. Ut pretium venenatis magna sed ultrices. Donec quis tortor odi."
      }
    }
  }
```

| nome                 |  tipo   | descrição                                                                                                                 |
| -------------------- | :-----: | ------------------------------------------------------------------------------------------------------------------------- |
| ip_address | string  | IP do assinante |
| session_id | string | Identificador de sessão do usuário na sua plataforma, deve ser algum identificador que permita solicitar auditoria de um OptIn feito na sua plataforma através deste identificador. |
| access_token |  string | Identificador do usuário logado na sua plataforma, deve ser possível solicitar auditoria de cadastro deste usuário através deste identificador. |
| additional_data | objeto | Objeto JSON configurável para acomodar informações adicionais que o parceiro julgar relevantes que adicionem fidelidade/credibilidade/autent icidade na assinatura realizada dentro de sua plataforma. |
| signed_term | _SignedTerm_ | Objeto que traz informações sobre o termo que está sendo utilizado para coleta de consentimento. | 

## Objeto *SignedTerm*

Request Body

```json
  {
    "raw_text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas elementum erat et tempus dapibus. Donec eu sapien tortor. Pellentesque et tortor eget erat pulvinar mattis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin ornare diam arcu, sit amet auctor lorem varius quis. Ut pretium venenatis magna sed ultrices. Donec quis tortor odi."
  }
```

| nome                 |  tipo   | descrição                                                                                                                 |
| -------------------- | :-----: | ------------------------------------------------------------------------------------------------------------------------- |
| raw_text | string | Texto plano do termo que está sendo assinado. |

---

# Dados Sistema de Informações de Créditos (SCR - BACEN)

URL: /documentation/caas/credit_analysis/scr

Caso o cliente contrate, temos a opção da utilização dos dados disponíveis no SCR da pessoa física ou jurídica no momento da análise de crédito. Para utilização dos dados do SCR, é primordial que o consentimento do consultado seja coletado. Esse consentimento pode ser coletado pela QI Tech ou pelo próprio cliente e isso influencia no fluxo de consentimento, bem como nos dados que devem ser enviados para a API, conforme abaixo:

**1. Coleta de consentimento via QI Tech -** Caso opte pela coleta do consentimento via QI Tech, um link para assinatura eletrônica é enviado diretamente, via e-mail, da QI Tech para o usuário consultado e, quando o usuário assina o link e finaliza o processo, a informação do SCR automaticamente torna-se disponível para uso. Para utilização deste fluxo, é necessário que, na integração, sejam enviados os dados do usuário final que irá assinar o termo de consentimento.

**2. Coleta do consentimento pelo próprio cliente -**  É possível coletar a assinatura do termo de consentimento em seu próprio ambiente ou esteira de crédito (pode ser feito por documento assinado ou opt-in box do termo). Para que isso seja possível, o termo de consentimento utilizado deve ser validado pelo time jurídico da QI Tech e se faz necessário o envio de informações que comprovem de maneira auditável que o consentimento para acesso à informação de SCR foi coletado através do objeto *scr_parameters*.

Atenção, ambas configurações de acesso as informações de SCR, incluindo qual fluxo será utilizado, devem ser acordadas durante contratação do produto para que a funcionalidade esteja disponível para uso.

## Coleta do Consentimento via QI Tech - Pessoa Física

No caso de uma pessoa física, para que a QI Tech envie o pedido de consentimento, basta o preenchimento dos dados pessoais do consultado no objeto de CreditProposal . Com isso, a QI Tech irá enviar o pedido de consentimento ao consultado via e-mail e, automaticamente, realizar a consulta (após autorizaçao), disponibilizando os resultados para análise de crédito.

É obrigatório o envio dos campos _document_number_ , name , email e do objeto phone para coleta do consentimento de pessoa física via QI Tech.

## Coleta do Consentimento via QI Tech - Pessoa Jurídica

Request Body

```json

  {
    "id": "32199d0s",
    "legal_name": "QI CAAS LTDA",
    "trading_name": "QI Tech",
    ...
    "scr_parameters": {
      "signers": [
        {
          "document_number": "372.989.950-30",
          "name": "Felipe Marques da Silva",
          "email": "felipe.silva@qitech.com.br",
          "phone": {
            "number": "991722315",
            "area_code": "16",
            "international_dial_code": "55"
          }
        },
        {
          "document_number": "440.896.050-08",
          "name": "Claudio Mattos",
          "email": "claudiomattos@sample.com",
          "phone": {
            "number": "991722315",
            "area_code": "16",
            "international_dial_code": "55"
          }
        }
      ]
    }
  }
```

No caso de uma pessoa jurídica, para que a QI Tech envie o pedido de consentimento, é necessário incluir o objeto adicional scr_parameters na requisição de análise. Dentro deste objeto, será necessário adicionar a lista de responsáveis legais da empresa para os quais serão enviados os pedidos de assinatura eletrônica via e-mail. Essa lista deve ser enviada dentro da propriedade signers . Após a assinatura de todos os representantes legais, a QI Tech realizará a consulta, disponibilizando os resultados para análise de crédito. Acima temos um exemplo do objeto scr_parameters para o caso descrito.

## Coleta do Consentimento pelo Próprio Cliente - Pessoa Física

Request Body

```json
  {
    "id": "678",
    "credit_request_date": "2021-03-31T10:30:00-03:00",
    "credit_type": "student_loan",
    "name": "Victor Silva Barbosa",
    "document_number": "199.208.915-92",
    ...
    "scr_parameters": {
      "signature_evidence": {
        "ip_address": "179.104.42.245",
        "session_id": "ddb1d063-4fdf-4330-af9c-3316e9142ff3",
        "access_token":         "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQSflKxwRJSMeKKF2QT4fwpMeJf36PO6yJV_adQssw5d",
        "additional_data": {
          ...
        },
        "signed_term": {
          "raw_text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas elementum erat et tempus dapibus. Donec eu sapien tortor. Pellentesque et tortor eget erat pulvinar mattis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin ornare diam arcu, sit amet auctor lorem varius quis. Ut pretium venenatis magna sed ultrices. Donec quis tortor odi."
        }
      }
    }
  }
```

No caso de uma pessoa física, quando a coleta do consentimento é realizada pelo cliente, é necessário incluir o objeto adicional scr_parameters na requisição de análise. Dentro deste objeto, é necessário adicionar informações para comprovar que a pessoa analisada autorizou a consulta. Essas informações devem ser enviadas dentro da propriedade signature_evidence . Acima temos um exemplo do objeto scr_parameters para o caso descrito.

## Coleta do Consentimento pelo Próprio Cliente - Pessoa Jurídica

Request Body

```json
  {
    "id": "678",
    "credit_request_date": "2021-03-31T10:30:00-03:00",
    "credit_type": "student_loan",
    "name": "Victor Silva Barbosa",
    "document_number": "199.208.915-92",
    ...
    "scr_parameters": {
      "signers": [
        {
          "document_number": "372.989.950-30",
          "name": "Felipe Marques da Silva",
          "email": "felipe.silva@qitech.com.br",
          "phone": {
            "number": "991722315",
            "area_code": "16",
            "international_dial_code": "55"
          }
        },
        {
          "document_number": "440.896.050-08",
          "name": "Claudio Mattos",
          "email": "claudiomattos@sample.com",
          "phone": {
            "number": "991722315",
            "area_code": "16",
            "international_dial_code": "55"
          }
        }
      ],
      "signature_evidence": {
        "ip_address": "179.104.42.245",
        "session_id": "ddb1d063-4fdf-4330-af9c-3316e9142ff3",
        "access_token":         "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQSflKxwRJSMeKKF2QT4fwpMeJf36PO6yJV_adQssw5d",
        "additional_data": {
          ...
        },
        "signed_term": {
          "raw_text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas elementum erat et tempus dapibus. Donec eu sapien tortor. Pellentesque et tortor eget erat pulvinar mattis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin ornare diam arcu, sit amet auctor lorem varius quis. Ut pretium venenatis magna sed ultrices. Donec quis tortor odi."
        }
      }
    }
  }
```

No caso de uma pessoa jurídica, quando a coleta do consentimento é realizada pelo cliente, é necessário incluir o objeto adicional scr_parameters na requisição de análise. Dentro deste objeto, é necessário adicionar informações para comprovar que a pessoa analisada autorizou a consulta, bem como adicionar a lista de responsáveis legais da empresa que autorizaram a consulta. As informações de autorização deverão ser enviadas dentro da propriedade signature_evidence e a lista de pssoas que autorizaram a consulta dentro da propriedade signers . Acima temos um exemplo do objeto scr_parameters para o caso descrito.

---

# Padrões

URL: /documentation/caas/credit_analysis/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões que são seguidos em toda a API.

## Valores Monetários
> Exemplos:

```
10000
12345
98741
1223
1
0
```

As APIs assumem que todos os valores monetários enviados são em Reais Brasileiros. Os valores devem ser enviados como inteiro em centavos.

## Data e Hora com Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12-03:00
2018-05-01T13:32:11+00:00
2019-05-01T00:00:00+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será valido. Por exemplo, se um aluguel estiver marcado para começar às 09:30 no aeroporto de Brasília, o horário enviado deverá ser representado por 09:30-03:00, se o aluguel estiver marcado para começar às 09:30 em Manaus, deverá ser representado por 09:30-04:00.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss±hh:mm`

## Data e Hora sem Fuso Horario
> Alguns exemplos:

```
2019-10-15T22:35:12
2018-05-01T13:32:11
2019-05-01T00:00:00
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão ser enviados sem ele, sempre em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ssZ`

## Data
> Alguns exemplos

``` 
2019-10-15
2019-01-01
2017-03-20
```

No caso de campos que recebem somente data, uma data de nascimento, por exemplo, somente a data, sem nenhum horário deve ser enviada com o seguinte formato:

`YYYY-MM-dd`
 

## Documentos
Uma vez que os números de documento são bastante variados e muitos deles possuem caracteres que não se enquadram como numéricos, definem-se todos os números de documento como string. Outro bom motivo para definí-los como string é evitar que os zeros à esquerda desapareçam. Documentos previstos nesta página possuem uma máscara bem definida e estarão sujeitos a validação. O restante dos documentos, como RG, dada sua falta de padronização, não serão validados.

## CPF

> Exemplos de CPFs válidos contra a máscara definida:

```
123.456.789-12
321.987.543-23
111.283.333-00
```

> Exemplos de CPFs inválidos contra a máscara definida:

```
8.577.477-8
08.104.627/0001-23
123.456.789-1
23.456.789-01
```

O CPF é sempre definido como uma string e será validado conta a máscara:

`###.###.###-##`

## CNPJ

> Exemplos de CNPJs válidos contra a máscara definida:

```
08.104.627/0001-02
01.079.210/0114-67
32.402.502/0001-35
```

> Exemplos de CNPJs inválidos contra a máscara definida:

```
8.577.477-8
123.456.789-12
321.987.543-23
32.402.502/0001-3
032.402.502/0001-3
```

O CNPJ é sempre definido como uma string e será validado conta a máscara:

`##.###.###/####-##`

## IP

> Exemplos de IPs válidos contra a máscara definida:

```
201.81.161.86
201.081.161.86
201.81.161.086
201.81.0.1
```

> Exemplos de IPs inválidos:

```
201.81..86
358.81.161.86
201.81.161
```

IPs deverão ser enviados sempre em IPv4, zeros à esquerda poderão ou não ser enviados, respeitando a seguinte máscara:

`###.###.###.###`

---

# Dinâmica dos Status

URL: /documentation/caas/credit_analysis/status_dynamics

O processo de análise de crédito consiste em enviar uma requisição, tanto de **NaturalPerson** como de **LegalPerson** no respectivo endpoint e esperar a resposta.

Após a QI Tech realizar a análise de crédito, ela retornará uma resposta com um status referente a análise. Esse status tem o nome de **analysis_status**, que representa o resultado da analise de crédito realizado pela QI Tech.

Além do **analysis_status** a QI Tech também possui o **credit_proposal_status** que tem como objetivo representar o status do crédito analisado em cada momento de sua vida na sua plataforma.

## **analysis_status**

Conforme descrito anteriormente, a QI Tech possui sete **analysis_status** que indicam o status da decisão da análise de crédito e possui uma máquina de estados bastante simples:

analysis_status | Descrição
:---------: | ---------
automatically_approved | Os algoritmos da QI Tech recomendam que este cadastro seja aprovado
automatically_reproved | Os algoritmos da QI Tech recomendam que este cadastro seja reprovado
in_manual_analysis | Os algoritmos da QI Tech enviaram este cadastro para a análise manual
manually_approved | Após análise manual, o analista decidiu aprovar o cadastro
manually_reproved | Após análise manual, o analista decidiu reprovar o cadastro
waiting_for_data | A análise de crédito está aguardado o retorno de alguma informação de bureau ou provedor de dados e será respondido por meio de Webhook
automatically_challenged | Os algoritmos da QI Tech recomendam que este cadastro seja desafiado
manually_challenged | Após análise manual, o analista decidiu desafiar o cadastro
pending | A análise de crédito está demorando mais do que o esperado, este cadastro entrou em uma fila de análise automática e será respondido por meio de Webhook

:::info **Atenção**

Você deve substituir EXAMPLE-OF-API-KEY com a API Key recebida do suporte.
:::

## **credit_proposal_status**

O **credit_proposal_status** indica o status da operação do cliente, ou seja, o status da proposta de crédito na sua empresa ou plataforma. Os seguintes enumeradores existem para este status:

credit_proposal_status | Descrição
:---------: | ---------
created | A proposta de crédito foi criada na sua plataforma
disbursed | O proposta de crédito foi desembolsada na sua plataforma
paid | O cliente realizou o pagamento integral do crédito
defaulted | O cliente está inadimplente na sua plataforma

---

# Atualizar o status de uma Análise de Crédito

URL: /documentation/caas/credit_analysis/update_credit_analysis

Request Body: Para marcar o crédito como concedido

```json
{
  "credit_proposal_status": "disbursed",
  "event_date": "2021-11-05T13:34:12-03:00"
}
```

Para garantir a retroalimentação das regras e do modelo de inteligência artificial implementado, é necessário informar ao sistema quando as operações são efetivadas. Para isso, requisições com o método PUT devem ser utilizadas, autenticadas normalmente:

* **Natural Person:**

`PUT https://api.caas.qitech.app/credit_analysis/natural_person/12345678`

* **Legal Person:**

`PUT https://api.caas.qitech.app/credit_analysis/legal_person/12345678`

---

# Webhook

URL: /documentation/caas/credit_analysis/webhook

Webhook

Atualizações no status (Para cadastros que sejam derivados para análise manual ou que sejam respondidos como Pendente), são notificados por meio de Webhook. Para tanto, é necessário, por meio da equipe do [suporte](mailto:suporte.caas@qitech.com.br), configurar um endereço do endpoint por onde vamos notificar as atualizações e também um *secret_token* que será utilizado para assinar a requisição.

O cliente pode, apesar de não recomendável, também utilizar a técnica de [polling](https://en.wikipedia.org/wiki/Polling_(computer_science)). Neste caso, basta não configurar o endpoint de webhook e utilizar os endpoints de recuperação de cadastro para proceder com o polling.

## Assinatura do Webhook

## Requisição

```bash
curl --location 'YOUR-ENDPOINT-HERE' \
--header 'Signature: CALCULATED-HASH-HMAC' \
--data '{"natural_person_id": "538509",  "analysis_status": "manually_approved", "event_date": "2024-11-13T17:52:50Z", "reason": "manually_approved"}'
```

A requisição possui o formato acima e notifica a mudança no status. É importante ressaltar que a requisição utiliza o verbo HTTP POST e o corpo da requisição é enviado como texto codificado em UTF-8.

## Retentativas

A notificação é considerada realizada quando recebe como resposta um HTTP Status 200. Caso as notificações falhem, serão feitas 5 retentativas, com os seguintes intervalos, até que um 200 seja retornado ou as tentativas terminem:

* 30 segundos
* 60 segundos
* 120 segundos
* 240 segundos
* 360 segundos

---

# Objeto Account

URL: /documentation/caas/device_manager/account

A account (conta) é uma entidade organizacional que permite o cadastramento de dispositivos. Esta API foi projetada para atender a [Normativa 491 do BACEN](https://www.bcb.gov.br/estabilidadefinanceira/exibenormativo?tipo=Instru%C3%A7%C3%A3o%20Normativa%20BCB&numero=491), portanto, dados de account devem seguir um padrão para as informações definidas pelo Banco Central, mas quaisquer outros campos necessários podem ser adicionados aos dados da account.

## Definição do Objeto Account

Request Body

```json
{
  "account_id": "12345678",
  "account_type": "natural_person",
  "registration_date": "2019-12-11T11:37:15.12-03:00",
  "account_data": {
    "account_number": "12345678",
    "agency_number": "1234"
    ...
  }
}
```

Todas as trocas de informação de uma account utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

nome | tipo | descrição
:----: | :----: | ---------
account_id | string | Identificador da account. **É essencial que este número seja único para cada account** *(obrigatório)*
account_type | string | Identificador do tipo de account cadastrada no sistema de cadastro de dispositivo. As accounts podem ser do tipo pessoa física `natural_person` ou pessoa jurídica `legal_person` .*(obrigatório)*
registration_date | datetime | Data e hora do registro da account, com fuso horário. *(obrigatório)*
account_data | object | objeto que pode conter quaisquer dados da account, mas se contiver o número da account `account_number` e agência `agency_number` os dois devem ser obrigatoriamente do tipo string.

## Enviar um Account

Request Body

```json
  {
    "account_id": "12345",
    ...
  }
```

Response Body

```json
  {
    "account_id": "12345678",
    "account_type": "natural_person",
    "registration_date": "2019-12-11T11:37:15.12-03:00",
    "account_data": {
      "account_number": "12345678",
      "agency_number": "1234"
      ...
    }
  }
```

Para realizar a criação de uma account, basta enviar um objeto do tipo Account ao seguinte endpoint:

`POST https://api.caas.qitech.app/device_manager/account`

---

# Autenticação

URL: /documentation/caas/device_manager/authentication

> Para autenticar uma chamada, utilize o código a seguir:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> Substitua a API Key 'EXAMPLE-OF-API-KEY' pela sua chave, que deve ser obtida através do nosso time de suporte.

Utilizamos uma API Key para permitir acesso à nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE-OF-API-KEY`

:::info **Atenção**

Você deve substituir EXAMPLE-OF-API-KEY pela sua chave, que deve ser obtida com o nosso time de suporte.
:::

---

# Objeto Device

URL: /documentation/caas/device_manager/device_registration

O registro de um device (dispositivo) com identificação única deve ser realizado por meio do endpoint de Device. Para que o cadastro seja efetivado, é necessária a utilização da Device Scan para que a identificação desse device seja registrada para reconhecimento posterior.

### Dinâmica dos Status - **status**

O status **status** refere-se ao status atual do device. Os seguintes status estão disponíveis:

* registered
* not_registered
* deactivated

### Dinâmica dos Status - **analysis_status**

O status **analysis_status** indica o status da decisão do motor de fraude e possui o seguinte fluxo de estados:

* automatically_approved
* automatically_reproved
* pending

## Definição do Objeto Device

Request Body

```json
{
  "device_id": "12345678",
  "session_id": "12345678",
  "face_recognition_key": "12345678",
  "document_number": "111.111.111-11",
  "mfa_status": "approved",
  "registration_date": "2019-12-11T11:37:15.12-03:00"
}
```

Todas as trocas de informação de um cadastro utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

nome | tipo | descrição
:----: | :----: | ---------
device_id | string | Identificador do device. **É essencial que este número seja único para cada device** *(obrigatório)*
session_id | string | Identificador da sessão na Device Scan. *(obrigatório)*
face_recognition_key | string | Identificador da imagem para biometria facial caso o produto seja contratado como 2FA do cadastro.
document_number | string | Documento do usuário para validação de rosto. Só deve ser enviado caso não tenha sido informado no momento do cadastro do objeto person.
mfa_status | string | Status do MFA do cadastro podendo estar entre os seguintes valores: *approved* *reproved*
registration_date | datetime | A data e hora de início do cadastro, com fuso horário. *(obrigatório)*

:::warning Atenção
 O campo `document_number` é necessário para a validação do rosto na base, então, caso não tenha sido informado no momento do cadastro do usuário, ele é obrigatório. Ele nunca deve ser diferente do cadastrado na person.
:::

## Enviar um Device Registration

Request Body

```json
  {
    "device_id": "12345",
    ...
  }
```

Response Body

```json
  {
    "device_id": "12345",
    "status": "registered",
    "analysis_status": "automatically_approved",
    "reason": "rule_decision_enum",
    "reason_description": "Descrição da regra"
  }
```

Para realizar o registro de um device, basta enviar um objeto do tipo Device ao seguinte endpoint:

`POST https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}/device`

---

# Status HTTP

URL: /documentation/caas/device_manager/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, conforme a RFC 7231 :

Status HTTP | Significado | Descrição
:----------: | :-------: | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Geralmente, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, conforme a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado com a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica a este endpoint.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição. Ao encontrarmos esse erro, nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Indica uma indisponibilidade temporária, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/device_manager/introduction

Bem-vindo à API de Cadastro de Dispositivos da QI Tech! Esta api foi projetada para atender a [Normativa 491 do BACEN](https://www.bcb.gov.br/estabilidadefinanceira/exibenormativo?tipo=Instru%C3%A7%C3%A3o%20Normativa%20BCB&numero=491). Em conjunto com a Device Scan, essa API é capaz de gerar uma identificação única para cada dispositivo.

Esta API administra o processo de identificação de dispositivos, possibilitando que, posteriormente, você possa validar esse mesmo aparelho. Este fluxo é estruturado por meio das entidades a seguir:

* Account - Conta
* Person - Pessoa
* Device - Dispositivo

Você pode utilizar a nossa API para criar e recuperar cadastros de dispositivos por meio de do seguinte serviço:

* **Device Registration** - utilizado para associar um dispositivo a uma pessoa. Por meio desse cadastro, será possível realizar as validações de dispositivo para os demais acessos desta mesma pessoa.

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/device_manager/`
* Sandbox - `https://api.sandbox.caas.qitech.app/device_manager/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.
:::

No ambiente de Sandbox, as análises enviadas não são cobradas e são respondidas conforme a regra configurada para o evento.

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para garantir que, por desatenção ou qualquer outro motivo, não ocorram chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (como um erro de digitação ou uma organização inadequada), envie-nos um e-mail. Assim, nós tornamos a documentação cada vez mais prática para evitar que outros desenvolvedores encontrem as mesmas dificuldades.

---

# Objeto Person

URL: /documentation/caas/device_manager/person

A conta pode ter mais de um usuário a acessando, logo, cada usuário deve ter seu registro para segregar ações em contas conjuntas. As informações citadas abaixo devem seguir os padrões estabelecidos, mas quaisquer campos podem ser adicionados aos dados da conta caso seja necessário.

## Definição do Objeto Person

Request Body

```json
{
  "person_id": "12345678",
  "document_number": "111.111.111-11",
  "registration_date": "2019-12-11T11:37:15.12-03:00",
  "person_data": {
    "name": "Joao da Silva",
    "email": "person@email.com",
    "phone": {
      "number": "999999999",
      "international_dial_code": "55",
      "area_code": "11"
    }
  }
}
```

Todas as trocas de informação de uma pessoa utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

nome | tipo | descrição
:----: | :----: | ---------
person_id | string | Identificador da pessoa. **É essencial que este número seja único para cada pessoa** *(obrigatório)*
document_number | string | número do documento, podendo ser CPF ou CNPJ com pontuação.
registration_date | datetime | Data e hora do registro da pessoa associada à conta, com fuso horário. *(obrigatório)*
person_data | object | objeto que pode conter quaisquer dados da pessoa. Se contiver o nome `name`, email `email`, e telefone `phone` (com seus campos `number`, `international_dial_code` e `area_code`), todos os objetos citados devem ser do tipo string.

## Criar um Person

Request Body

```json
  {
    "person_id": "12345678",
    ...
  }
```

Response Body

```json
  {
    "person_id": "12345678",
    "document_number": "111.111.111-11",
    "registration_date": "2019-12-11T11:37:15.12-03:00",
    "person_data": {
      "name": "Joao da Silva",
      "email": "person@email.com",
      "phone": {
        "number": "999999999",
        "international_dial_code": "55",
        "area_code": "11"
      }
    }
  }
```

Para realizar a criação de uma pessoa, basta enviar um objeto do tipo Person ao seguinte endpoint:

`POST https://api.caas.qitech.app/device_manager/account/{account_id}/person`

---

# Recuperar ou Desativar uma Account, Person ou Device

URL: /documentation/caas/device_manager/query_registration

## Buscar Device específico

A fim de recuperar um Device específico, basta realizar uma requisição GET. O resultado retornado é o JSON mais atualizado do Device em questão. Caso este identificador não esteja relacionado a nenhum objeto, o HTTP Status 404 é retornado.

`GET https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}/device/{device_id}`

```shell
curl "https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}/device/{device_id}"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

## Buscar Lista de Devices

Para recuperar vários devices, basta realizar uma requisição GET. O resultado retornado é o JSON com uma lista de informações básicas de todos os devices de um usuário.

`GET https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}/devices`

```shell
curl "https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}/devices"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

## Desativar Device específico

Para desativar um Device específico, basta realizar uma requisição DELETE. Caso este identificador não esteja relacionado a nenhum objeto, o HTTP Status 404 é retornado. Um device após ser desativado não pode mais ser validado.

`DELETE https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}/device/{device_id}`

```shell
curl -X DELETE "https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}/device/{device_id}" \
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

## Buscar Conta específica

Permite recuperar os dados de uma conta pelo seu identificador. Retorna os detalhes da conta, ou 404 caso não exista.

`GET https://api.caas.qitech.app/device_manager/account/{account_id}`

```shell
curl "https://api.caas.qitech.app/device_manager/account/{account_id}" \
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

## Buscar Pessoa específica

Permite recuperar os dados de uma pessoa específica dentro de uma conta. Retorna os dados atualizados da pessoa, ou 404 caso não exista.

`GET https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}`

```shell
curl "https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}" \
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

---

## Desativar Conta

Realiza a desativação de uma conta. Após desativada, a conta não poderá mais ser utilizada para registro ou validação de devices.

`DELETE https://api.caas.qitech.app/device_manager/account/{account_id}`

```shell
curl -X DELETE "https://api.caas.qitech.app/device_manager/account/{account_id}" \
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

## Desativar Pessoa

Realiza a desativação de uma pessoa dentro de uma conta. Após desativada, a pessoa não poderá mais registrar ou validar devices.

`DELETE https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}`

```shell
curl -X DELETE "https://api.caas.qitech.app/device_manager/account/{account_id}/person/{person_id}" \
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

---

# Padrões

URL: /documentation/caas/device_manager/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões seguidos em toda a API.

## Valores Monetários
> Exemplos:

```
10000
12345
98741
1223
1
0
```

As APIs assumem que todos os valores monetários enviados são em reais brasileiros. Os valores devem ser enviados como números inteiros representando centavos.

## Data e Hora com Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12.232-03:00
2018-05-01T13:32:11.297+00:00
2019-05-01T00:00:00.000+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será valido.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss.sss±hh:mm`

## Data e Hora sem Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12
2018-05-01T13:32:11
2019-05-01T00:00:00
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ss.sssZ`

## Data
> Alguns exemplos

```
2019-10-15
2019-01-01
2017-03-20
```

No caso de campos que recebem somente a data, sem nenhum horário, ela deve ser enviada com o seguinte formato:

`YYYY-MM-dd`

## Documentos
Uma vez que os números de documento são bastante variados e muitos deles possuem caracteres que não se enquadram como numéricos, definem-se todos os números de documento como string. Outro bom motivo para defini-los como string é evitar que os zeros à esquerda desapareçam. Documentos previstos nesta página possuem uma máscara bem definida e estarão sujeitos à validação. O restante dos documentos, como RG, dada sua falta de padronização, não serão validados.

## CPF

> Exemplos de CPFs válidos contra a máscara definida:

```
123.456.789-12
321.987.543-23
111.283.333-00
```

> Exemplos de CPFs inválidos contra a máscara definida:

```
8.577.477-8
08.104.627/0001-23
123.456.789-1
23.456.789-01
```

O CPF é sempre definido como uma string e será validado contra a máscara:

`###.###.###-##`

## CNPJ

> Exemplos de CNPJs válidos contra a máscara definida:

```
08.104.627/0001-02
01.079.210/0114-67
32.402.502/0001-35
```

> Exemplos de CNPJs inválidos contra a máscara definida:

```
8.577.477-8
123.456.789-12
321.987.543-23
32.402.502/0001-3
032.402.502/0001-3
```

O CNPJ é sempre definido como uma string e será validado contra a máscara:

`##.###.###/####-##`

## IP

> Exemplos de IPs válidos contra a máscara definida:

```
201.81.161.86
201.081.161.86
201.81.161.086
201.81.0.1
```

> Exemplos de IPs inválidos:

```
201.81..86
358.81.161.86
201.81.161
```

IPs deverão ser enviados sempre em IPv4, zeros à esquerda poderão ou não ser enviados, respeitando a seguinte máscara:

`###.###.###.###`

---

# Dinâmica dos Status

URL: /documentation/caas/device_manager/status_dynamics

O processo de análise consiste em enviar um evento, como de Device Validation, por exemplo, no endpoint adequado e aguardar a resposta.

Após a QI Tech realizar a análise do evento, ela retornará uma resposta com um status referente à análise. O campo **analysis_status** representa o resultado da análise de evento realizada pela QI Tech.

### **analysis_status**

Conforme descrito anteriormente, a QI Tech possui três **analysis_status** que indicam o status da decisão do motor de análise e possui a seguinte máquina de estados:

analysis_status | Descrição
:---------: | ---------
automatically_approved | Os algoritmos da QI Tech recomendam que este evento seja aprovado.
automatically_reproved | Os algoritmos da QI Tech recomendam que este evento seja reprovado.
pending | As consultas estão demorando mais do que o esperado, este evento entrou em uma fila de análise automática e será respondido assim que possível.

---

# O objeto DeviceScan

URL: /documentation/caas/device_scan/android/device_scan_object

Para utilizar a DeviceScanSDK, é necessário instanciar a classe DeviceScan. Essa instância recebe o currentContext e pode ser configurada com token/sessão, ambiente e callback (notifier).

:::danger Aviso Importante!
A partir da versão 5.0.0, o sistema de autenticação foi atualizado para usar um **token** temporário no lugar do **mobileToken**.
:::

## Versão 5.0.0+

| Parâmetro | Função | Obrigatório |
|------------|--------------|--------------|
|currentContext|Contexto da aplicação, utilizado no acesso a dados necessários. |Sim.|
|token (via .setToken(this.token))| Token de autenticação que identifica que os dados coletados são provenientes do seu aplicativo. O token é obtido por meio de requisição à API da Device Scan. |Sim.|
|sessionId (via .setSessionId(this.sessionId))|Identificador da sessão de onde os dados coletados são provenientes.|Sim.|
|notifier (via .setNotifier(this.deviceScanNotifier))|Instância de DeviceScanNotifier. Atua como callback, retornando a situação do envio (sucesso ou falha). |Não.|
|sandbox (via .setSandboxEnvironment())|Configura a biblioteca para enviar dados ao ambiente `sandbox`. Se não configurado, as requisições são enviadas para `production`. |Não.|

 **Ambiente padrão**: caso `setSandboxEnvironment()` não seja chamado, o envio é feito para `production`. 

## Versões Anteriores (até 4.x)

| Parâmetro | Função | Obrigatório |
|------------|--------------|--------------|
|currentContext|Contexto da aplicação, utilizado no acesso a dados necessários.|Sim.|
|mobileToken (via .setMobileToken(this.mobileToken))|Chave do cliente que identifica que os dados coletados são provenientes do seu aplicativo. Caso ainda não tenha recebido o seu **mobile-token**, entre em contato com o suporte: <a href='mailto:suporte.caas@qitech.com.br'>suporte.caas@qitech.com.br</a>.|Sim.|
|sessionId (via .setSessionId(this.sessionId))|Identificador da sessão de onde os dados coletados são provenientes.|Sim.|
|notifier (via .setNotifier(this.deviceScanNotifier))|Instância de DeviceScanNotifier. Atua como callback, retornando a situação do envio (sucesso ou falha).|Não.|
|sandbox (via .setSandboxEnvironment())|Configura a biblioteca para enviar dados ao ambiente `sandbox`. Se não configurado, as requisições são enviadas para `production`. |Não.|

## Resumo Rápido (Migração)
- 5.0.0+: usar `token` temporário (`setToken(this.token)`)
- < 5.0.0: usar `mobileToken` (`setMobileToken(this.mobileToken)`)
- Em ambas: `currentContext` e `sessionId` são obrigatórios. `notifier` e `sandbox` são opcionais.

---

# Implementação

URL: /documentation/caas/device_scan/android/example

:::danger Aviso Importante!
A partir da versão 5.0.0, o sistema de autenticação foi atualizado para usar um **token** dinâmico em vez de **mobileToken**. Antes de configurar o SDK, você deve gerar um **token** temporário através de uma requisição server-to-server para a nossa API de Device Scan.
:::

```java
package com.example.zaig_device_scan_sdk_test_app;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;

import com.qitech.android.devicescan.DeviceScan;
import com.qitech.android.devicescan.DeviceScanNotifier;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    private DeviceScan deviceScan;
    private DeviceScanNotifier deviceScanNotifier;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        deviceScanNotifier = new DeviceScanNotifier(this);
    }

    public void sendDeviceScan(View view) {
        try{
            deviceScan = new DeviceScan.Builder(this.getApplicationContext())
                .setToken(this.token)
                .setSessionId(this.sessionId)
                .setNotifier(this.deviceScanNotifier)
                .setSandboxEnvironment()
                .build();
        }catch (Exception ex) {
            Log.e("DeviceScan Error", "There was an error collecting DeviceScan data: " + ex.toString());
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
        try{
            deviceScan.collectData(this.documentNumber,
                    this.eventId,
                    this.eventType);
        }catch (Exception ex) {
            Log.e("DeviceScan Error", "There was an error collecting DeviceScan data: " + ex.toString());
        }
    }

    private class ScanNotifier implements DeviceScanNotifier {
        AppCompatActivity activity;
        public ScanNotifier (AppCompatActivity myActivity){
            // Este método é customizável e pode ser utilizado para se armazenar a Activity, utilizada para operar a UI
            this.activity = myActivity;
        }

        public void onSuccess(){
            Log.i("DeviceScan", "DeviceScan successfully submitted");
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // Adicionar aqui quaisquer mudanças de UI que sejam necessárias após o envio com sucesso do device scan
                }
            });
        }

        public void onError(){
            Log.i("DeviceScan", "DeviceScan submission failed");
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // Adicionar aqui quaisquer mudanças de UI que sejam necessárias após o envio com sucesso do device scan
                }
            });
        }
    }
}

```

Para utilizar o SDK do device scan android, os seguintes passos são necessários:

* Inserir as autorizações ao manifest da aplicação;
* Importar a biblioteca ao projeto da aplicação;
* Ao iniciar a aplicação, instanciar a biblioteca, passando os parâmetros adequados em seu construtor, incluindo o Notifier, responsável por dar o CallBack da operação com o resultado;
* Utilizar a função `onRequestPermissionsResult` da Activity para ser notificado do resultado da aprovação ou não das permissões requeridas;
* Requisitar as permissões ao usuário. É obrigatória a permissão de acesso a internet para o funcionamento da biblioteca;
* Ao ser notificado do resultado da aprovação ou não das permissões, colete e envie os dados por meio do método `collectData`.

---

# Soluções híbridas

URL: /documentation/caas/device_scan/android/hybrid_solutions

Além de oferecer integração nativa em Java, nossos SDKs também são compatíveis com diversos frameworks cross-platform. Isso é possível por meio da integração de plugins nativos específicos para cada um desses frameworks. Ao utilizar o sistema nativo de cada solução, é viável incorporar nosso SDK nativo no ambiente Android.

Algumas das tecnologias híbridas mais utilizadas são o React Native ([Native Modules](https://reactnative.dev/docs/turbo-native-modules-introduction)), Cordova ([Plugin Development Guide](https://cordova.apache.org/docs/en/latest/guide/hybrid/plugins/index.html)), Ionic ([Native](https://ionicframework.com/docs/v3/native/)), Unity ([Native Plug-in para Android](https://docs.unity3d.com/Manual/PluginsForAndroid.html)), Xamarin ([Native Libraries](https://learn.microsoft.com/en-us/xamarin/android/platform/native-libraries)), Appcelerator, Phonegap e Node.

Para facilitar o processo de integração com nossas soluções nativas, disponibilizamos plugins para os frameworks React Native e Flutter. Caso tenha interesse, disponibilizamos a documentação e um exemplo de integração em nossos repositórios privados. Para as demais tecnologias, também temos alguns exemplos de implementação dessa ponte com o código nativo. Fique à vontade para entrar em contato com nosso suporte suporte.caas@qitech.com.br para obter acesso.

---

# Coleta de informações

URL: /documentation/caas/device_scan/android/information_gathering

Para disparar a coleta e o envio de informações, é necessário (após obter as permissões do usuário) chamar o método `collectData`. O método, além de capturar as informações do dispositivo, tem como objetivo mapear a jornada do cliente dentro da aplicação. Por esse motivo, o método também aceita os campos `eventId` e `eventType`. O método possui os seguintes parâmetros:

nome | tipo | descrição
---- | ---- | ---------
documentNumber | String | O número do documento do usuário, caso disponível. (CPF/CNPJ sem pontos, traços e barra)
eventId | String | Um identificador do evento que está sendo reportado
eventType | String | Um valor enumerado que define o tipo de evento que está sendo reportado. Recomenda-se cuidado para que eventos muito similares sejam reportados com o mesmo enumerador, a fim de que inteligência possa ser construída sobre esses dados.

Após a chamada de coleta dos dados, um dos dois métodos da instância de `DeviceScanNotifier` passada no construtor da classe `DeviceScan` será chamado: `onSuccess` caso tudo corra conforme o esperado ou `onError`, em caso de erro.

---

# Introdução

URL: /documentation/caas/device_scan/android/introduction

Bem-vindo(a) ao manual de integração do Device Scan Android da QI Tech! Você deve utilizar nosso SDK para coletar informações do dispositivo e do comportamento do usuário no seu aplicativo e, assim, aumentar a assertividade das decisões.

## Problemas?

Não somos uma companhia que se esconde atrás de uma API. Entre em contato com o nosso [suporte](mailto:suporte.caas@qitech.com.br) e responderemos o mais rápido possível. Fique à vontade para nos ligar caso precise de uma resposta mais rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o problema ou que ele seja muito simples (como um erro de digitação ou uma organização inadequada), envie-nos um e-mail. Assim, tornamos a documentação cada vez mais prática, e a próxima pessoa não precisa passar pelas mesmas dores.

## Ambientes

Disponibilizamos dois ambientes para os nossos clientes. A seleção é realizada por meio de um enumerador informado no construtor do SDK. No momento, os seguintes ambientes estão disponíveis:

* Produção - `production`
* Sandbox - `sandbox`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas no ambiente de Sandbox da QI Tech.
:::

---

# Integração nativa

URL: /documentation/caas/device_scan/android/native_java

Para importar nossos SDKs, é necessário realizar alterações nos arquivos build.gradle do projeto e do aplicativo.

## Adicionando ao Projeto
Adicione o endereço do nosso repositório Maven no build.gradle do projeto (no Android Studio, este arquivo aparece como “Project: \{nome_do_projeto\}”), conforme o exemplo abaixo:

```java
buildscript {
    ...
}

allprojects {
    repositories {
        ...
        maven { url 'https://sdks.qitech.com.br/' }
    }
}
```

## Adicionando ao Aplicativo
Em seguida, adicione a biblioteca que você pretende importar no build.gradle do app (no Android Studio, este arquivo aparece como **“Module: \{nome_do_projeto\}.app”**), incluindo a dependência abaixo:

```java
dependencies {
    ...
    implementation 'com.qitech.android:devicescan:v6.0.0'
}
```

:::warning
Desde **abril de 2025**,** novas políticas da Google Play exigem **Android API Level 35** para que aplicativos possam ser publicados ou atualizados na Google Play Store. Por isso, recomendamos fortemente que você utilize **targetSdkVersion 35**, no mínimo.
:::

:::info
A utilização de **targetSdkVersion 35** implica na utilização do **compileSdkVersion 35**, o que acarreta alguns **requisitos mínimos** para ferramentas
do ecossistema do Android:
* compileSdkVersion 35 --> AGP 8.6.0
* AGP 8.6.0 --> Gradle 8.7
* AGP 8.6.0 --> Java 17 (JDK 17)
* AGP 8.6.0 --> Kotlin 2+
:::

## Arquivo Manifest

Para utilizar o SDK, você deve adicionar a seguinte configuração ao AndroidManifest da sua aplicação:

```java
<meta-data
            android:name="com.google.android.gms.ads.AD_MANAGER_APP"
            android:value="true"/>
```

Você também deve adicionar, no mínimo, a permissão de internet, que é utilizada para enviar os dados coletados aos servidores da QI Tech:

` `

A lista de permissões deverá ser ajustada de acordo com a necessidade.

---

# Permissões

URL: /documentation/caas/device_scan/android/permissions

O SDK coleta dados do dispositivo do usuário de acordo com as permissões disponíveis no momento da coleta: quanto mais permissões o seu aplicativo solicitar e o usuário conceder, mais informações poderão ser coletadas.

:::info **Atenção**

A permissão INTERNET é obrigatória para que o SDK consiga enviar as informações aos servidores da QI Tech.
:::

## Permissões utilizadas pelo SDK

Na versão atual do SDK, as permissões abaixo podem ser utilizadas, caso estejam disponíveis:

| Permissão | Função | Obrigatória |
|------------|--------------|--------------|
|INTERNET|Envio das informações aos servidores da QI Tech.| Sim. |
|BLUETOOTH|Captura de informações do hardware de Bluetooth.| Não. |
|BLUETOOTH_CONNECT|Captura de informações de conexão Bluetooth.| Não. |
|READ_CONTACTS|Leitura da agenda de contatos.| Não. |
|ACCESS_COARSE_LOCATION|Acesso a informações de rede (Antena, operadora, etc) e à localização por este meio (menos precisa).| Não. |
|ACCESS_FINE_LOCATION|Acesso à localização por meio de GPS (mais precisa).| Não. |
|READ_PHONE_STATE|Informações de Rede, SIM, Imei e outros aspectos de telefonia.| Não. |
|QUERY_ALL_PACKAGES|Informações de aplicativos instalados no dispositivo. Necessária para devices Android 11 em diante.| Não. |

:::info **Importante**

Nosso SDK não solicita as permissões descritas. Portanto, para garantir um device scan mais completo, recomendamos solicitar e obter essas permissões antes de executar a chamada do device scan.
:::

:::info **Atenção**

A permissão QUERY_ALL_PACKAGES pode gerar atrito com o Google Play no momento do lançamento do app. Para contornar esse ponto, é possível descrever o motivo da solicitação dessa permissão.
:::

---

# Autenticação

URL: /documentation/caas/device_scan/api/authentication

:::danger Aviso Importante!
A partir da versão 5.0.0 dos SDKs de iOS e Android, o sistema de autenticação foi atualizado para usar um token temporário em vez do mobileToken.
:::

Utilizamos uma API Key para permitir o acesso à nossa API. Normalmente, essa chave é enviada por e-mail. Caso você ainda não tenha recebido a sua, envie uma mensagem para suporte.caas@qitech.com.br .

## Token temporário de autenticação

Antes de configurar o SDK, você deve gerar um token temporário por meio de uma requisição server-to-server para a nossa API.

### Gerar token

```bash
curl -X POST "https://d.viewpkg.com/device_scan/token" \
     -H "Authorization: EXAMPLE_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{ "session_id": "unique_session_identifier" }'
```

**Endpoints**

| Ambiente | URL |
|----------|-----|
| Sandbox | https://d.sandbox.viewpkg.com/device_scan/token |
| Produção | https://d.viewpkg.com/device_scan/token |

**Detalhes da Requisição**

| Campo | Tipo | Obrigatório | Descrição|
|-------|------|------------|---------|
| session_id | string | Sim | Identificador único da sessão gerado pelo seu sistema (por exemplo, UUID). |

**Request Body**
```json
{
  "session_id": "unique_session_identifier" 
}
```

**Response Body**

A resposta bem-sucedida conterá o campo `token`.
```json
{
  "token": "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6..."
}
```

:::info Atenção
Substitua `EXAMPLE_API_KEY` pela API Key recebida do suporte.
:::

---

# O objeto QitechDeviceScan

URL: /documentation/caas/device_scan/flutter/device_scan_object

:::danger Aviso Importante!
A partir da versão 1.0.0, o sistema de autenticação foi atualizado para usar um **token** temporário no lugar do **mobileToken**. O token é obtido por meio de requisição server-to-server à API da Device Scan.
:::

## Chamada

Para utilizar o plugin de Device Scan, é necessário realizar a chamada do método `startDeviceScan` que possui os seguintes parâmetros:

## Versão 1.0.0+

| Parâmetro | Tipo | Função | Obrigatório |
|------------|--------------|--------------|--------------|
|token|String|Token de autenticação temporário obtido por meio de requisição à API da Device Scan. Deve ser gerado com o mesmo `sessionId` passado a este método.|Sim.|
|environment|CaaSEnvironment|Enumerador utilizado para configurar o ambiente de execução para `sandbox` ou `production`. |Sim.|
|sessionId|String|Chave que identifica a sessão da qual os dados coletados são provenientes. **Deve ser enviado em letras minúsculas.**|Sim.|
|eventType|String|Um enumerador que define o tipo de evento sendo reportado - É pedido cuidado para que eventos muito similares seja reportados com o mesmo enumerador, a fim de que inteligência possa ser construída sobre esses dados.|Sim.|
|eventId|String|Um identificador do evento sendo reportado|Sim.|
|documentNumber|String?|O número do documento do usuário, caso disponível. (CPF/ CNPJ sem pontos, traços e barra). Pode ser omitido.|Não.|

## Versões Anteriores (até 0.x)

| Parâmetro | Tipo | Função | Obrigatório |
|------------|--------------|--------------|--------------|
|mobileToken|String|Chave do cliente que identifica que os dados coletados são provenientes do seu aplicativo. Caso ainda não tenha recebido o seu mobile-token, entre em contato com o <a href='mailto:suporte.caas@qitech.com.br'>suporte</a>.|Sim.|
|environment|CaaSEnvironment|Enumerador utilizado para configurar o ambiente de execução para `sandbox` ou `production`. |Sim.|
|sessionId|String|Chave que identifica a sessão da qual os dados coletados são provenientes. **Deve ser enviado em letras minúsculas.**|Sim.|
|eventType|String|Um enumerador que define o tipo de evento sendo reportado - É pedido cuidado para que eventos muito similares seja reportados com o mesmo enumerador, a fim de que inteligência possa ser construída sobre esses dados.|Sim.|
|eventId|String|Um identificador do evento sendo reportado|Sim.|
|documentNumber|String?|O número do documento do usuário, caso disponível. (CPF/ CNPJ sem pontos, traços e barra). Pode ser omitido.|Não.|

## Resumo Rápido (Migração)
- 1.0.0+: usar `token` temporário obtido via API (`token: token`)
- '`)
- Em ambas: `environment`, `sessionId`, `eventType` e `eventId` são obrigatórios. `documentNumber` é opcional.

## Retorno

O método retorna uma String para indicar sucesso ou falha durante a coleta das informações:

### Sucesso

```javascript
Success collecting device scan data
```

### Erro

```javascript
Device Scan fail. Check token, environment and permissions
```

---

# Implementação

URL: /documentation/caas/device_scan/flutter/example

## Pré-requisito para startDeviceScan

O método `startDeviceScan` requer um `token`. Este token é temporário e deve ser gerado no seu backend por meio de uma requisição server-to-server para a nossa API antes de chamar o método do SDK.

**Detalhes do Endpoint:**

- **Método:** POST
- **Path:** `/device_scan/token`
- **Sandbox URL:** `https://d.sandbox.viewpkg.com/device_scan/token`
- **Production URL:** `https://d.viewpkg.com/device_scan/token`

**Headers:**

```json
{
  "Authorization": "YOUR_DEVICE_SCAN_API_KEY"
}
```

**Body:**

```json
{
  "session_id": "unique_session_id"
}
```

A resposta bem-sucedida desta API conterá o `token` que você deve repassar ao método `startDeviceScan`.

:::note
O método de device scan pode ser executado de forma assíncrona. Portanto, não é necessário bloquear a thread principal para aguardar a resolução deste método. O usuário pode interagir normalmente com o app enquanto o device scan é processado em segundo plano.
:::

:::note
Recomendamos que o método de device scan seja executado o mais cedo possível. Como ele pode precisar de mais tempo de execução para coletar todos os dados, esta chamada antecipada é recomendada para que as informações mais completas do dispositivo sejam extraídas.
:::

---

```dart

import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:qitech_device_scan/qitech_device_scan.dart';

final _qitechDeviceScanPlugin = QitechDeviceScan();

// Etapa 1: Gerar o token temporário via requisição server-to-server
Future<String?> fetchDeviceScanToken(String sessionId) async {
  final response = await http.post(
    Uri.parse('<DEVICE_SCAN_API_URL>'),
    headers: {
      HttpHeaders.authorizationHeader: '<API_KEY>',
      HttpHeaders.contentTypeHeader: 'application/json',
    },
    body: jsonEncode({'session_id': sessionId}),
  );

  if (response.statusCode == 200) {
    final data = jsonDecode(response.body);
    return data['token'] as String?;
  }
  return null;
}

// Etapa 2: Inicializar o SDK com o token obtido
final sessionId = '<SESSION_ID>';
final token = await fetchDeviceScanToken(sessionId);

if (token == null) {
  print('Failed to fetch device scan token');
  return;
}

final result = await _qitechDeviceScanPlugin.startDeviceScan(
    token: token,
    environment: CaaSEnvironment.sandbox,
    sessionId: sessionId,
    eventType: '<EVENT_TYPE>',
    eventId: '<EVENT_ID>',
);

print('Device Scan result: $result');

```

## Flutter Setup

Para utilizar o plugin do device scan, os seguintes passos são necessários:

### Instalação

Inicialmente, é necessário executar o seguinte comando para instalar o plugin:

```bash
flutter pub add qitech_device_scan
```

O comando deve instalar a versão mais recente, que pode ser verificada em seu arquivo `pubspec.yaml`:

```yaml
dependencies:
  qitech_device_scan: ^1.0.0
```

### Importação

Agora, basta importar o pacote para começar a utilizá-lo:

```dart
import 'package:qitech_device_scan/qitech_device_scan.dart';
```

## Android Setup

Adicionar a referência do repositório android da Qi Tech em seu arquivo `build.gradle`:

```gradle
allprojects {
    repositories {
        maven { url 'https://sdks.qitech.com.br/' }
        ...
    }
}
```

Inicializar o serviço de AdMob ao adiconar o seguinte código em seu `AndroidManifest.xml`:

```xml
<meta-data
    android:name="com.google.android.gms.ads.APPLICATION_ID"
    android:value="<ADMOB_APP_ID>"/>
```

Caso não possua um `ADMOB_APP_ID`, entre em contato com o suporte.caas@qitech.com.br .

## iOS Setup

Adicionar a referência do repositório iOS da Qi Tech em seu arquivo `Podfile`:

```ruby
source 'https://cdn.cocoapods.org/'
source 'https://github.com/QITechSDKs/iOS.git'
```

Instalar as dependências diretamente através do cocoapods:

```bash
cd ios
pod install
```

ou através do flutter:

```bash
flutter build ios
```

---

# Introdução

URL: /documentation/caas/device_scan/flutter/introduction

Bem vindo ao manual de integração da Device Scan da QI Tech em Flutter! Você deve utilizar o nosso Plugin para coletar informações do celular e do comportamento do usuário em seu aplicativo e assim melhorar a assertividade das decisões.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso [suporte](mailto:suporte.caas@qitech.com.br) e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. A seleção é realizada por meio de enumerador repassado no parâmetro da chamada do plugin, no momento, os seguintes ambientes estão disponíveis:

* Produção - `production`
* Sandbox - `sandbox`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

---

# Permissões

URL: /documentation/caas/device_scan/flutter/permissions

O plugin coleta dados do dispositivo do usuário conforme as permissões que estão disponíveis no momento da coleta: conforme mais permissões seu aplicativo requerir e o usuário disponibilizar, mais informações são coletadas do dispositivo do usuário.

:::info **Atenção**

A permissão de INTERNET é obrigatória para que o SDK consiga enviar as informações aos servidores da QI Tech.
:::

## Permissões utilizadas pelo plugin

:::info **Importante**

Nosso plugin não solicita as permissões descritas. Portanto, para garantir um scan de dipositivo mais completo, recomendamos a coleta dessas permissões antes de executar a chamada da device scan.
:::

### Android

Para a plataforma android, as seguintes permissões são utilizadas caso estejam disponíveis:

| Permissão | Função | Obrigatória |
|------------|--------------|--------------|
|INTERNET|Obrigatória, para envio das informações aos servidores da QI Tech.| Sim. |
|BLUETOOTH|Captura de informações do hardware de Bluetooth.| Não. |
|BLUETOOTH_CONNECT|Captura de informações de conexão Bluetooth.| Não. |
|READ_CONTACTS|Leitura da agenda de contatos.| Não. |
|ACCESS_COARSE_LOCATION|Acesso a informações de rede (Antena, operadora...) e à localização por este meio (Menos preciso).| Não. |
|ACCESS_FINE_LOCATION|Acesso à localização por meio de GPS (Mais preciso).| Não. |
|READ_PHONE_STATE|Informações de Rede, SIM, Imei e outros aspectos de telefonia.| Não. |
|QUERY_ALL_PACKAGES|Informações de aplicativos instalados no dispositivo. Necessária para devices Android 11 em diante.| Não. |

:::info **Atenção**

A permissão de QUERY_ALL_PACKAGES pode gerar atrito com o Google Play no momento do lançamento do App. Para solucioná-lo é possível descrever o motivo da solicitação da permissão.
:::

### iOS

Para a plataforma iOS, as seguintes permissões são utilizadas caso estejam disponíveis:

* location - Captura de dados de geolocalização do device

#### Arquivo Info.plist

O primeiro passo para disponibilizar permissões para o plugin é configurar a permissão no arquivo Info.plist da aplicação, utilizando a seguinte linha de código para cada uma das permissões desejadas:

* location - Captura de dados de geolocalização do device:

` NSLocationWhenInUseUsageDescription `
` Adicionar a mensagem que você deseja que apareça para o usuário quando o iOS solicitar a permissão de acesso à geolocalização `

:::info **Atenção**

Para melhorar a experiência do usuário no momento da solicitação das permissões você deve personalizar a mensagem reproduzida no pop-up de solicitação conforme descrito anteriormente.
:::

---

# O objeto QITechIosDeviceScan

URL: /documentation/caas/device_scan/ios/device_scan_object

Para utilizar o DeviceScan iOS da QI Tech, é necessário importar o framework QITechIosDeviceScan e então instanciar a classe QITechIosDeviceScan que possui os seguintes parâmetros no construtor:

:::danger Aviso Importante!
A partir da versão 5.0.0, o sistema de autenticação foi atualizado para usar um **token**  temporário em vez de **mobileToken**.
:::

## Versão 5.0.0+

nome | tipo | descrição
---- | ----- | ------
environment | String | Um enumerador do ambiente onde a aplicação está sendo executada - `sandbox` ou `production` - caso um valor diferente seja enviado, uma exceção será gerada **obrigatório**
token | String | Token de autenticação que identifica que os dados coletados são provenientes do seu aplicativo. Obtida através de requisição à API da Device Scan. **obrigatório**
sessionId | String | O identificador da sessão (**Deve ser o mesmo utilizado para gerar o token**), que será enviado também no momento da avaliação do evento (Transação, Onboarding, por exemplo), para cruzamento entre os dados do device scan e o evento a ser avaliado. **obrigatório**

## Versões Anteriores

nome | tipo | descrição
---- | ----- | ------
environment | String | Um enumerador do ambiente onde a aplicação está sendo executada - `sandbox` ou `production` - caso um valor diferente seja enviado, uma exceção será gerada **obrigatório**
mobileToken | String | A chave de cliente enviada pelo suporte da QI Tech e que identifica que os dados coletados são provenientes do seu aplicativo. Por questões de segurança, caso esta chave esteja incorreta, os servidores da QI Tech recebem mas não processam a chamada. **obrigatório**
sessionId | String | O identificador da sessão, que será enviado também no momento da avaliação do evento (Transação, Onboarding, por exemplo), para cruzamento entre os dados do device scan e o evento a ser avaliado. **obrigatório**

---

# Implementação

URL: /documentation/caas/device_scan/ios/example

:::danger Aviso Importante!
A partir da versão 5.0.0, o sistema de autenticação foi atualizado para usar um **token** dinâmico em vez de **mobileToken**. Antes de configurar o SDK, você deve gerar um **token** temporário através de uma requisição server-to-server para a nossa API de Device Scan.
:::

```swift
import UIKit
import QITechIosDeviceScan

class ViewController: UIViewController {

    var qitechDeviceScan : QITechIosDeviceScan?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.setupDeviceScan()
    }

    func setupDeviceScan() -> Void
    {
        // The environment can be 'sandbox' ou 'production'
        let environment = "sandbox"

        // MobileToken is the key sent to you by QI Tech. Each environment requires a different MobileToken.
        let token = "TEMPORARY_TOKEN_FROM_DEVICE_SCAN_API"

        // You must send the same session id in the moment of using the device scan and event analysis. It must be a key that uniquely identifies each user session in the app
        let sessionId = "62715840-068a-4ded-a4e2-a1ec83f857d4"

        do{
            self.qitechDeviceScan = try QITechIosDeviceScan(environment: environment, token: token, sessionId: sessionId)
        }
        catch{
            print ("Error found when instantiating QITech's DeviceScan")
        }

        let permissions = ["location"]

        do{
            try self.qitechDeviceScan?.requestPermissions(permissions: permissions)
        }
        catch{
            print ("Error found when requesting QITech's DeviceScan's permissions")
        }
    }

    func onSuccess()
    {
        // Do something if QI Tech DeviceScan's collectData method succesfully collected device data
    }

    func onError()
    {
        // Do something if QI Tech DeviceScan's collectData method found any error when collecting device data
    }

    func collectQITechDeviceScanData()
    {
        // If you have your customer's document number (CPF or CNPJ without dots, hyphen or slash), you must sent it to QI Tech
        let documentNumber = "12345678900"

        // EventType must represent with type of interation the user had with your app on the moment that collectData method was called
        let eventType = "login"

        // EventId is your code that identifies the event sent to QI Tech
        let eventId = "7038632032"

        do{
            try self.qitechDeviceScan?.collectData(documentNumber: documentNumber, eventId: eventId, eventType: eventType, onSuccessHandler: self.onSuccess, onErrorHandler: self.onError)
        }
        catch{
            print("Error found when collecting QITech's DeviceScan data")
        }
    }
}
```

Para utilizar o SDK do Device Scan iOS, os seguintes passos são necessários:

Inserir as autorizações no arquivo Info.plist
Adicionar o framework ao projeto do aplicativo
Ao iniciar a aplicação, instanciar a biblioteca, passando os parâmetros adequados
Caso sua aplicação ainda não tenha solicitado as permissões ao usuário, requisitar as permissões ao usuário por meio da função `requestPermissions` do objeto previamente instanciado
Coletar e enviar os dados por meio do método `collectData`

---

# Soluções híbridas

URL: /documentation/caas/device_scan/ios/hybrid_solutions

Além de oferecer integração nativa em Swift, nossas SDKs também são compatíveis com diversos frameworks híbridos. Isso é possível através da integração de plugins nativos específicos para cada um desses frameworks. Utilizando o sistema nativo de cada solução, é viável incorporar nosso SDK nativa no ambiente iOS.

Algumas das tecnologias híbridas mais utilizadas são o React Native ([Native Modules](https://reactnative.dev/docs/turbo-native-modules-introduction)), Cordova ([Plugin Development Guide](https://cordova.apache.org/docs/en/latest/guide/hybrid/plugins/index.html)), Ionic ([Native](https://ionicframework.com/docs/v3/native/)), Unity ([Native Plug-in para Android](https://docs.unity3d.com/Manual/PluginsForAndroid.html)), Xamarin ([Native Libraries](https://learn.microsoft.com/en-us/xamarin/android/platform/native-libraries)), Appcelerator, Phonegap e Node.

Para facilitar o processo de integração com nossas soluções nativas, disponibilizamos plugins para os frameworks React Native e Flutter. Caso tenha interesse, provemos a documentação e um exemplo de integração em nossos repositórios privados. Para as demais tecnologias híbridas, temos alguns exemplos de implementação dessa ponte para o código nativo. Fique à vontade para entrar em contato com nosso suporte para obter acesso.

---

# Coleta de informações

URL: /documentation/caas/device_scan/ios/information_gathering

Para disparar a coleta e o envio de informações, é necessário chamar o método `collectData`. O método, além de capturar as informações do dispositivo, tem como objetivo mapear a jornada do cliente dentro da aplicação. É por esta razão que o método também aceita os campos `eventId` e `eventType`. Outro ponto importante é que o método envia as informações para o servidor da QI Tech via request http assíncrono, e para isso, a notificação de sucesso ou erro da requisição é feita através de Completion Handlers. O método possui os seguintes parâmetros:

nome | tipo | descrição
---- | ---- | ---------
documentNumber | String | O número do documento do usuário, caso disponível. (CPF/ CNPJ sem pontos, traços e barra)
eventId | String | Um identificador do evento sendo reportado
eventType | String | Um enumerador que define o tipo de evento sendo reportado (Exemplo: 'login') - Cuidado para que eventos muito similares sejam reportados com o mesmo enumerador, a fim de que inteligência possa ser construída sobre esses dados
onSuccessHandler | func() &#8209;> Void | Função que será chamada no caso de sucesso no envio dos dados para o servidor da QI Tech **obrigatório**
onErrorHandler | func() &#8209;> Void | Função que será chamada no caso de erro no envio dos dados para o servidor da QI Tech **obrigatório**

---

# Introdução

URL: /documentation/caas/device_scan/ios/introduction

Bem vindo ao manual de integração do Device Scan iOS da QI Tech! Você deve utilizar o nosso Framework para coletar informações do celular e do comportamento do usuário em seu aplicativo e assim melhorar a assertividade das decisões.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso [suporte](mailto:suporte.caas@qitech.com.br) e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. A seleção é realizada por meio de enumerador repassado no construtor da classe QITechIosDeviceScan, no momento, os seguintes ambientes estão disponíveis:

* Produção - `production`
* Sandbox - `sandbox`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

---

# Integração nativa

URL: /documentation/caas/device_scan/ios/native_swift

## Remotamente

> Iniciando a instalação

```shell
  pod init
```

Nosso SDK pode ser importado utilizando CocoaPods.

SDK | Versão atual
---- | -----
QITechIosDeviceScan | `pod 'QITechIosDeviceScan', '~> 6.0.0'`

:::info iOS Minimum Deployment Target
15.5
:::

Para iniciar a instalação, execute o comando ao lado na pasta raiz do seu projeto.

> Adicionando a source na podfile

```ruby
   source 'https://github.com/QITechSDKs/iOS.git'
```

O próximo passo é adicionar no arquivo `podfile` o source da QI Tech.

> Adicionando o pod na podfile

```ruby
  pod 'QITechIosDeviceScan', '~> <version>'
```
Por fim, basta adicionar o nome do `pod` de acordo com o formato acima.

:::danger Atenção: 
Mudança de Arquitetura (v5.0.0+) A partir da versão 5.0.0, o SDK passou a ser distribuída exclusivamente de forma estática. No seu Podfile, você deve utilizar a configuração :linkage => :static. 
:::

> Exemplo de podfile (Versão 5.0.0 ou superior)

```ruby
  source 'https://github.com/QITechSDKs/iOS.git'
  target 'ExampleApp' do
    use_frameworks! :linkage => :static
    pod 'QITechIosDeviceScan', '~> 6.0.0'
  end

  post_install do |installer|
    installer.pods_project.targets.each do |target|
      if ['DatadogCore', 'DatadogInternal', 'DatadogCrashReporting', 'DatadogLogs'].include?(target.name)
        target.build_configurations.each do |config|
          config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'
          config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
        end
      end
    end
  end
```

> Exemplo de podfile (Versões Anteriores)

```ruby
  source 'https://github.com/QITechSDKs/iOS.git'
  target 'ExampleApp' do
    use_frameworks!
    pod 'QITechIosDeviceScan', '~> 2.0.0'
  end

  post_install do |installer|
    installer.pods_project.targets.each do |target|
      if ['DatadogCore', 'DatadogInternal', 'DatadogCrashReporting', 'DatadogLogs'].include?(target.name)
        target.build_configurations.each do |config|
          config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'
          config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
        end
      end
    end
  end
```

:::info **Atenção**

É necessário habilitar a estabilidade do módulo para a dependência de monitoramento 'Datadog'. Para evitar possíveis problemas de compilação para diferentes versões do swift. Portanto, adicione o bloco descrito no post_install do seu arquivo Podfile (ou inclua-o no bloco post_install existente, caso já tenha um)
:::

:::warning Atenção
Ao integrar dependências no iOS, pode surgir a necessidade de usar linkagem estática para algumas bibliotecas e dinâmica para outras. Essa configuração é relevante para garantir compatibilidade, evitar erros de build e otimizar o desempenho do projeto. 
:::

### Linkagem Híbrida de Dependências (caso necessário)
A necessidade de linkagem híbrida surge porque algumas bibliotecas têm requisitos específicos, sendo que algumas precisam de linkagem estática para evitar conflitos internos e duplicação de símbolos e outras dependências podem precisar linkagem dinâmica, pois são projetadas para modularidade e compartilhamento entre projetos.

Diferenças Entre Linkagem Estática e Dinâmica
* Estática (static_framework): O código da biblioteca é incorporado diretamente no binário final, reduzindo o tempo de carregamento em runtime e eliminando dependências externas durante a execução.
* Dinâmica (dynamic_framework): A biblioteca é carregada em tempo de execução como um arquivo separado. Isso reduz o tamanho do binário final e facilita atualizações/modificações independentes.

> Configurando linkagem híbrida no Podfile

```ruby
...

use_frameworks! :linkage => :dynamic # CONFIGURANDO O MODO PADRÃO DE LINKAGEM PARA DINÂMICO

...

static_frameworks = ['framework_1', 'framework_2', ...] # INCLUIR TODAS AS DEPENDÊNCIAS QUE PRECISAM SER LINKADAS DE MODO ESTÁTICO
pre_install do |installer|
  installer.pod_targets.each do |pod|
    if static_frameworks.include?(pod.name)
      def pod.static_framework?;
        true
      end
      def pod.build_type;
        Pod::BuildType.static_framework
      end
    end
  end
end
```

> Instalando as dependencias

```shell
  pod install
```

Por fim, execute o comando `pod install` para baixar e instalar as dependências.

---

# Permissões

URL: /documentation/caas/device_scan/ios/permissions

A SDK coleta dados do dispositivo e, de acordo com o funcionamento do sistema operacional iOS, necessita de permissões específicas para cada dado a ser coletado. De maneira a oferecer uma experiência customizada para os usuários da aplicação que possua o SDK embarcado, implementamos um mecanismo que utiliza os parâmetros passados pelo desenvolvedor para solicitar as permissões ao usuário, seguindo a seguinte mecânica:

As permissões que forem enviadas como parâmetro do método `requestPermissions`, no formato de String, são solicitadas ao usuário - a menos que já tenham sido solicitadas anteriormente.
O usuário, por meio de uma caixa de diálogo disponibilizada pelo próprio sistema operacional, é questionado sobre as permissões consideradas necessárias pelo framework.
As permissões são então concedidas ou negadas e, no momento que o método `collectData`, este coletará apenas os dados cuja permissão foi concedida.

:::info **Atenção**

Caso seu aplicativo já tenha solicitado as permissões necessárias, não é necessário chamar novamente o método `requestPermissions`, o SDK irá herdar as permissões solicitadas pelo aplicativo.
:::

## Permissões utilizadas pelo SDK

Na versão atual do SDK, as seguintes permissões são utilizadas caso estejam disponíveis:

* location - Captura de dados de geolocalização do device

## Arquivo Info.plist

O primeiro passo para disponibilizar permissões para o SDK é configurar a permissão no arquivo Info.plist da aplicação, utilizando a seguinte linha de código para cada uma das permissões desejadas:

* location - Captura de dados de geolocalização do device:

` NSLocationWhenInUseUsageDescription `
` Adicionar a mensagem que você deseja que apareça para o usuário quando o iOS solicitar a permissão de acesso à geolocalização `

:::info **Atenção**

Para melhorar a experiência do usuário no momento da solicitação das permissões você deve personalizar a mensagem reproduzida no pop-up de solicitação conforme descrito anteriormente.
:::

---

# Desktop Device Scan

URL: /documentation/caas/device_scan/web/desktop

Este é o **Desktop Device Scan**, nosso módulo *white label* complementar à **Web Device Scan**. Você pode utilizar nosso programa para coletar informações profundas do dispositivo, além de identificar a presença de softwares maliciosos!

Este software foi desenvolvido para atender à [Instrução Normativa BCB nº 491](https://www.bcb.gov.br/estabilidadefinanceira/exibenormativo?tipo=Instru%C3%A7%C3%A3o%20Normativa%20BCB&numero=491). Ele, em conjunto com a Web Device Scan, é capaz de gerar uma **identificação única e confiável** para cada dispositivo!

:::warning Atenção
Nosso aplicativo é *White Label*! Você pode utilizar seus próprios logotipos no instalador, além de personalizar o nome do executável e as mensagens exibidas, deixando a experiência mais amigável para o seu usuário.
:::

## Utilização

Neste passo a passo, você encontrará detalhes sobre a utilização do programa em conjunto com a biblioteca, bem como um exemplo de implementação em JavaScript. Com isso, você terá as ferramentas necessárias para adaptar a solução ao seu caso de uso.

```html
<html>
<head>
    <script src="https://ds.viewpkg.com/device-scan-2-1-1.js"></script>
</head>

<script>
    var deviceScan = new vPkg.DeviceScan('web_token', 'session_id')
    deviceScan.setSandbox()
    deviceScan.setDesktop(true)
    deviceScan.info('event_type', 'event_id')
        .then((res) => console.log(res))
        .catch((error) => console.log(error))
</script>
</html>
```

Ao utilizar a flag `deviceScan.setDesktop(true)`, o SDK web tentará identificar a presença do aplicativo instalado. Caso ele não esteja instalado ou apresente problemas, você poderá receber um dos seguintes erros:

| Erro                        | Descrição                                                                                                                                                                                         |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Timeout in Secure App**   | O aplicativo está presente, mas não está respondendo corretamente. Reinstale o aplicativo para corrigir o problema.                                                                               |
| **Invalid desktop data**    | O aplicativo foi modificado ou corrompido. Reinstale o aplicativo para restaurar a integridade.                                                                                                   |
| **Desktop App Not Present** | O aplicativo não está instalado. Ofereça o link de download fornecido pela QI Tech ao usuário.                                                                                                    |
| **Unexpected App Error**    | Um erro inesperado ocorreu na comunicação com o aplicativo. Se o problema persistir após a reinstalação, entre em contato com o suporte: <a href='mailto:suporte.caas@qitech.com.br'>suporte</a>. |

## Sistemas Operacionais Suportados

O **Desktop Device Scan** está disponível para os principais sistemas operacionais modernos, oferecendo compatibilidade nativa e desempenho otimizado em cada plataforma.

Windows 10/11 x64
macOS Intel (x86_64)
macOS Apple Silicon (M1/M2/M3)

---

# O objeto DeviceScan

URL: /documentation/caas/device_scan/web/device_scan_object

Para utilizar serviço de scan de dispositivo, é necessário instanciar a classe DeviceScan que possui os seguintes parâmetros no construtor:

| Parâmetro | Função | Obrigatório |
|------------|--------------|--------------|
|.setSandbox()|Caso este parâmetro seja utilizado no construtor, a biblioteca será configurada para enviar os dados ao ambiente de `sandbox`. Caso ausente, as requisições são enviadas para o ambiente `production`. |Não.|
|.setGeoLocation(true)|Caso este parâmetro seja definido como `true`, a biblioteca irá solicitar a permissão de coleta dos dados de GPS. Caso ausente ou definido como `false`, as informações de geo localização não são extraídas.|Não.|

:::info **Atenção**
Se o usuário negar o acesso aos dados de localização, a biblioteca será executada normalmente, mas sem coletar essas informações.
:::

## A função deviceScan.info()

Para executar a função de análise de dados do seu usuário, é necessário enviar os seguintes parâmetros para a biblioteca que identificarão sua empresa e a sessão de usuário a qual as informações pertencem. Além disso, os argumentos event_id e event_type, apesar de serem opcionais, nos auxiliam a indenfiticar o padrão de navegação do usuário em sua página, e com isso, evitar ainda mais fraudes.

Abaixo temos o detalhamento de cada um dos argumentos:

Nome | Tipo | Descrição
---- | ---- | ---------
web_token | String | Chave do cliente que identifica que os dados coletados são provenientes do seu aplicativo. Caso ainda não tenha recebido o seu web-token, entre em contato com o suporte . **obrigatório**
session_id | String | Chave que identifica a sessão da qual os dados coletados são provenientes. **obrigatório**
event_id | String | Um identificador do evento sendo reportado
event_type | String | Um enumerador que define o tipo de evento sendo reportado - É pedido cuidado para que eventos muito similares seja reportados com o mesmo enumerador, a fim de que inteligência possa ser construída sobre esses dados.

## Exemplo de Implementação
Um exemplo simples de implementação pode ser visto abaixo:

```html
   html>
    <head>
        <script src="https://ds.viewpkg.com/device-scan-2-1-1.js"></script>
    </head>

    <script>
        var deviceScan = new vPkg.DeviceScan('web_token', 'session_id')
        deviceScan.setSandbox()
        deviceScan.setGeoLocation(true)
        async function callDeviceScan(eventType, eventId) {
            await deviceScan.info(eventType, eventId)
            .then((res) => console.log(res))
            .catch((error) => console.log(error))
        }
    </script>

    <body>
        <input id="login" type="button" value="login" onclick="callDeviceScan('login', '1');" />
        <input id="buy" type="button" value="buy" onclick="callDeviceScan('buy', '2');" />
    </body> 
</html>
```

No exemplo acima, foi criada uma função de suporte **callDeviceScan** para poder atribuir o uso do Device Scan ao clique de um botão e a função de coleta de dados pode ser chamada duas vezes:

* A primeira quando o usuário pressionar o botão de login, e as características e comportamentos do usuário até este evento serão enviadas para os servidores da QI Tech com os identificadores web_token, session_id, event_type ("login") e event_id ("1").

* A segunda quando o usuário pressionar o botão de compra, coletando os comportamentos do usuário utilizando os mesmos identificadores web_token (referente a sua empresa) e session_id (referente a sessão do seu usuário) mas um event_type ("buy") e event_id("2") distintos, indicando que um evento diferente do anterior foi realizado neste passo, mapeando assim toda a jornada do usuário pelo seu website.

---

# Implementação

URL: /documentation/caas/device_scan/web/example

```html
   <html>
    <head>
        <script src="https://ds.viewpkg.com/device-scan-2-1-1.js"></script>
    </head>

    <script>
        var deviceScan = new vPkg.DeviceScan('web_token', 'session_id')
        deviceScan.setSandbox()
        deviceScan.setGeoLocation(true)
        deviceScan.info('event_type', 'event_id')
            .then((res) => console.log(res))
            .catch((error) => console.log(error))
    </script>
   </html>
```

A biblioteca realiza uma análise do usuário através de uma chamada da função **.info()**, que pertence a classe **DeviceScan**, que está contida em nossa biblioteca **vPkg**, conforme o exemplo acima. As variávies 'web_token', 'session_id', 'event_type' (**opcional**) e 'event_id' (**opcional**) devem ser substituídas pelos **seus respectivos valores reais**. Em caso de sucesso a biblioteca irá retornar uma String indicando o sucesso da coleta, e em caso de falha irá retornar uma String indicando o tipo do erro.

---

# Importando a biblioteca

URL: /documentation/caas/device_scan/web/import

Para importar a nossa biblioteca, adicione a URL em uma TAG **src** no HTML de seu website:

```html
    <script src = "https://ds.viewpkg.com/device-scan-2-1-1.js"></script>
```

---

# Coletando os Retornos

URL: /documentation/caas/device_scan/web/information_gathering

A Web Device Scan SDK devolve uma _Promise_, que irá retornar uma **String** indicando a finalização do fluxo para os casos de sucesso. 
Já em casos de erro, irá retornar uma **String** com a descrição do erro. Abaixo está um exemplo de como mapear cada um desses casos e pegar seus resultados:

```html
    <script>
        var deviceScan = new vPkg.DeviceScan('web_token', 'session_id')
        deviceScan.setSandbox()
        deviceScan.setGeoLocation(true)
        deviceScan.info('event_type', 'event_id')
            .then((res) => console.log(res))
            .catch((error) => console.log(error))
    </script>
```

### Retorno de Sucesso

Retorno | Descrição
--------- | ---------
Device Scan Successfully Sent | O escaneamento do dispositivo foi realizado com sucesso, assim como o envio das informações extraídas.

### Retorno de Erro

Erro | Descrição
--------- | ---------
Web Token Error | Web Token utilizado é inválido. Caso tenha certeza que esteja utilizando corretamente o Web Token que foi provido pela QI Tech, entre em contato com nosso suporte (suporte.caas@qitech.com.br) imediatamente.
Invalid Request | Informações do dispositivo não foram coletadas da maneira correta.
Internal Server Error | Ocorreu um erro inesperado, checar conexão com internet.

---

# Introdução

URL: /documentation/caas/device_scan/web/introduction

Bem vindo ao manual de integração do Web Device Scan da QI Tech! Você pode utilizar a nossa biblioteca para coletar informações do dispositivo, do navegador e do comportamento do usuário em seu website e assim melhorar a assertividade das decisões.

Neste passo a passo você encontrará detalhes da biblioteca bem como um exemplo de implementação em javascript. Com isso você possui as ferramentas para poder adequar ao caso de uso da sua aplicação.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. A seleção é realizada por meio de enumerador repassado no construtor do SDK, no momento, os seguintes ambientes estão disponíveis:

* Produção - `production`
* Sandbox - `sandbox`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

---

# Enviando um documento

URL: /documentation/caas/document_analysis/document_submission

## **Enviando um Documento para uma análise padrão**

Para iniciar a análise de um documento, envie uma requisição POST para o endpoint `/document` utilizando o formato `multipart/form-data`.

Endpoint: `https://api.caas.qitech.app/document_analysis/document`

**Formato da Requisição**

A requisição deve ser enviada como `multipart/form-data` e incluir campos de dados e um campo de arquivo. Os campos obrigatórios para uma análise são `id`, `document_analysis_type`, `document_bytes`.

Exemplo de requisição:

``` bash
curl -X POST "https://api.caas.qitech.app/document_analysis/document" \
-H "Authorization: SUA_CHAVE_API" \
-H "Content-Type: multipart/form-data" \
-F "id=solicitacao-abc-12345" \
-F "document_analysis_type=proof_of_address" \
-F "document_bytes=@/caminho/para/seu/comprovante.pdf"
```

## **Descrição dos Atributos de Envio**

| **Atributo** | **Descrição** |
| --- | --- |
| id (obrigatório)| Um identificador único para a requisição, fornecido por você. Este ID pode ser usado posteriormente para recuperar os resultados da análise. |
| document_analysis_type (obrigatório)| Uma string que especifica o tipo de análise a ser realizada no documento. Veja a tabela abaixo para os tipos suportados. |
| document_bytes (obrigatório)| O arquivo do documento a ser analisado. Deve ser enviado como um arquivo no corpo da requisição multipart. Atenção: Não envie este campo como uma string codificada em base64.|
| async (opcional, default=false)| Um booleano (true ou false) que define o modo de processamento. <br/>- false (síncrono): A API tentará processar o documento e retornar o resultado na mesma requisição. <br/>- true (assíncrono): A API confirmará o recebimento e processará em segundo plano. O resultado será enviado via webhook para um url configurado previamente (veja mais na sessão sobre webhooks). |

:::info **Atenção**

O campo async deve ser utilizado para indicar uma requisição assíncrona. As requisições síncronas devem ser feitas apenas para documentos pequenos e análises rápidas em que uma resposta imediata é crucial. Caso uma requisição demore mais de 30 segundos ela será automaticamente redirecionada para uma fila, o status de retorno será `202 Accepted` e o resultado da análise será enviado para o url de webhook previamente configurado (veja mais na sessão sobre webhooks).
:::

## **Tipos de Análise Suportadas**

O campo `document_analysis_type` determina qual modelo de extração de dados será aplicado ao seu documento. Abaixo estão os tipos atualmente suportados.

| **Tipo de Análise** | Tipo de Documento | **Descrição** |
| --- | --- | --- |
| company_statute_default | Contrato/Estatuto Social | Realiza a extração e validação básica de contratos sociais. Extrai informações gerais da empresa e dos sócios. |
| company_statute_credit_assignment | Contrato/Estatuto Social | Realiza a extração avançada de contratos sociais, incluindo a validação de poderes para assinatura de contratos de cessão de crédito. |
| proof_of_address_default | Comprovantes de Residência (contas de luz, gás, internet, cartas do governo, declarações, entre outros) | Extrai e valida informações de comprovantes de residência, como CEP, endereço completo, nome e data. |
| invoice | Notas fiscais, DANFEs. | Extrai informações chave de notas fiscais, incluindo detalhes do fornecedor/cliente, totais e itens. |
| bankslip | Boletos Bancários | Extrai informações de boletos bancários, como o beneficiário, o valor e a data de vencimento. |
| ccb_default | Cédulas de Crédito Bancárias (CCBs) | Extrai dados de Cédulas de Crédito Bancárias. |

Para tipos de análise não listados aqui, entre em contato com nossa equipe de suporte em `suporte.caas@qitech.com.br` para consultar sobre implementações personalizadas.

## **Respostas**

### Resposta de Sucesso (`200 OK`)

Se o documento em uma análise síncrona for processado com sucesso, a API retornará um status `HTTP 200 OK` e um objeto JSON contendo os dados extraídos. A estrutura deste objeto JSON irá variar dependendo do `document_analysis_type` solicitado. Se a requisição tiver um `timeout` a API retornará um status `HTTP 202 Accepted` e a requisição será processada de maneira assíncrona. Depois de alguns instantes é possível recuperar a análise do documento usando uma requisição GET, conforme descrito abaixo .

### Resposta de Aceito (`202 OK`)

Se o documento for processado de forma assíncrona, a API retornará um status `HTTP 202 Accepted` e a requisição será processada de maneira assíncrona. Depois de alguns instantes é possível recuperar a análise do documento usando uma requisição GET, conforme descrito abaixo .

## **Resposta de Erro (`4xx`)**

Se houver um problema com a requisição ou com o documento, a API retornará um código de status `4xx` com um corpo JSON descrevendo o erro.

## Referência de Códigos de Erro

As tabelas a seguir listam todos os códigos de erro possíveis retornados pela API. Você pode usar esses códigos para implementar um tratamento de erros robusto em sua aplicação.

### **Categoria 1: Erros de Requisição (DOC001xx)**

| Código | Título | Descrição |
| --- | --- | --- |
| `DOC00100` | Missing required field | A requisição não contém um campo obrigatório no corpo `multipart/form-data`. |
| `DOC00101` | Invalid field length | O comprimento de um valor em um campo `form-data` é inválido. |
| `DOC00102` | Invalid content type at request | O cabeçalho `Content-Type` da requisição não é `multipart/form-data`. |
| `DOC00103` | Invalid field at request | A requisição contém um campo inesperado ou inválido no corpo `form-data`. |

### **Categoria 2: Erros no Processamento do Arquivo (DOC002xx)**

Estes erros ocorrem quando o próprio arquivo enviado possui problemas que impedem seu processamento.

| Código | Título | Descrição |
| --- | --- | --- |
| `DOC00200` | Invalid Document Analysis Type | O `document_analysis_type` não é válido para o documento enviado. (ex: uma análise `company_statute_default` apartir de uma conta de luz.) |
| `DOC00201` | Invalid File Size | O tamanho do documento enviado excede o limite máximo permitido. |
| `DOC00202` | Invalid File Type | O arquivo não pôde ser processado devido a inconsistências em seu tipo ou formato (ex: um arquivo `.jpg` foi enviado com o tipo `application/pdf`). |
| `DOC00203` | PDF exceeds page limit | O arquivo PDF fornecido contém mais páginas do que o limite máximo permitido para processamento (o limite atual é de 200 páginas). |

### **Categoria 3: Erros na Análise do Documento (DOC003xx)**

Estes erros ocorrem durante a fase de extração e análise de dados, após o arquivo ter sido aberto com sucesso.

| Código | Título | Descrição |
| --- | --- | --- |
| `DOC00300` | Missing Information | O documento não contém informações essenciais necessárias para que a análise seja concluída. |
| `DOC00301` | Bad Quality | A qualidade do documento (ex: resolução, legibilidade, nitidez) é muito baixa para ser analisada com precisão. |
| `DOC00302` | Invalid Data | O documento contém dados inconsistentes ou inválidos (ex: checksums incorretos, campos contraditórios). |
| `DOC00303` | Incorrect Document Type | O conteúdo do documento não corresponde ao tipo de documento esperado para o `document_analysis_type` selecionado. |
| `DOC00304` | Invalid PDF File | O arquivo fornecido não é um PDF válido ou bem-formado e não pôde ser aberto. |
| `DOC00305` | Password Protected PDF | O PDF enviado está criptografado com uma senha e não pode ser processado. |
| `DOC00306` | Parsing Error | A análise do documento não pôde ser processada. |

# **Recuperar a Análise de um documento**

Você pode recuperar os resultados de uma análise de documento enviada anteriormente a qualquer momento, usando seu `id` exclusivo.

`https://api.caas.qitech.app/document_analysis/document/{document_id}` 

Substitua document_id pelo mesmo valor que você usou para fazer a requisição `POST`.

---

# Status HTTP

URL: /documentation/caas/document_analysis/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro. Nesta API implementamos uma série de códigos de erro específicos para ajudar a entender o que pode estar errado.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado (POST, GET, PUT, ...) não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id do documento enviado corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor, ou requisições e dois documentos com o mesmo id.
500 | Internal Server Error | Tivemos um problema para processar esta requisição. Quando este erro acontece nosso time é automaticamente notificado e inicia a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/document_analysis/introduction

Bem vindo à API de Análise de Documentos da QI Tech. Está API foi especialmente feita para analisar documentos complexos que não seguem um formato padrão, como comprovantes de residencia, contratos, notas fiscais, CCBs, boletos e outros.

## **Suporte e Feedback**

Caso encontre qualquer problema técnico ou necessite de assistência, entre em contato com nossa equipe de suporte através do e-mail suporte.caas@qitech.com.br. Estamos comprometidos em fornecer uma resposta em tempo hábil.

## **Adoramos Feedback**

Valorizamos muito o feedback de nossos clientes! Se identificar quaisquer imprecisões, seções pouco claras ou tiver sugestões de melhoria, encorajamos que as compartilhe com nossa equipe. Sua contribuição nos ajuda a aprimorar a experiência de todos os usuários!

## **Ambientes**

A API está disponível em dois ambientes distintos para uso dos clientes. As URLs base para as APIs são as seguintes:

- Produção - `https://api.caas.qitech.app/document_analysis/`
- Sandbox - `https://api.sandbox.caas.qitech.app/document_analysis/`

**Aviso Importante!**

O uso de dados reais de pessoas físicas e/ou jurídicas é estritamente proibido no ambiente de Sandbox da QI Tech.

## **Somente HTTPS**

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para garantir a conformidade e prevenir a transmissão insegura de dados, o servidor está configurado para aceitar exclusivamente conexões na porta 443 com o protocolo TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente rejeitadas.

## **Autenticação**

O acesso à API é concedido através do uso de uma Chave de API (API Key). A sua chave de acesso foi ou será enviada para o seu e-mail. Caso ainda não a tenha recebido, por favor, entre em contato com nossa equipe de suporte em suporte.caas@qitech.com.br.

A API espera que a chave seja incluída no cabeçalho (header) `Authorization` de cada requisição enviada ao servidor.

**Exemplo de Requisição:**

```bash
# A flag -H adiciona o cabeçalho de autorização necessário à requisição.
curl "endpoint_da_api_aqui" \
  -H "Authorization: EXAMPLE_API_KEY"
```

:::info **Atenção**

Você deve substituir EXAMPLE-OF-API-KEY com a API Key recebida do suporte.
:::

---

# Webhook

URL: /documentation/caas/document_analysis/webhook

Webhook

Quando uma análise assíncrona é finalizada, um webhook é enviado com o resultado da análise. Para isso, é necessário configurar um endereço onde vamos notificar as atualizações e também uma *signature_key* que será utilizada para assinar a requisição. Caso ainda não tenha um webhook configurado, fale com a equipe de [suporte](mailto:suporte.caas@qitech.com.br).

## Assinatura do Webhook

## Requisição

A requisição possui o formato abaixo e notifica que a análise foi finalizada. A requisição utiliza o método HTTP POST e o corpo da requisição é enviado como texto codificado em UTF-8.

### Webhook de Sucesso

```bash
curl --location 'YOUR-ENDPOINT-HERE' \
--header 'Signature: CALCULATED-HASH-HMAC' \
--data '{"id": "e314ffci-14f3-41a1-ad5d-c9c18782jhfe", "document": {"analysis_result": {...},  "validation_status": "valid"}, "status": "successful", "status_reason": "", "status_description": "Sucessfull Analysis"}'
```

### Webhook de Erro 
```bash
curl --location 'YOUR-ENDPOINT-HERE' \
--header 'Signature: CALCULATED-HASH-HMAC' \
--data '{"id": "e314ffci-14f3-41a1-ad5d-c9c18782jhfe", "status": "bad_request", "status_reason": "missing_information
", "status_description": "The document is missing required information."}'
```

---

# Coletando os Resultados

URL: /documentation/caas/face_recognition/android/collecting_response

Para obter o objeto **FaceReconResponse**, que contém os resultados das capturas obtidas pelo SDK, incluindo os identificadores das imagens enviadas no sistema QI Tech, sobrescreva o método *onActivityResult* na mesma activity que você iniciou a **FaceReconActivity**:

```java
@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE) {
            if (resultCode == RESULT_OK && data != null) {
                faceReconResponse = data.getParcelableExtra("FaceReconResponse");
                image_key = faceReconResponse.image_key;
                device_scan_session_id = faceReconResponse.device_scan_session_id;
                Log.i(TAG_LIVENESS, "FACE RECON RESPONSE: " + faceReconResponse.image_key);
            }
            else if (resultCode == RESULT_CANCELED && data != null) {
                faceReconResponse = data.getParcelableExtra("FaceReconResponse");
                Log.i(TAG_LIVENESS, "FACE RECON RESPONSE: " + faceReconResponse.status_code + " - " + faceReconResponse.reason + " - " + faceReconResponse.description);
            }
        }
    }
```

## Descrição dos Atributos do Objeto FaceReconResponse

:::info Aviso: 
Integração com Device Scan A partir da versão 5.2.0, o serviço de Face Recognition passa a realizar automaticamente uma chamada interna ao Device Scan. Com isso, o retorno de sucesso incluirá o campo `device_scan_session_id`. Esta chave identifica a sessão de scan de dispositivo realizada internamente e pode ser utilizada de forma integrada em outros serviços do ecossistema QI Tech. 
:::

Atributo | Descrição | Resultado | Versões
--------- | --------- | --------- | ---------
image_key | Chave de identificação da imagem fornecida que pode ser utilizada em qualquer outro serviço do sistema QI Tech. | **RESULT_OK** | **Todas**
device_scan_session_id | Chave de identificação da sessão de scan de dispositivo realizada internamente que pode ser utilizada em qualquer outro serviço do sistema QI Tech. | **RESULT_OK** |  **5.2.0+**
status_code | Status code da requisição. | **RESULT_CANCELED** | **5.0.0+**
reason | Identificador do erro | **RESULT_CANCELED** | **5.0.0+**
description | Descrição do erro. | **RESULT_CANCELED** | **5.0.0+**

## Estrutura de Erro (SDK 5.0.0+)

:::danger Aviso Importante! 
A partir da versão **5.0.0**, a estrutura de erros foi reformulada para fornecer informações mais detalhadas e diagnósticas.
:::

### Exemplo: InvalidToken

```java
{
   status_code = 401
    reason = "INVALID_TOKEN"
    description = "Authentication token expired or invalid"
}
```
### Exemplo: UserCanceled

```java
{
    status_code = 0
    reason = "USER_CANCELED"
    description = "User pressed the back button."
}
```

## Versões Anteriores

```java
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        FaceRecognition.RequestResponseObject result;
        if (requestCode == REQUEST_CODE){
            if (resultCode == RESULT_OK && data != null){
                faceReconResponse = data.getParcelableExtra("FaceReconResponse");
            }
        }
    }
```

---

# Soluções híbridas

URL: /documentation/caas/face_recognition/android/hybrid_solutions

Além de oferecer integração nativa em Java, nossas SDKs também são compatíveis com diversos frameworks híbridos. Isso é possível através da integração de plugins nativos específicos para cada um desses frameworks. Utilizando o sistema nativo de cada solução, é viável incorporar nosso SDK nativa no ambiente Android.

Algumas das tecnologias híbridas mais utilizadas são o React Native ([Native Modules](https://reactnative.dev/docs/turbo-native-modules-introduction)), Cordova ([Plugin Development Guide](https://cordova.apache.org/docs/en/latest/guide/hybrid/plugins/index.html)), Ionic ([Native](https://ionicframework.com/docs/v3/native/)), Unity ([Native Plug-in para Android](https://docs.unity3d.com/Manual/PluginsForAndroid.html)), Xamarin ([Native Libraries](https://learn.microsoft.com/en-us/xamarin/android/platform/native-libraries)), Appcelerator, Phonegap e Node.

Para facilitar o processo de integração com nossas soluções nativas, disponibilizamos plugins para os frameworks React Native e Flutter. Caso tenha interesse, provemos a documentação e um exemplo de integração em nossos repositórios privados. Para as demais tecnologias híbridas, temos alguns exemplos de implementação dessa ponte para o código nativo. Fique à vontade para entrar em contato com nosso suporte para obter acesso.

---

# Introdução

URL: /documentation/caas/face_recognition/android/introduction

Bem-vindo ao SDK Android de Reconhecimento Facial da QI Tech. Este SDK realiza a captura da face e o seu envio para a API de Face Recognition da QI Tech . Você pode utilizá-lo para capturar uma imagem do rosto de um cliente por meio do seu aplicativo e referenciá-la por meio de uma chave nos demais produtos do sistema QI Tech.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso [suporte](mailto:suporte.caas@qitech.com.br) e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

---

# Integração nativa

URL: /documentation/caas/face_recognition/android/native_java

Para importar nossas SDKs, é necessário realizar alteração no _build.gradle_ de Projeto e de Aplicativo.

## Adicionando ao Projeto

Adicione o endereço de nosso repositório maven no _build.gradle_ do projeto (no Android Studio este arquivo aparece como: **"Project: \{nome_do_projeto\}"**), conforme exemplo abaixo.

```java
maven { url 'https://sdks.qitech.com.br/' }
```

## Adicionando ao Aplicativo

Após isso, adicione a biblioteca que você pretende importar em seu build.gradle do app (no Android Studio este arquivo aparece como: **"Module: \{nome_do_projeto\}.app"**), incluindo a dependência apresentada abaixo.

```java
dependencies {
    implementation 'com.qitech.android:facerecon:v7.0.0'
}
```

:::warning
Desde **abril de 2025**, novas políticas da Google Play requerem **Android API Level 35** para que aplicativos possam ser publicados
ou atualizados na Google Play Store. Por isso recomendamos fortemente que utilize **targetSdkVersion na versão 35** pelo menos.
:::

:::info
A utilização de **targetSdkVersion 35** implica na utilização do **compileSdkVersion 35**, o que desencadeia alguns **requisitos mínimos** para ferramentas
do ecossistema do Android:
* compileSdkVersion 35 --> AGP 8.6.0
* AGP 8.6.0 --> Gradle 8.7
* AGP 8.6.0 --> Java 17 (JDK 17)
* AGP 8.6.0 --> Kotlin 2+
:::

## Iniciando o SDK

:::danger Aviso Importante!
A partir da versão 5.0.0, o sistema de autenticação foi atualizado para usar **clientSessionKey** em vez de **mobileToken**. Além disso, foram adicionadas novas opções de configuração para telas de feedback.
:::

### Obtendo o Client Session Key

Antes de configurar o SDK, você deve gerar um **clientSessionKey** temporário através de uma requisição server-to-server para a nossa API de face recognition.

### Endpoint

| Ambiente | URL |
|----------|-----|
| **Sandbox** | `https://api.sandbox.zaig.com.br/face_recognition/client_session` |
| **Produção** | `https://api.zaig.com.br/face_recognition/client_session` |

### Requisição

**Method:** `POST`

**Headers:**
```json
{
  "Authorization": "YOUR_FACE_RECON_API_KEY"
}
```

**Body (Opcional, mas recomendado):**
```json
{
  "user_id": "unique_user_identifier" // Se disponível, utilize o CPF do usuário!
}
```

> **Importante:** O campo `user_id` é **altamente recomendado** para medidas de segurança e antifraude. Use um identificador único do usuário da sua aplicação.

### Resposta

A resposta bem-sucedida conterá o `client_session_key` que deve ser passado para a configuração do SDK.

```json
{
  "client_session_key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

Para incorporar o SDK ao seu aplicativo você deve realizar a configuração do seu aplicativo de captura personalizado através de um componente Builder e submetê-lo como parâmetro via Intent Extra para a FaceReconActivity.

### Exemplo de inicialização do SDK
```java
  Intent intent = new Intent(getApplicationContext(), FaceReconActivity.class);

  var onboardingTextConfiguration = new OnboardingTextConfiguration(
        "Conselhos relevantes",
        "Esteja com o rosto visível",
        "Encaixe seu rosto no oval",
        "Retire acessórios que cubram o rosto"
  );

  FaceRecognition mFaceRecognition = new FaceRecognition.Builder(clientSessionKey)
        .setSessionId("SESSION_ID")
        .setDocumentNumber("111.111.111-11")
        .setFontColor("#FFFFFF")
        .setBackgroundColor("#000000")
        .setFontFamily(FaceRecognition.FontFamily.futura)
        .showIntroductionScreens(true)
        .setShowSuccessScreen(true)
        .setShowInvalidTokenScreen(false)
        .setOnboardingTextConfiguration(onboardingTextConfiguration)
        .audioConfiguration(AudioConfiguration.enable)
        .setLogLevel(FaceRecognition.LogLevel.debug)
        .build();

  intent.putExtra("settings", mFaceRecognition);
  startActivityForResult(intent, REQUEST_CODE);
```

**Versões anteriores à v6.0.0**
```java
  Intent intent = new Intent(getApplicationContext(), FaceReconActivity.class);

  VisualConfiguration visualConfiguration = new VisualConfiguration()
          .setOnboardingDrawable(R.drawable.introscreen,500);

  TextConfiguration textConfiguration = new TextConfiguration()
          .setCustomText(TextConfiguration.CustomLabel.onboardingTitle, "Para tirar uma boa foto:")
          .setCustomText(TextConfiguration.CustomLabel.onboardingFirstLabel, "- Vá para um local iluminado")
          .setCustomText(TextConfiguration.CustomLabel.onboardingSecondLabel, "- Retire adereços e mostre bem o rosto")
          .setCustomText(TextConfiguration.CustomLabel.onboardingThirdLabel, "- Insira seu rosto na moldura, aguardando que fique verde para realizar a captura");

  FaceRecognition mFaceRecognition = new FaceRecognition.Builder(clientSessionKey)
          .showIntroductionScreens(true)
          .setVisualConfiguration(visualConfiguration)
          .setTextConfiguration(textConfiguration)
          .setBackgroundColor("#000000")
          .setFontColor("#FFFFFF")
          .setFontFamily(FaceRecognition.FontFamily.futura)
          .setSessionId("SESSION_ID")
          .setLogLevel(FaceRecognition.LogLevel.debug)
          .setShowSuccessScreen(false)
          .build();
  intent.putExtra("settings", mFaceRecognition);
  startActivityForResult(intent, REQUEST_CODE);
```

## FaceRecognition.Builder
| Parâmetro | Função | Obrigatório |
|------------|--------------|--------------|
|clientSessionKey |Chave do cliente que identifica que os dados coletados são provenientes do seu aplicativo. Obtida através de requisição à API da Face Recognition|Sim.|
|.setSandboxEnvironment()|Caso este parâmetro seja utilizado no construtor, a biblioteca será configurada para enviar os dados ao ambiente de sandbox. Caso ausente, as requisições são enviadas para o ambiente production.|Não.|
|.showIntroductionScreens(Boolean showIntroductionScreens)|Quando "false" desativa as telas de introdução à coleta da foto que aparecem para o usuário.|Não. O padrão é "true".|
|.setShowSuccessScreen(Boolean showSuccessScreen)|Quando "false" desativa a tela de sucesso após a coleta da foto.|Não. O padrão é "true".|
|.setShowInvalidTokenScreen(Boolean showSuccessScreen)|Quando "false" desativa a tela de falha de autenticação.|Não. O padrão é "true".|
|.setBackgroundColor(String backgroundColor)|Permite a configuração da cor de background das activities do SDK.|Não. O padrão é "#ffffff".|
|.setFontColor(String fontColor)|Permite a configuração da cor da fonte e dos ícones das activities do SDK.|Não. O padrão é "#000000".|
| .setFontFamily(FontFamily fontFamily)| Permite a configuração da fonte das activities do SDK.| Não. Caso não seja informada o padrão é FontFamily.open_sans. Fontes disponíveis: FontFamily.open_sans, FontFamily.futura, FontFamily.verdana, FontFamily.roboto, FontFamily.poppins e FontFamily.helvetica.|Não.|
|.setOnboardingTextConfiguration(OnboardingTextConfiguration onboardingTextConfiguration) | Permite a customização das instruções na tela de introdução. | Não. |
|.audioConfiguration(AudioConfiguration audioConfiguration)|Indica se o SDK deve ou não executar áudios de indicação para o usuário. As configurações aceitas são  _AudioConfiguration.enable_ que executa os áudios de indicação, _AudioConfiguration.disable_ que não executa estes áudios e _AudioConfiguration.accessibility_ que executa os áudios caso o dispositivo do usuário possua configurações de acessibilidade ativadas.|Não. O padrão é _AudioConfiguration.disable_.|
|.setSessionId(String sessionId)| Utilizado para definir a chave que identifica a sessão iniciada no SDK. É usada para rastrear todo fluxo percorrido pelo usuário na execução da FaceRecon através de logs. Este campo aceita até 255 caracteres. |Não.|
|.setLogLevel(FaceRecognition.LogLevel logLevel)| Utilizado para customizar o nível de verbosidade dos logs do SDK. Níveis disponíveis: LogLevel.debug, LogLevel.info, LogLevel.warn, LogLevel.error e LogLevel.trace. O padrão é LogLevel.debug. |Não.|
|.setDocumentNumber(String documentNumber)| Utilizado para definir o número do documento do usuário. Este campo aceita 14 caracteres. | Para Identificação utilizada internamente para anti-fraude e segurança. |

**Versões anteriores à v6.0.0**
| Parâmetro | Função | Obrigatório |
|------------|--------------|--------------|
|clientSessionKey |Chave do cliente que identifica que os dados coletados são provenientes do seu aplicativo. Obtida através de requisição à API da Face Recognition|Sim.|
|.setSandboxEnvironment()|Caso este parâmetro seja utilizado no construtor, a biblioteca será configurada para enviar os dados ao ambiente de sandbox. Caso ausente, as requisições são enviadas para o ambiente production.|Não.|
|.showIntroductionScreens(Boolean showIntroductionScreens)|Quando "false" desativa as telas de introdução à coleta da foto que aparecem para o usuário.|Não. O padrão é "true".|
|.setShowSuccessScreen(Boolean showSuccessScreen)|Quando "false" desativa a tela de sucesso após a coleta da foto.|Não. O padrão é "true".|
|.setShowInvalidTokenScreen(Boolean showSuccessScreen)|Quando "false" desativa a tela de falha de autenticação.|Não. O padrão é "true".|
|.setBackgroundColor(String backgroundColor)|Permite a configuração da cor de background das activities do SDK.|Não. O padrão é "#ffffff".|
|.setFontColor(String fontColor)|Permite a configuração da cor da fonte e dos ícones das activities do SDK.|Não. O padrão é "#000000".|
| .setFontFamily(FontFamily fontFamily)| Permite a configuração da fonte das activities do SDK.| Não. Caso não seja informada o padrão é FontFamily.open_sans. Fontes disponíveis: FontFamily.open_sans, FontFamily.futura, FontFamily.verdana, FontFamily.roboto, FontFamily.poppins e FontFamily.helvetica.|Não.|
|.activeFaceLiveness(Boolean activeFaceLiveness)|Indica se o SDK deve realizar um procedimento de captura de selfie do usuário ou de prova de vida ativa. |Não. O padrão é *false*.|
|.audioConfiguration(AudioConfiguration audioConfiguration)|Indica se o SDK deve ou não executar áudios de indicação para o usuário. As configurações aceitas são  _AudioConfiguration.enable_ que executa os áudios de indicação, _AudioConfiguration.disable_ que não executa estes áudios e _AudioConfiguration.accessibility_ que executa os áudios caso o dispositivo do usuário possua configurações de acessibilidade ativadas.|Não. O padrão é _AudioConfiguration.disable_.|
|.setVisualConfiguration(VisualConfiguration visualConfiguration)|Utilizado para customizar as imagens mostradas para o usuário ao longo da execução do SDK.|Não.|
|.setTextConfiguration(TextConfiguration textConfiguration)|Utilizado para customizar os textos da tela introdutória de onboarding mostradas para o usuário ao longo da execução do SDK.|Não.|
|.setSessionId(String sessionId)| Utilizado para definir a chave que identifica a sessão iniciada no SDK. É usada para rastrear todo fluxo percorrido pelo usuário na execução da FaceRecon através de logs. Este campo aceita até 255 caracteres. |Não.|
|.setLogLevel(FaceRecognition.LogLevel logLevel)| Utilizado para customizar o nível de verbosidade dos logs do SDK. Níveis disponíveis: LogLevel.debug, LogLevel.info, LogLevel.warn, LogLevel.error e LogLevel.trace. O padrão é LogLevel.debug. |Não.|
|.setDocumentNumber(String documentNumber)| Utilizado para definir o número do documento do usuário. Este campo aceita 14 caracteres. |Apenas para as chamadas que utilizem a validação 1:1 em algum momento. |
|.setValidation(Boolean validation)| Utilizado para definir se o SDK deve ou não realizar a validação 1:1 com a selfie do usuário. Na primeira sessão do usuário esta flag deve estar, **obrigatoriamente**, false. Esta função necessita do método setDocumentNumber preenchido.  |Não. O padrão é *false*.|

## O Objeto VisualConfiguration
:::warning
__DEPRECADO__ A PARTIR DA **v6.0.0**!
:::

| Parâmetro                                                             | Função                                                                                                                                                                                                                                        | Obrigatório             |
| --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| .setOnboardingDrawable(int onboarding_drawable, int onboarding_width) | Utilizado para configurar a imagem mostrada para o usuário na tela de onboarding do SDK. O parâmetro _onboarding_drawable_ deve referenciar o id da imagem a ser mostrada e _onboarding_width_ é o tamanho desejado de exibição desta imagem. | Não.                    |
| .setButtonBorderSize(int border_size)                                 | Utilizado para configurar a largura de borda dos botões do SDK.                                                                                                                                                                               | Não. O padrão é _1_.    |
| .setButtonShadow(boolean button_shadow)                               | Quando setado para _false_ remove o efeito de sombra, padrão no android, utilizado pelos botões do SDK.                                                                                                                                       | Não. O padrão é _true_. |

## O Objeto TextConfiguration
:::warning
__DEPRECADO__ A PARTIR DA **v6.0.0**!
:::

| Parâmetro                                      | Função                                                                                    | Obrigatório |
| ---------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------- |
| .setCustomText(CustomLabel label, String text) | Utilizado para configurar os textos mostrados para o usuário na tela de onboarding do SDK | Não.        |

---

# Autenticação

URL: /documentation/caas/face_recognition/api/authentication

:::danger Aviso Importante!
A partir da versão 5.0.0 das SDKs de iOS e Android e a versão 3.0.0 do SDK de Web, o sistema de autenticação foi atualizado para usar clientSessionKey em vez de mobileToken.
:::

Utilizamos uma API Key para permitir acesso à nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

## Client Session Key

Antes de configurar o SDK, você deve gerar um clientSessionKey temporário através de uma requisição server-to-server para a nossa API.

### Gerar Client Session Key

```bash
curl -X POST "https://api.zaig.com.br/face_recognition/client_session" \
     -H "Authorization: EXAMPLE_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{ "user_id": "unique_user_identifier" }'
```

**Endpoints**

| Ambiente | URL |
|----------|-----|
| Sandbox | https://api.sandbox.zaig.com.br/face_recognition/client_session |
| Produção | https://api.zaig.com.br/face_recognition/client_session |

**Detalhes da Requisição**

| Campo | Tipo | Obrigatório | Descrição|
|----------|----------|----------|----------|
| user_id | string | Não | Identificador único do usuário da sua aplicação (ex: CPF, RG, etc) |

O campo `user_id` no corpo da requisição é altamente recomendado para medidas de segurança e antifraude.

**Request Body**
```json
{
  "user_id": "unique_user_identifier"
}
```

**Response Body**

A resposta bem-sucedida conterá o `client_session_key`.
```json
{
  "client_session_key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

:::info Atenção
Você deve substituir `EXAMPLE_API_KEY` pela API Key recebida do suporte.
:::

---

# Registro de rosto (1:1)

URL: /documentation/caas/face_recognition/api/face_registration

Para realizar um **registro de rosto** (para posterior validação 1:1), é necessário utilizar os **endpoints específicos** da API de Face Recognition descritos nesta página.

## Endpoints disponíveis

Os recursos de registro de rosto estão expostos nas seguintes rotas:

| Método | Endpoint | Descrição |
|--------|----------|-----------|
| POST | `/face_recognition/registration` | Cria um novo registro de rosto |
| GET | `/face_recognition/registration/{registration_key}` | Recupera registro pela chave |
| GET | `/face_recognition/registration/document_number/{document_number}` | Recupera registro pelo número do documento |

**URL base (produção):** `https://api.caas.qitech.app`  
**URL base (sandbox):** `https://api.sandbox.caas.qitech.app`

---

## Criação de um registro (POST)

Para cadastrar o rosto de um cliente, envie uma requisição **POST** para:

`https://api.caas.qitech.app/face_recognition/registration`

O corpo da requisição deve conter o **número do documento** e a imagem do rosto, de uma das duas formas abaixo.

### Opção 1: imagem via `image_key` (extraída da SDK)

Utilize o **image_key** retornado pela SDK após a captura do rosto.

Request Body – image_key

```json
{
    "document_number": "DOCUMENT_NUMBER",
    "image_key": "<IMAGE_KEY_FROM_SDK>"
}
```

### Opção 2: imagem em Base64

Envie a imagem diretamente em Base64 (sem cabeçalhos ou metadados adicionais).

Request Body – image (Base64)

```json
{
    "document_number": "DOCUMENT_NUMBER",
    "image": "<IMAGE_BASE64>"
}
```

### Campos do request

nome | tipo | descrição
:----: | :----: | ---------
document_number | string | Número do documento (ex.: CPF) do cliente
image_key | string | Chave da imagem retornada pela SDK (UUID). Use **ou** `image_key` **ou** `image`
image | string | Imagem do rosto em Base64. Use **ou** `image` **ou** `image_key`

:::info
É obrigatório enviar **apenas um** dos campos de imagem: `image_key` **ou** `image`. Não envie os dois no mesmo request.
:::

Após o envio com sucesso, a API retorna apenas a chave do registro de rosto:

Response Body

```json
{
    "registration_key": "chave_do_registro_do_rosto"
}
```

---

## Recuperação de registro por chave (GET)

Para obter a chave de um registro pela sua chave única:

`https://api.caas.qitech.app/face_recognition/registration/{registration_key}`

Substitua `{registration_key}` pelo identificador retornado na criação do registro.

**Response Body:**

```json
{
    "registration_key": "chave_do_registro_do_rosto"
}
```

---

## Recuperação de registro por documento (GET)

Para obter a chave de um registro pelo número do documento:

`https://api.caas.qitech.app/face_recognition/registration/document_number/{document_number}`

Substitua `{document_number}` pelo número do documento do cliente (ex.: CPF).

**Response Body:**

```json
{
    "registration_key": "chave_do_registro_do_rosto"
}
```

---

---

# Status HTTP

URL: /documentation/caas/face_recognition/api/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Imagem

URL: /documentation/caas/face_recognition/api/image

O envio de uma foto de rosto é mandatório para a utilização de nossa API de reconhecimento facial. Visando garantir uma maior confiabilidade das análises executadas, é necessário que o cliente siga algumas regras na hora de tirar a foto:

* A foto deve conter apenas um rosto;
* Todo o rosto deve estar visível na foto;
* O rosto deve ocupar ao menos 15% da area da foto;
* O rosto deve estar encarando a câmera e paralelo a ela;
* O rosto deve estar com os olhos abertos;
* O rosto deve estar com a boca fechada;
* O rosto deve possuir expressão neutra e sem sorrisos;
* O rosto não deve estar coberto por nenhum tipo de acessório (chapéus, óculos ou máscaras).

Além disso, somente imagens .jpeg e .png com tamanho máximo de 3MB serão aceitas.

## Envio de arquivos

Request Body

```json
{
    "image": "base64_image_code"
}
```

Response Body

```json
{ 
    "image_key": "f4b5337a-7b50-406e-8c8e-7d0e77b5aa02",
    "file_size": 47407,
    "width_px": 0,
    "height_px": 0,
    "created_at": "2020-07-29T18:40:57Z"
}
```

Em casos que seja necessário o envio de uma imagem sem a execução imediata das rotinas de cadastro ou validação facial, um objeto JSON contendo o Base64 da imagem deve ser enviado. 
Para tal deve-se enviar uma requisição do tipo **POST** para o endpoint:

`https://api.caas.qitech.app/face_recognition/image`

Uma vez enviada, a imagem será submetida a testes de qualidade e, caso aprovada, será retornado um JSON contendo a chave de acesso à imagem. Essa chave deverá ser usada para referenciar a foto durante o cadastro ou validação facial.

:::info **Atenção**

Deve ser enviado apenas o código Base64 correspondente a imagem.
:::

## Validação de qualidade da imagem

Response Body: Caso de imagem inválida

```json
{
    "title": "image_quality",
    "description": "This image was not approved in quality assessment. The face is too close to image edges.",
    "image_status": "not_center"
}
```

Ao realizar um post no endpoint de imagem, caso a imagem não seja suficiente para validação, um HTTP Status Code 400 será retornado.

O valor do campo *description* é a mensagem que explica o motivo da imagem ser inválida.

Além disso, retornamos um enumerador *image_status* para que seja maepado o motivo da imagem ser inválida. Abaixo temos a listagem dos possíveis *image_status*:

image_status |  descrição
:----: | :---------:
no_faces | Nenhum rosto identificado.
multiple_faces | Mais de um rosto identificado.
close_face | Rosto muito próximo à câmera.
distant_face | Rosto muito distante à câmera.
not_centered | Rosto não está centralizado o suficiente.
inclined_face | Rosto está inclinado.
wearing_acessories | Pessoa está utilizando acessórios que cobrem parte do rosto.
facial_expression | A pessoa está com a boca aberta, sorrindo ou com os olhos fechados.
brightness_problem | A imagem não está com a iluminação adequada.
sharpness_problem | A imagem não está nítida o suficiente.

**Atenção -** Existem outros motivos pelos quais retornaremos 400 (Todos relacionados a dados inválidos). Somente os retornos com title "image_quality" são resultantes da validação de qualidade da imagem e portanto devem ser repassados ao usuário.

## Recuperação dos arquivos
> Recuperação de imagem

```shell
    curl "https://api.caas.qitech.app/face_recognition/image/f4b5337a-7b50-406e-8c8e-7d0e77b5aa02/file" \
         -H "Authorization: EXAMPLE_API_KEY"
```

Em qualquer momento é possível recuperar as imagens enviadas. Para isso, basta enviar  uma requisição **GET** adequadamente autenticada no endpoint:

`https://api.caas.qitech.app/face_recognition/image/{image_key}/file`

Onde image_key é o valor retornado durante o envio da imagem.

## Recuperação de arquivo processado
> Recuperação de imagem processada

```shell
    curl "https://api.caas.qitech.app/face_recognition/image/f4b5337a-7b50-406e-8c8e-7d0e77b5aa02/cropped_file" \
         -H "Authorization: EXAMPLE_API_KEY"
```
Após a associação de uma imagem a um cadastro ou uma validação, essa imagem será processada e uma nova imagem contendo apenas o rosto utilizado nas rotinas de reconhecimento facial será gerada.

Esta imagem está disponível para ser recuperada através de uma requisição **GET**, adequadamente autenticada, no endpoint:

`https://api.caas.qitech.app/face_recognition/image/{image_key}/cropped_file`

Onde image_key é o valor retornado durante o envio da imagem base.

## Recuperação dos meta-dados do arquivo
> Recuperação de meta dados

```shell
    curl "https://api.caas.qitech.app/face_recognition/image/f4b5337a-7b50-406e-8c8e-7d0e77b5aa02" \
         -H "Authorization: EXAMPLE_API_KEY"
```

Após o envio de uma imagem para a API, é possível recuperar os meta-dados da imagem utilizando o endpoint:

`https://api.caas.qitech.app/face_recognition/image/{image_key}`

Onde image_key é o valor retornado durante o envio da imagem.

---

# Introdução

URL: /documentation/caas/face_recognition/api/introduction

Bem vindo à API de Reconhecimento Facial da QI Tech! Você pode usar a nossa API para acessar os endpoints, cadastrar fotos de clientes e realizar o reconhecimento facial destes antes da execução de transações.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/face_recognition/`
* Sandbox - `https://api.sandbox.caas.qitech.app/face_recognition/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

---

# Padrões

URL: /documentation/caas/face_recognition/api/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões que são seguidos em toda a API.

## Data e Hora com Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12-03:00
2018-05-01T13:32:11+00:00
2019-05-01T00:00:00+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será valido. Por exemplo, se um aluguel estiver marcado para começar às 09:30 no aeroporto de Brasília, o horário enviado deverá ser representado por 09:30-03:00, se o aluguel estiver marcado para começar às 09:30 em Manaus, deverá ser representado por 09:30-04:00.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss±hh:mm`

## Data e Hora sem Fuso Horario
> Alguns exemplos:

```
2019-10-15T22:35:12Z
2018-05-01T13:32:11Z
2019-05-01T00:00:00Z
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão ser enviados sem ele, sempre em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ssZ`

## Data
> Alguns exemplos

``` 
2019-10-15
2019-01-01
2017-03-20
```

No caso de campos que recebem somente data, uma data de nascimento, por exemplo, somente a data, sem nenhum horário deve ser enviada com o seguinte formato:

`YYYY-MM-dd`
 

## Documentos
Uma vez que os números de documento são bastante variados e muitos deles possuem caracteres que não se enquadram como numéricos, definem-se todos os números de documento como string. Outro bom motivo para definí-los como string é evitar que os zeros à esquerda desapareçam. Documentos previstos nesta página possuem uma máscara bem definida e estarão sujeitos a validação. O restante dos documentos, como RG, dada sua falta de padronização, não serão validados.

## CPF

> Exemplos de CPFs válidos contra a máscara definida:

```
123.456.789-12
321.987.543-23
111.283.333-00
```

> Exemplos de CPFs inválidos contra a máscara definida:

```
8.577.477-8
08.104.627/0001-23
123.456.789-1
23.456.789-01
```

O CPF é sempre definido como uma string e será validado contra a máscara:

`###.###.###-##`

---

# Coletando os Retornos do SDK

URL: /documentation/caas/face_recognition/ios/collecting_response

Para obter as respostas do SDK , você deve implementar o delegate **QITechIosFaceRecognitionControllerDelegate** em seu controller, conforme exemplo ao lado.

```swift
class ViewController: UIViewController, QITechIosFaceRecognitionControllerDelegate {
    
    // Do something if QI Tech FaceRecognition's SDK succesfully collected document picture
    func qitechIosFaceRecognitionController(_ faceRecognitionViewController: QITechIosFaceRecognitionController, didFinishWithResults response: QITechIosFaceRecognitionControllerResponse) {
    
    }
    
    // Do something if QI Tech FaceRecognition's SDK found any error when collecting document picture
    func qitechIosFaceRecognitionController(_ faceRecognitionViewController: QITechIosFaceRecognitionController, didFailWithError error: QITechIosFaceRecognitionControllerError) {
        
    }
    
    // Do something if the user canceled the picture collection on any steps
    func qitechIosFaceRecognitionControllerDidCancel(_ faceRecognitionViewController: QITechIosFaceRecognitionController) {

    }
}
```

## QITechIosFaceRecognitionControllerResponse

A classe **QITechIosFaceRecognitionControllerResponse** é utilizada para que você possa receber a resposta do SDK da QI Tech.

Na tabela abaixo você encontra o detalhe de todas as propriedades desta classe:

### Propriedades

:::info Aviso: 
Integração com Device Scan A partir da versão 6.1.0, o serviço de Face Recognition passa a realizar automaticamente uma chamada interna ao Device Scan. Com isso, o retorno de sucesso incluirá o campo `DeviceScanSessionId`. Esta chave identifica a sessão de scan de dispositivo realizada internamente e pode ser utilizada de forma integrada em outros serviços do ecossistema QI Tech. 
:::

| Nome | Tipo | Descrição |
|------|------|-----------|
| `FaceRecognitionKey` | `String` | Identificador único da foto do rosto armazenado na QI Tech. **Importante:** Armazene este valor para enviar nas APIs de validação (ex.: API de Onboarding). |
`DeviceScanSessionId` | `String` | Identificador único da sessão de scan de dispositivo realizada internamente. |

## QITechIosFaceRecognitionControllerError

A classe **QITechIosFaceRecognitionControllerError** é acionada quando ocorre um erro que leva ao encerramento do SDK.

:::danger Aviso Importante! 
A partir da versão **5.0.0**, a estrutura de erros foi reformulada para fornecer informações mais detalhadas e diagnósticas.
:::
#### Principais mudanças:

1. **Novos tipos de erro**: `InvalidToken` (substitui `InvalidMobileToken`)
2. **Novas propriedades disponíveis**:
   - `status_code`: Código HTTP do erro
   - `reason`: Identificador do motivo do erro
   - `description`: Descrição detalhada do erro

### Estrutura de Erro (SDK 5.0.0+)

#### Exemplo: InvalidToken

```swift
{
    status_code: 401,
    reason: "INVALID_TOKEN",
    description: "Authentication token expired or invalid"
}
```

## Tipos de Erro

### SDK 5.0.0 e posteriores

| Erro | Status Code | Descrição |
|------|-------------|-----------|
| `InvalidToken` | 401 | Token de autenticação expirado ou inválido (substitui `InvalidMobileToken`) |

### Versões anteriores à 5.0.0

| Classe de Erro | Descrição |
|----------------|-----------|
| `InvalidMobileToken` | MobileToken enviado nas configurações é inválido *(substituído por `InvalidToken` na v5.0.0+)* |
| `MissingPermission` | Alguma das permissões necessárias não foi concedida |
| `NetworkFailure` | Perda de conexão com a internet durante a validação |
| `ServerFailure` | Resposta de erro do servidor da QI Tech |
| `MissingStorage` | Espaço de armazenamento insuficiente |
| `LowImageQuality` | Qualidade da imagem insuficiente para validação |

---

# QITechIosFaceRecognitionConfiguration

URL: /documentation/caas/face_recognition/ios/configuration

## SDK 7.0.0 e posteriores
```swift
let onboardingTextConfiguration = OnboardingTextConfiguration(
        onboardingTitle: "Conselhos relevantes",
        onboardingFirstLabel: "Esteja com o rosto visível",
        onboardingSecondlabel: "Encaixe seu rosto no oval",
        onboardingThirdLabel: "Retire acessórios que cubram o rosto"
)

let faceRecognitionConfig = QITechIosFaceRecognitionConfiguration(
        environment: QITechIosFaceRecognitionEnvironment.sandbox,
        clientSessionKey: clientSessionKey,
        sessionId: "7d8c6f9a-f222-450d-9501-a07c68eb2388",
        documentNumber: "123.456.789-00",
        fontColor: "#337DFF",
        backgroundColor: "#C9CCD3",
        fontFamily: .open_sans,
        showIntroductionScreens: true,
        showSuccessScreen: true,
        showInvalidTokenScreen: false,
        audioConfiguration: AudioConfiguration.enable,
        onboardingTextConfiguration: onboardingTextConfiguration,
        logLevel: .debug
)
```

**Versões anteriores à v7.0.0**
```swift
let visualConfiguration = VisualConfiguration()
        visualConfiguration.setOnboarding(onboardingFilePath: Bundle.main.path(forResource: "onboarding", ofType: "png")!, onboardingWidth: 200)

let textConfiguration = TextConfiguration()
        textConfiguration.setCustomText(on: .onboardingTitle, text: "Para tirar uma boa foto:")
        textConfiguration.setCustomText(on: .onboardingFirstLabel, text: "- Vá para um local iluminado")
        textConfiguration.setCustomText(on: .onboardingSecondLabel, text: "- Retire adereços e mostre bem o rosto")
        textConfiguration.setCustomText(on: .onboardingThirdLabel, text: "- Insira seu rosto na moldura, aguardando que fique verde para realizar a captura")

let faceRecognitionConfig = QITechIosFaceRecognitionConfiguration(environment: QITechIosFaceRecognitionEnvironment.Sandbox,
                                            clientSessionKey: clientSessionKey,
                                            sessionId: "7d8c6f9a-f222-450d-9501-a07c68eb2388",
                                            backgroundColor: "#C9CCD3",
                                            fontColor: "#337DFF",
                                            fontFamily: .open_sans,
                                            showIntroductionScreens: true,
                                            showSuccessScreen: false,
                                            showInvalidTokenScreen: true,
                                            activeFaceLiveness: true,
                                            audioConfiguration: AudioConfiguration.Enable,
                                            logLevel: .debug
                                            )

faceRecognitionConfig.setVisualConfiguration(visualConfiguration: visualConfiguration)
faceRecognitionConfig.setTextConfiguration(textConfiguration: textConfiguration)
```

A classe **QITechIosFaceRecognitionConfiguration** é utilizada para que você possa configurar ambiente, credenciais, aspectos visuais e textuais ou seja, todas as configurações necessárias para personalização e funcionamento do SDK.

Na tabela abaixo você encontra o detalhe de todos os argumentos que devem ser utilizados na sua instanciação:

| nome                    |               tipo                | descrição                                                                                                                                                                                                                                                                                                                                   |
| ----------------------- | :-------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| environment             | QITechIosFaceRecognitionEnvironment | _(obrigatório)_ Enumerador que descreve o ambiente.                                                                                                                                                                                                                                                                                         |
| clientSessionKey        |              string               | _(obrigatório)_ Token enviado pela API face recognition para autenticação do SDK.                                                                                                                                                                                                                                                                        |
| sessionId               |              string               | _(opcional)_ ID único usado para rastrear todo fluxo percorrido pelo usuário na execução da FaceRecon através de logs. Este campo aceita até 255 caracteres.                                                                                                                                                                                |
| documentNumber          |              string               | _(opcional)_ Utilizado para identificação do usuário para anti-fraude e segurança interna |
| fontColor               |              string               | _(opcional)_ Hexadecimal da cor da fonte. Caso não seja informada o padrão é #1C49A5.                                                                                                                                                                                                                                                       |
| backgroundColor         |              string               | _(opcional)_ Hexadecimal da cor de fundo das telas. Caso não seja informada o padrão é #FCFCFC.                                                                                                                                                                                                                                             |
| fontFamily              |            FontFamily             | _(opcional)_ Familia da fonte. Caso não seja informada o padrão é .open_sans. Fontes disponíveis: .open_sans, .futura, .verdana, .trebuchetms, .tamilsangammn e .system_font.                                                                                                                                                               |
| showIntroductionScreens |             booleano              | _(opcional)_ Flag que indica se as telas de introdução, com instruções de como a foto deve ser capturada, devem ser mostradas. Caso não seja informada o padrão é _true_.                                                                                                                                                                   |
| showSuccessScreen       |             booleano              | _(opcional)_ Flag que indica se a tela de sucesso, com a mensagem de sucesso na captura, deve ser mostrada. Caso não seja informada o padrão é _true_.                                                                                                                                                                                      |
| showInvalidTokenScreen  |             booleano              | _(opcional)_ Flag que indica se a tela de falha de autenticação, com a mensagem de expiração de token, deve ser mostrada. Caso não seja informada o padrão é _true_. |
| audioConfiguration      |        AudioConfiguration         | _(opcional)_ Indica se o SDK deve ou não executar áudios de indicação para o usuário. As configurações aceitas são: _Enable_ que sempre executará os áudios de indicação, _Disable_ que nunca executará estes áudios e _Accessibility_ que executa os áudios caso o dispositivo do usuário possua configurações de acessibilidade ativadas. |
| onboardingTextConfiguration | OnboardingTextConfiguration | _(opcional)_ Permite configurar os textos da tela de instruções |
| logLevel                |             LogLevel              | _(opcional)_ Utilizado para customizar o nível de verbosidade dos logs do SDK. Níveis disponíveis: LogLevel.debug, LogLevel.info, LogLevel.warn, LogLevel.error e LogLevel.trace. Caso não seja informada o padrão é LogLevel.debug. |

Na tabela abaixo você encontra todos os métodos aceitos pela instância para configuração:
:::warning
__DEPRECADO__ A PARTIR DA **v7.0.0**!
:::

| método                 |                                                                                                                     argumentos                                                                                                                     | descrição                                                                                     |
| ---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | --------------------------------------------------------------------------------------------- |
| setVisualConfiguration |                                                                 visualConfiguration : VisualConfiguration                                                             | _(opcional)_ Classe que permite a modificação das imagens exibidas durante a execução do SDK; |
| setTextConfiguration   |                                                                                                       textConfiguration : TextConfiguration                                                                                                        | _(opcional)_ Classe que permite a modificação dos textos exibidos durante a execução do SDK;  |
| setDocumentNumber      |                                                    Utilizado para definir o número do documento do usuário. Este campo aceita 14 caracteres do CPF formatado da seguinte maneira 000.000.000-00                                                    | Sim em todas as chamadas caso use a validação 1:1 em algum momento.                                                                                         |
| setValidation          | Utilizado para definir se o SDK deve ou não realizar a validação 1:1 com a selfie do usuário. Na primeira sessão do usuário esta flag deve estar **obrigatoriamente false**. Esta função depende necessita do método setDocumentNumber preenchido. | Não. O padrão é _false_.                                                                      |

---

# Soluções híbridas

URL: /documentation/caas/face_recognition/ios/hybrid_solutions

Além de oferecer integração nativa em Swift, nossas SDKs também são compatíveis com diversos frameworks híbridos. Isso é possível através da integração de plugins nativos específicos para cada um desses frameworks. Utilizando o sistema nativo de cada solução, é viável incorporar nosso SDK nativa no ambiente iOS.

Algumas das tecnologias híbridas mais utilizadas são o Xamarin ([Native Libraries](https://learn.microsoft.com/en-us/xamarin/android/platform/native-libraries)), React Native ([Native Modules](https://reactnative.dev/docs/native-modules-intro)), Cordova ([Plugin Development Guide](https://cordova.apache.org/docs/en/10.x/guide/hybrid/plugins/)), Ionic ([Native](https://ionicframework.com/docs/v3/native/)), Flutter ([Platform-Specific Code](https://docs.flutter.dev/platform-integration/platform-channels)), Unity ([Native Plug-in para iOS](https://docs.unity3d.com/Manual/PluginsForIOS.html)), Appcelerator, Phonegap e Node.

Para facilitar o processo de integração com nossas soluções nativas, disponibilizamos plugins para os frameworks React Native e Flutter. Caso tenha interesse, provemos a documentação e um exemplo de integração em nossos repositórios privados. Para as demais tecnologias híbridas, temos alguns exemplos de implementação dessa ponte para o código nativo. Fique à vontade para entrar em contato com nosso suporte para obter acesso.

---

# Introdução

URL: /documentation/caas/face_recognition/ios/introduction

Bem vindo ao SDK iOS de Reconhecimento Facial da QI Tech. Este SDK realiza a captura de face e seu envio para a API de Face Recognition da QI Tech . Você pode utilizá-lo para capturar através do seu aplicativo uma imagem do rosto de um cliente e referenciá-lo através de uma chave nos demais produtos do sistema QI Tech.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso [suporte](mailto:suporte.caas@qitech.com.br) e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

---

# Importando o SDK

URL: /documentation/caas/face_recognition/ios/native_swift

## Remotamente

> Iniciando a instalação

```shell
  pod init
```

Nosso SDK pode ser importado utilizando CocoaPods.

| SDK              | Versão atual                         |
| ---------------- | ------------------------------------ |
| QITechIosFaceRecon | `pod 'QITechIosFaceRecon', '~> 8.0.0'` |

:::info iOS Minimum Deployment Target
15.5
:::

:::danger Utilização de simuladores em MacBooks com chip arm64
Atualmente, nosso SDK de FaceRecon para iOS infelizmente não suporta ser compilada para simuladores que estejam rodando
em um MacBook com **chip de arquitetura arm64** (M1/M2/M3/M4), **a não ser que seja utilizado Rosetta**, que faz a tradução
da arquitetura x86_64 para arm64.
:::

Para iniciar a instalação, execute o comando ao lado na pasta raiz do seu projeto.

> Adicionando a source no podfile

```ruby
   source 'https://github.com/QITechSDKs/iOS.git'
   source 'https://cdn.cocoapods.org/'
```

O próximo passo é adicionar no arquivo `podfile` o source da QI Tech.

> Adicionando o pod no podfile

```ruby
  pod 'QITechIosFaceRecon', '~> <version>'
```

Por fim, basta adicionar o nome do `pod` de acordo com o formato ao lado.

:::danger Atenção: 
Mudança de Arquitetura (v6.0.0+) A partir da versão 6.0.0, o SDK passou a ser distribuída exclusivamente de forma estática. No seu Podfile, você deve utilizar a configuração :linkage => :static. 
:::

> Exemplo de podfile (Versão 6.0.0 ou superior)

```ruby
  source 'https://github.com/QITechSDKs/iOS.git'
  source 'https://cdn.cocoapods.org/'
  target 'ExampleApp' do
    use_frameworks! :linkage => :static
    pod 'QITechIosFaceRecon', '~> 8.0.0'
  end

  post_install do |installer|
    installer.pods_project.targets.each do |target|
      if ['DatadogCore', 'DatadogInternal', 'DatadogCrashReporting', 'DatadogLogs'].include?(target.name)
        target.build_configurations.each do |config|
          config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'
          config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
        end
      end
    end
  end
```

> Exemplo de podfile (Versão Anteriores) 

```ruby
  source 'https://github.com/QITechSDKs/iOS.git'
  source 'https://cdn.cocoapods.org/'
  target 'ExampleApp' do
    use_frameworks!
    pod 'QITechIosFaceRecon', '~> 5.0.0'
  end

  post_install do |installer|
    installer.pods_project.targets.each do |target|
      if ['DatadogCore', 'DatadogInternal', 'DatadogCrashReporting', 'DatadogLogs'].include?(target.name)
        target.build_configurations.each do |config|
          config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'
          config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
        end
      end
    end
  end
```

:::warning Atenção
Ao integrar dependências no iOS, pode surgir a necessidade de usar linkagem estática para algumas bibliotecas e dinâmica para outras. Essa configuração é relevante para garantir compatibilidade, evitar erros de build e otimizar o desempenho do projeto. 
:::

### Linkagem Híbrida de Dependências (caso necessário)
A necessidade de linkagem híbrida surge porque algumas bibliotecas têm requisitos específicos, sendo que algumas precisam de linkagem estática para evitar conflitos internos e duplicação de símbolos e outras dependências podem precisar linkagem dinâmica, pois são projetadas para modularidade e compartilhamento entre projetos.

Diferenças Entre Linkagem Estática e Dinâmica
* Estática (static_framework): O código da biblioteca é incorporado diretamente no binário final, reduzindo o tempo de carregamento em runtime e eliminando dependências externas durante a execução.
* Dinâmica (dynamic_framework): A biblioteca é carregada em tempo de execução como um arquivo separado. Isso reduz o tamanho do binário final e facilita atualizações/modificações independentes.

> Configurando linkagem híbrida no Podfile

```ruby
...

use_frameworks! :linkage => :dynamic # CONFIGURANDO O MODO PADRÃO DE LINKAGEM PARA DINÂMICO

...

static_frameworks = ['framework_1', 'framework_2', ...] # INCLUIR TODAS AS DEPENDÊNCIAS QUE PRECISAM SER LINKADAS DE MODO ESTÁTICO
pre_install do |installer|
  installer.pod_targets.each do |pod|
    if static_frameworks.include?(pod.name)
      def pod.static_framework?;
        true
      end
      def pod.build_type;
        Pod::BuildType.static_framework
      end
    end
  end
end
```

> Instalando as dependências

```shell
  pod install
```

Por fim, execute o comando `pod install` para baixar e instalar as dependências.

## Permissões Necessárias

Para que o SDK possa acessar os recursos do dispositivo para coletar a selfie do usuário, é necessário que sejam solicitadas permissões ao usuário.

No arquivo **info.plist**, adicione as permissões abaixo:

| Permissão                          | Motivo                                             |
| ---------------------------------- | -------------------------------------------------- |
| Privacy - Camera Usage Description | Acesso à câmera para capturar a selfie do usuário. |

## Iniciando o SDK

:::danger Aviso Importante!
A partir da versão 5.0.0, o sistema de autenticação foi atualizado para usar **clientSessionKey** em vez de **mobileToken**. Além disso, foram adicionadas novas opções de configuração para telas de feedback.
:::

### Obtendo o Client Session Key

Antes de configurar o SDK, você deve gerar um **clientSessionKey** temporário através de uma requisição server-to-server para a nossa API de face recognition.

### Endpoint

| Ambiente | URL |
|----------|-----|
| **Sandbox** | `https://api.sandbox.zaig.com.br/face_recognition/client_session` |
| **Produção** | `https://api.zaig.com.br/face_recognition/client_session` |

### Requisição

**Method:** `POST`

**Headers:**
```json
{
  "Authorization": "YOUR_FACE_RECON_API_KEY"
}
```

**Body (Opcional, mas recomendado):**
```json
{
  "user_id": "unique_user_identifier"
}
```

> **Importante:** O campo `user_id` é **altamente recomendado** para medidas de segurança e antifraude. Use um identificador único do usuário da sua aplicação.

### Resposta

A resposta bem-sucedida conterá o `client_session_key` que deve ser passado para a configuração do SDK.

```json
{
  "client_session_key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

### Exemplo de inicialização do SDK

```swift

import QITechIosFaceRecognition

class ViewController: UIViewController, QITechIosFaceRecognitionControllerDelegate {

    var qitechFaceRecognitionConfiguration : QITechIosFaceRecognitionConfiguration?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.setupFaceRecognition()
    }

    func setupFaceRecognition() -> Void {
      let clientSessionKey = try await fetchClientSessionKey()
                    
      let onboardingTextConfiguration = OnboardingTextConfiguration(
          onboardingTitle: "Conselhos relevantes",                     // Título
          onboardingFirstLabel: "Esteja com o rosto visível",          // Primeira Instrução
          onboardingSecondlabel: "Encaixe seu rosto no oval",          // Segunda Instrução
          onboardingThirdLabel: "Retire acessórios que cubram o rosto" // Terceira Instrução
      )

      self.faceRecognitionConfig = QITechIosFaceRecognitionConfiguration(
          environment: QITechIosFaceRecognitionEnvironment.sandbox,
          clientSessionKey: clientSessionKey,
          sessionId: "test_session_id",
          documentNumber: "123.456.789-00",
          fontColor: "#AB9FF2",
          backgroundColor: "#FFFDF8",
          fontFamily: .futura,
          showIntroductionScreens: true,
          showSuccessScreen: true,
          showInvalidTokenScreen: false,
          audioConfiguration: AudioConfiguration.enable,
          onboardingTextConfiguration: onboardingTextConfiguration,
          logLevel: .debug 
      )
    }

    // Event where you intend to call QI Tech FaceRecognition View Controller - on this example, when the user press 'next' button

    @IBAction func pressNext(_ sender: Any) {
        let qitechFaceRecognitionController = QITechIosFaceRecognitionController(faceRecognitionConfiguration: self.faceRecognitionConfig)
        qitechFaceRecognitionViewController.delegate = self
        let qitechFaceRecognitionViewController =  qitechFaceRecognitionController.getViewController()
        present(qitechFaceRecognitionViewController, animated: true, completion: nil)
    }

    // Do something if QI Tech FaceRecognition's SDK successfully collected picture
    func qitechIosFaceRecognitionController(_ faceRecognitionViewController: QITechIosFaceRecognitionController, didFinishWithResults results: QITechIosFaceRecognitionControllerResponse) {

    }

    // Do something if QI Tech FaceRecognition's SDK found any error when collecting  picture
    func qitechIosFaceRecognitionController(_ faceRecognitionViewController: QITechIosFaceRecognitionController, didFailWithError error: QITechIosFaceRecognitionControllerError) {

    }

    // Do something if the user canceled the picture collection on any steps
    func qitechIosFaceRecognitionControllerDidCancel(_ faceRecognitionViewController: QITechIosFaceRecognitionController) {

    }
}
```

**Versões anteriores à v7.0.0**
```swift

import QITechIosFaceRecognition

class ViewController: UIViewController, QITechIosFaceRecognitionControllerDelegate {

    var qitechFaceRecognitionConfiguration : QITechIosFaceRecognitionConfiguration?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.setupFaceRecognition()
    }

    func setupFaceRecognition() -> Void {
        // The environment can be 'Sandbox' ou 'Production'
        let environment = QITechIosFaceRecognitionEnvironment.Sandbox

        // ClientSessionKey is the key you got via Face Recognition request. Each environment requires a different API_KEY.
        let clientSessionKey = fetchClientSessionKey()

        self.faceRecognitionConfig = QITechIosFaceRecognitionConfiguration(environment: environment,
                                            clientSessionKey: clientSessionKey,
                                            sessionId: "UNIQUE_SESSION_ID",
                                            backgroundColor: "#000000",
                                            fontColor: "#FFFFFF",
                                            fontFamily: .open_sans,
                                            showIntroductionScreens: true,
                                            showSuccessScreen: false,
                                            showInvalidTokenScreen: true,
                                            activeFaceLiveness: true,
                                            audioConfiguration: AudioConfiguration.Enable,
                                            logLevel: .debug
                                            )
    }

    // Event where you intend to call QI Tech FaceRecognition View Controller - on this example, when the user press 'next' button

    @IBAction func pressNext(_ sender: Any) {
        let qitechFaceRecognitionController = QITechIosFaceRecognitionController(faceRecognitionConfiguration: self.faceRecognitionConfig)
        qitechFaceRecognitionViewController.delegate = self
        let qitechFaceRecognitionViewController =  qitechFaceRecognitionController.getViewController()
        present(qitechFaceRecognitionViewController, animated: true, completion: nil)
    }

    // Do something if QI Tech FaceRecognition's SDK successfully collected picture
    func qitechIosFaceRecognitionController(_ faceRecognitionViewController: QITechIosFaceRecognitionController, didFinishWithResults results: QITechIosFaceRecognitionControllerResponse) {

    }

    // Do something if QI Tech FaceRecognition's SDK found any error when collecting  picture
    func qitechIosFaceRecognitionController(_ faceRecognitionViewController: QITechIosFaceRecognitionController, didFailWithError error: QITechIosFaceRecognitionControllerError) {

    }

    // Do something if the user canceled the picture collection on any steps
    func qitechIosFaceRecognitionControllerDidCancel(_ faceRecognitionViewController: QITechIosFaceRecognitionController) {

    }
}
```

Para incorporar o SDK ao seu aplicativo você deve realizar a configuração do seu aplicativo de captura personalizado através da classe **QITechIosFaceRecognitionConfiguration** e depois instanciar o **ViewController QITechIosFaceRecognitionController** passando como argumento as configurações personalizadas.

Para iniciar o processo de análise de face, basta chamar a função _present_ para chamar o ViewController da QI Tech que realizará a coleta da selfie.

Importante implementar o _Delegate_ responsável por receber os retornos em caso de sucesso, erro ou no caso de o usuário interromper a jornada em qualquer etapa da validação.

Acima temos um exemplo completo da implementação.

---

# Coletando os Retornos do SDK

URL: /documentation/caas/face_recognition/web/collecting_response

## O método .initialize()

O método `.initialize()` é responsável pela inicialização do componente de reconhecimento facial e prova de vida. A partir de sua execução, o SDK carrega o modelo de detecção de face e valida as condições do dispositivo/navegador.

**Promise resolution:**

```javascript
{
  status: "SUCCESS",
  data: null
}
```

**Cenários de Rejection:**

- **Unsupported Browser:**

```javascript
{
  status: "FAILURE",
  reason: "UNSUPPORTED_BROWSER",
  description: "User browser is not supported."
}
```

- **Not Mobile Device:**

```javascript
{
  status: "FAILURE",
  reason: "NOT_MOBILE_DEVICE",
  description: "User device is not mobile."
}
```

- **Initialization Error:**

```javascript
{
  status: "FAILURE",
  reason: "INITIALIZATION_ERROR",
  description: "..."
}
```

## O método .open()

Este método recebe o `clientSessionKey` (obtido via chamada server-to-server) e inicia a interação com o usuário para a coleta da prova de vida. Retorna uma _Promise_ que é resolvida com a chave da imagem capturada assim que o fluxo é concluído.

**Promise resolution:**

```javascript
{
  status: "SUCCESS",
  data: string // image_key que identifica a imagem no servidor
}
```

Exemplo:

```javascript
{
  status: "SUCCESS",
  data: "d8a3b1c4-9e2f-47a5-8c3d-1b2e5..."
}
```

**Promise rejection:**

```javascript
{
  status: string;
  reason: string;
  description: string;
}
```

**Cenários de Rejection:**

- **User Canceled:**

```javascript
{
  status: "FAILURE",
  reason: "USER_CANCELED",
  description: "User pressed the back button."
}
```

- **Invalid Token:** (ocorre quando o `clientSessionKey` é inválido ou expirou)

```javascript
{
  status: "FAILURE",
  reason: "INVALID_TOKEN",
  description: "Authentication token expired or invalid"
}
```

- **Session Superseded:** (ocorre quando `.open()` é chamado novamente em uma instância já aberta)

```javascript
{
  status: "FAILURE",
  reason: "SESSION_SUPERSEDED",
  description: "A new session has been started before the previous one was completed."
}
```

---

# Implementação

URL: /documentation/caas/face_recognition/web/example

:::info Novidade na versão 4.0.0
A partir da versão **4.0.0**, o construtor `WebFaceRecon` não recebe mais o `hostComponent` — o SDK gerencia seu próprio nó DOM. O `client_session_key` continua sendo obrigatório e deve ser passado ao método `.open()`.
:::

A implementação é realizada instanciando `QITechWebFaceRecon.WebFaceRecon()`, encadeando as opções de configuração e chamando `.build()`. A inicialização ocorre em `.initialize()`, e a captura da prova de vida é iniciada com `.open(clientSessionKey)`.

## Obtendo o Client Session Key

Antes de chamar `.open()`, você deve gerar um **clientSessionKey** temporário via requisição server-to-server para a nossa API de face recognition.

### Endpoint

| Ambiente | URL |
|----------|-----|
| **Sandbox** | `https://api.sandbox.zaig.com.br/face_recognition/client_session` |
| **Produção** | `https://api.zaig.com.br/face_recognition/client_session` |

### Requisição

**Method:** `POST`

**Headers:**
```json
{
  "Authorization": "YOUR_FACE_RECON_API_KEY"
}
```

**Body (Opcional, mas recomendado):**
```json
{
  "user_id": "unique_user_identifier"
}
```

> **Importante:** O campo `user_id` é **altamente recomendado** para medidas de segurança e antifraude. Use um identificador único do usuário da sua aplicação.

### Resposta

```json
{
  "client_session_key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

## Exemplo completo

```html
<script src="https://facerecon.caas.qitech.app/face-recognition-4-2-1.js"></script>

<script>
  async function iniciarReconhecimentoFacial() {
    // 1. Obtenha o clientSessionKey via chamada server-to-server
    const clientSessionKey = await fetchClientSessionKey();

    // 2. Configure e instancie o SDK
    const webFaceRecon = new QITechWebFaceRecon.WebFaceRecon()
      .setThemeConfiguration({
        primaryColor:  "#2848A8",
        tertiaryColor: "#57D9FF",
        fontFamily:    "Verdana"
      })
      .setSandboxEnvironment()
      .setSessionId("UNIQUE_SESSION_ID")
      .build();

    // 3. Inicializa (valida browser/dispositivo e carrega modelo)
    await webFaceRecon.initialize();

    // 4. Inicia a captura da prova de vida
    const response = await webFaceRecon.open(clientSessionKey);
    console.log(`Status: ${response.status}, Key: ${response.data}`);
  }
</script>
```

## Versões anteriores

:::danger Aviso Importante!
Versões anteriores à **4.0.0** recebem o `hostComponent` como primeiro argumento do construtor. A partir da **3.0.0**, o `web_token` foi removido do construtor e o fluxo de `client_session_key` foi introduzido.
:::

```html
<script>
  // Versões 3.x
  var hostComponent = document.getElementById('webfacerecon');
  var webFaceRecon = new QITechWebFaceRecon.WebFaceRecon(hostComponent)
    .setThemeConfiguration({
      "buttonColor": "#2848A8",
      "fontColor": "#FFFFFF",
      "backgroundColor": "#FFFFFF"
    })
    .setSandboxEnvironment()
    .setSessionId('UNIQUE_SESSION_ID')
    .build();

  webFaceRecon.initialize()
    .then(() => fetchClientSessionKey())
    .then(clientSessionKey => webFaceRecon.open(clientSessionKey))
    .then(response => console.log(`Status: ${response.status}, Key: ${response.data}`))
    .catch(error => {
      console.error(error);
      alert(error.reason || error);
    });
</script>
```

---

# O construtor QITechWebFaceRecon.WebFaceRecon()

URL: /documentation/caas/face_recognition/web/example_zaigwebfacerecon

O método `.WebFaceRecon()` é responsável pela configuração da instância do seu componente de reconhecimento facial. A partir da versão **4.0.0**, o construtor não recebe mais parâmetros — a renderização é gerenciada internamente pelo SDK. Utilize os métodos encadeados abaixo para personalizar o comportamento:

| Nome | Descrição | Obrigatório |
|----------|----------|----------|
| `.setSandboxEnvironment()` | Configura o ambiente para modo Sandbox. | Não |
| `.setShowInvalidTokenScreen(Boolean)` | Define se a tela de falha de autenticação deve ser exibida. Padrão: `false`. | Não |
| `.setShowBackButton(Boolean)` | Define se o botão de voltar deve ser exibido (ao ser pressionado, encerra o fluxo). Padrão: `true`. | Não |
| `.setSessionId(String)` | Define a chave que identifica a sessão iniciada no SDK — usada para rastrear o fluxo do usuário nos logs. Aceita até 255 caracteres. | Não |
| `.setThemeConfiguration(object)` | Personaliza a identidade visual do SDK. | Não |
| `.setLogLevel(String)` | Nível de verbosidade dos logs. Opções: `"info"`, `"debug"`, `"warn"`, `"error"`. Padrão: `"info"`. | Não |
| `.setCameraNotAllowedErrorDescription(String)` | Mensagem customizada exibida quando o usuário nega permissão de câmera. | Não |

O método `.setThemeConfiguration` deve receber um objeto com os seguintes campos:

| Nome | Tipo | Descrição |
| -------- | -------- | -------- |
| primaryColor | String | Hexadecimal da cor principal do SDK (fundo, header). Caso não seja informada, o padrão é `#285BB8`. |
| tertiaryColor | String | Hexadecimal da cor dos botões de ação. Caso não seja informada, o padrão é `#57D9FF`. |
| fontFamily | String | _Font Family_ a ser configurada nos textos do SDK. Caso não seja informada, será utilizada a fonte padrão do sistema. |

## Versões Anteriores

:::danger Aviso Importante!
A partir da versão **4.0.0**, o parâmetro `hostComponent` e o `web_token` no construtor foram removidos. O SDK gerencia seu próprio nó DOM internamente.
:::

Nas versões anteriores a **4.0.0**, o construtor recebia os seguintes parâmetros posicionais:

| Nome | Descrição | Obrigatório |
|----------|----------|----------|
| hostComponent | Componente HTML pai que abrigava o HTML do SDK. | Sim |
| web_token | Chave do cliente enviada pela QI Tech. | Sim (versões < 3.0.0) |

---

# Importando a biblioteca

URL: /documentation/caas/face_recognition/web/import

Para importar nossa biblioteca, adicione o endereço da nossa biblioteca em uma TAG **src** no HTML de seu website:

```html
<script src="https://facerecon.caas.qitech.app/face-recognition-4-2-1.js"></script>
```

---

# Introdução

URL: /documentation/caas/face_recognition/web/introduction

Bem vindo ao manual de integração do Web Face Recognition da QI Tech! Esta biblioteca realiza a captura de face e seu envio para a API de Face Recognition da QI Tech . Você pode utilizar esta biblioteca para capturar através do seu website uma imagem do rosto de um cliente e referenciá-lo através de uma chave nos demais produtos do sistema QI Tech.

Neste passo a passo você encontrará detalhes da biblioteca bem como um exemplo de implementação em javascript. Com isso você possui as ferramentas necessárias para poder adequar ao caso de uso da sua aplicação.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. 

* Produção
* Sandbox

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

A seleção é realizada por meio do método `.setSandboxEnvironment()` durante a configuração do SDK, que irá alterar o ambiente para Sandbox. Caso o método não seja chamado, o ambiente de produção será utilizado.

---

# Registro de Rosto e Validação 1:1

URL: /documentation/caas/face_recognition/web/registration_and_validation

:::danger Funcionalidade Descontinuada
Os métodos `.setDocumentNumber()` e `.setValidation()` foram descontinuados e removidos do Web Face Recognition SDK. O fluxo de registro e validação 1:1 via SDK Web não é mais suportado em nenhuma versão.

Para realizar registro e validação de face, utilize diretamente a [API de Face Recognition](https://docs.qitech.com.br/documentation/caas/face_recognition/api/face_registration).
:::

---

# Status HTTP

URL: /documentation/caas/limits/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/limits/introduction

Bem vindo à API de Limites Pix da QI Tech! Você pode utilizar a nossa API para gerenciar os seus limites pix:
- Cadastrar novos limites pix;
- Modificar limites pix pré-existentes;
- Recuperar limites pix pré-existentes.

Abaixo, você pode observar a implementação da API utilizando cUrl. Com isso você possui exemplos para poder adaptar adequadamente à linguagem de programação da sua preferência.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/limits_pix/`
* Sandbox - `https://api.sandbox.caas.qitech.app/limits_pix/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

No ambiente de Sandbox, as análises enviadas não são cobradas e são respondidas de acordo com regras pré estabelecidas.

Para a análise de uma transação, a seguinte regra é aplicada sobre o valor da transação:

Mínimo | Máximo | Decisão
------ | ------ | -------
0 | 1000 | Aprovado Automaticamente
1001 | 2000 | Derivado para análise manual - Posteriormente aprovado
2001 | 3000 | Derivado para análise manual - Posteriormente reprovado
3001 | 4000 | Reprovado Automaticamente
4001 | 5000 | Não analisado
5001 | - | Pendente

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

## Autenticação

> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE_API_KEY"
```

> Substitua a API key 'EXAMPLE_API_KEY' com a sua chave adquirida com o nosso suporte.

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE_API_KEY`

:::info **Atenção**

Você deve substituir EXAMPLE_API_KEY com a API Key recebida do suporte.
:::

---

# Cadastro de Novo Limite

URL: /documentation/caas/limits/limit_registration

Para realizar o cadastro de um novo limite, basta enviar um objeto do tipo _Account_ ao seguinte endpoint:

`POST https://api.caas.qitech.app/limits_pix/account`

<!-- Ao final do cadastro de uma pessoa física em sua plataforma, é necessário executar a avaliação de fraude e de KYC deste cliente, o que deve ser realizado através do endpoint de Natural Person. Os dados enviados deverão ser os dados finais, que não serão alterados em hipótese alguma, isto é, não deverá existir a possibilidade de se realizar uma alteração nos dados básicos de cadastro como CPF, Nome, Data de Nascimento e outros após este processo. Isto é muito importante para garantir dois pontos:

* Consistência dos dados na base de dados do Antifraude
* Avaliação realista do risco, evitando fraudes em momentos posteriores da operação -->

> Exemplo

```json
{
    "account_id": "5ce7fab5-8165-44a5-9b89-bb2d6d61e4f4",
    "registration_date": "2019-12-20T15:23:12",
    "limit": {
        "withdraw": {
            "daytime" : {
                "start_time": "06:00:00-03:00",
                "amount": 500000
            },
            "nighttime" : {
                "start_time": "20:00:00-03:00",
                "amount": 300000
            }
        },
        "change": {
            "daytime" : {
                "start_time": "06:00:00-03:00",
                "amount": 500000
            },
            "nighttime" : {
                "start_time": "20:00:00-03:00",
                "amount": 300000
            }
        },
        "transaction_natural_person": {
            "daytime" : {
                "start_time": "06:00:00-03:00",
                "amount": 500000
            },
            "nighttime" : {
                "start_time": "20:00:00-03:00",
                "amount": 300000
            }
        },
        "transaction_legal_person": {
            "daytime" : {
                "start_time": "06:00:00-03:00",
                "amount": 500000
            },
            "nighttime" : {
                "start_time": "20:00:00-03:00",
                "amount": 300000
            }
        }
    }
}
```

Todas as trocas de informação de um cadastro utilizam a seguinte definição para este objeto. Em alguns casos, para facilitar a implementação e diminuir o fluxo de dados entre as partes, algumas informações poderão ser omitidas.

nome | tipo | descrição
:----: | :----: | ---------
account_id | string | Identificador único da conta. **É essencial que este número seja único para cada requisição**
registration_date |	string (ISO 8601) | Data e hora do cadastro.
limit |	limit | 	Objeto do tipo _limit_.

## Objeto Limit

```json
{
    "withdraw": {
        "daytime" : {
            "start_time": "06:00:00-03:00",
            "amount": 500000
        },
        "nighttime" : {
            "start_time": "20:00:00-03:00",
            "amount": 300000 
        }
    },
    "change": {
        "daytime" : {
            "start_time": "06:00:00-03:00",
            "amount": 500000
        },
        "nighttime" : {
            "start_time": "20:00:00-03:00",
            "amount": 300000 
        }
    },
    "transaction_natural_person": {
        "daytime" : {
            "start_time": "06:00:00-03:00",
            "amount": 500000
        },
        "nighttime" : {
            "start_time": "20:00:00-03:00",
            "amount": 300000 
        }
    },
    "transaction_legal_person": {
        "daytime" : {
            "start_time": "06:00:00-03:00",
            "amount": 500000
        },
        "nighttime" : {
            "start_time": "20:00:00-03:00",
            "amount": 300000 
        }
    }
}
```

Este objeto representa os limites de valores aplicáveis aos diferentes tipos de transações em diferentes momentos do dia, levando em consideração a divisão de períodos diurno e noturno.

O objeto está organizado em quatro categorias principais (ou tipos de limites): "withdraw" (referente a modalidade PIX Saque), "change" (referente a modalidade PIX troco), "transaction_natural_person" (referente a modalidade PIX transacional para pessoas físicas) e "transaction_legal_person" (referente a modalidade PIX transacional para pessoas jurídicas). Cada categoria contém 2 períodos, "daytime" e "nighttime", representando respectivamente os períodos diurno e noturno, descrevendo o horário de início e os respectivos limites de valores a ser aplicados para a modalidade. Vale citar que as 4 categorias de PIX do objeto limit são obrigatórias, devendo estar presentes no momento de criação da conta.

Estrutura de uma Janela de Limite:

nome |	tipo |	descrição
:----: | :----: | ---------
start_time |	string (ISO 8601) |	Indica o momento em que os limites de valor para transações PIX são aplicados. Atente-se para a configuração correta do início da Janela de Limite de acordo com o fuso horário que pretende utilizar.
amount |	inteiro |	Valor do limite máximo permitido para a modalidade no período especificado pelo "start_time" em centavos de reais.

Uma vez que, de acordo com as diretrizes do Banco Central, as janelas diurnas de limites PIX devem iniciar obrigatoriamente às 6AM, apenas o valor "06:00:00-03:00" será atualmente aceito para configuração do start_time destas janelas.

De maneira similar, já que as janelas noturnas de limites PIX devem iniciar às 8PM ou às 10PM, apenas os valores "20:00:00-03:00" e "22:00:00-03:00" serão aceitos para configuração do start_time destas janelas.

*Exemplo de Uso:*
Suponhamos que o usuário esteja realizando uma transação PIX para pessoa física no horário 12:00:00-03:00. Ao consultar o objeto, localizamos a categoria "transaction_natural_person". Nessa categoria, encontramos os 2 períodos, "daytime" e "nighttime": o primeiro inicia em "06:00:00-03:00" e o segundo inicia em "20:00:00-03:00". Se a transação for realizada entre esses horários, o limite máximo de valor permitido é de 5.000,00 (cinco mil) reais, conforme especificado na primeira janela  de limite.

No entanto, caso a transação ocorra após "20:00:00-03:00" e antes do próximo horário de início (neste exemplo, às 06:00 do dia seguinte), o limite máximo de valor permitido será de 3.000,00 (três mil) reais, conforme indicado na segunda janela (janela noturna) de limite.

# Criando uma Proposta de Modificação de Limite

Para solicitar uma modificação de um limite, basta enviar um objeto do tipo Limit ao seguinte endpoint:

`POST https://api.caas.qitech.app/limits_pix/account/{account_id}/limit_update_request`

> Exemplo

```json
{
    "withdraw": {
        "daytime" : {
            "start_time": "06:00:00-03:00",
            "amount": 500000
        },
        "nighttime" : {
            "start_time": "20:00:00-03:00",
            "amount": 300000 
        }
    },
    "change": {
        "daytime" : {
            "start_time": "06:00:00-03:00",
            "amount": 550000
        },
        "nighttime" : {
            "start_time": "20:00:00-03:00",
            "amount": 350000 
        }
    },
    "transaction_natural_person": {
        "daytime" : {
            "start_time": "06:00:00-03:00",
            "amount": 500000
        },
        "nighttime" : {
            "start_time": "20:00:00-03:00",
            "amount": 300000 
        }
    }
}
```

O retorno da requisição será composto por uma lista com todas as modificações que foram realizadas, separados por período e por categoria de limite PIX. No caso do exemplo acima, as alterações foram realizadas na categoria "change" (PIX Troco) com a requisição para aumento do limite de ambos os periodos. Portanto a resposta da requisição será a seguinte:

```json
{   "limit_update_requests" : [
        { 
            "limit_update_request_id": "5ce7fab5-8165-44a5-9b89-bb2d6d61e4f4",
            "analysis_status": "automatically_approved",
            "client_notification_status": "not_applicable",
            "limit_update_request_status": "applied",
            "limit_update_request_type" : "change_daytime",
            "event_date": "2019-10-01T10:37:25-03:00"
        },
        { 
            "limit_update_request_id": "5ce7fab5-8165-44a5-9b89-bb2d6d61e4f4",
            "analysis_status": "automatically_approved",
            "client_notification_status": "not_applicable",
            "limit_update_request_status": "applied",
            "limit_update_request_type" : "change_nighttime",
            "event_date": "2019-10-01T10:37:25-03:00"
        },
    ]
}
```

nome |	tipo |	descrição
:----: | :----: | ---------
limit_update_request_id |	string |	Identificador único da Proposta de Modificação de Limite
analysis_status |	string |	Enumerador do analysis_status da proposta
client_notification_status |	string |	Enumerador do client_notification_status da proposta
limit_update_request_status |	string |	Enumerador do limit_update_request_status da proposta
limit_update_request_type |	  string |	Enumerador do limit_update_request_type da proposta
event_date |	string (ISO 8601) |	Data e hora da criação da Proposta de Modificação de Limite

Para um melhor entendimento dos status de retorno acesse dinâmica de status .

---

# Criando uma lista de beneficiários

URL: /documentation/caas/limits/recipient_list

Conforme regulamentação de limites PIX do Banco Central, é possível realizar a criação de uma lista de beneficiários que utilizarão o mesmo
limite diferenciado.

Para solicitar a criação de uma lista de beneficiários para uma conta, basta enviar um objeto do tipo Limite ao seguinte endpoint:

`POST https://api.caas.qitech.app/limits_pix/account/{account_id}/recipient_list`

```json
{
    "limit" : {
        "transaction": {
            "daytime" : {
                "start_time": "06:00:00-03:00",
                "amount": 60000
            },
            "nighttime" : {
                "start_time": "20:00:00-03:00",
                "amount": 60000 
            }
        }
    }
}
```

Que apresentará o seguinte retorno:

```json
{
    "event_date": "2019-10-01T10:37:25-03:00"
}
```

nome |	tipo |	descrição
:----: | :----: | ---------
event_date |	string (ISO 8601) |	Data e hora da criação da Lista de Beneficiários

# Adicionando um novo Beneficiário a lista de Beneficiários

Para adicionar um novo beneficiário a uma lista de beneficiários previamente criada, é necessário apenas realizar a seguinte requisição:

`POST https://api.caas.qitech.app/limits_pix/account/{account_id}/recipient_list/recipient`

```json
{
    "document_number": "123.456.789-10"
}
```

Que apresentará o seguinte retorno:

```json
{
    "recipient_id": "c7a79970-b558-4425-998a-5cd6747c1c90",
    "analysis_status": "automatically_approved",
    "client_notification_status": "awaiting_notification_period",
    "recipient_status": "created",
    "event_date": "2019-10-01T10:37:25-03:00"
}
```

nome |	tipo |	descrição
:----: | :----: | ---------
recipient_id |	string |	Identificador único do Beneficiário desta Proposta de Modificação de Limite
analysis_status |	string |	Enumerador do analysis_status da proposta
client_notification_status |	string |	Enumerador do client_notification_status da proposta
recipient_status |	string |	Enumerador do recipient_status da proposta
event_date |	string (ISO 8601) |	Data e hora da criação da Proposta de Modificação de Limite

Para um melhor entendimento dos status de retorno acesse dinâmica de status .

# Removendo um Beneficiário

Para remover um beneficiário específico para uma conta, basta enviar uma requisição do tipo DELETE para o seguinte endereço:

`DELETE https://api.caas.qitech.app/limits_pix/account/{account_id}/recipient_list/recipient/{recipient_id}`

# Editando os Limites de uma lista de Beneficiários

Para solicitar a alteração dos limites de beneficiário de uma dada conta, basta realizar o envio da seguinte requisição:

`POST https://api.caas.qitech.app/limits_pix/account/{account_id}/recipient_list/limit_update_request`

```json
{
    "limit" : {
        "transaction": {
            "daytime" : {
                "start_time": "06:00:00-03:00",
                "amount": 70000
            },
            "nighttime" : {
                "start_time": "20:00:00-03:00",
                "amount": 70000 
            }
        }
    }
}
```

O retorno da requisição será composto por uma lista com todas as modificações que foram realizadas, separados por período. No caso do exemplo acima, as alterações foram realizadas na categoria "transaction" com requisição para aumento do limite de ambos os periodos. Portanto a resposta da requisição será a seguinte:

```json
{   "recipient_list_limit_update_requests" : [
        { 
            "limit_update_request_id": "c7a79970-b558-4425-998a-5cd6747c1c90",
            "analysis_status": "automatically_approved",
            "client_notification_status": "awaiting_notification_period",
            "recipient_status": "created",
            "recipient_list_limit_update_request_type" : "transaction_daytime",
            "event_date": "2019-10-01T10:37:25-03:00"
        },
        { 
            "limit_update_request_id": "c7a79970-b558-4425-998a-5cd6747c1c90",
            "analysis_status": "automatically_approved",
            "client_notification_status": "awaiting_notification_period",
            "recipient_status": "created",
            "recipient_list_limit_update_request_type" : "transaction_nighttime",
            "event_date": "2019-10-01T10:37:25-03:00"
        },
    ]
}
```

nome |	tipo |	descrição
:----: | :----: | ---------
recipient_id |	string |	Identificador único do Beneficiário desta Proposta de Modificação de Limite
analysis_status |	string |	Enumerador do analysis_status da proposta
client_notification_status |	string |	Enumerador do client_notification_status da proposta
recipient_status |	string |	Enumerador do recipient_status da proposta
recipient_list_limit_update_request_type |	  string |	Enumerador do recipient_list_limit_update_request_type da proposta
event_date |	string (ISO 8601) |	Data e hora da criação da Proposta de Modificação de Limite

---

# Padrões

URL: /documentation/caas/limits/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões que são seguidos em toda a API.

## Valores Monetários
> Exemplos:

```
10000
12345
98741
1223
1
0
```

As APIs assumem que todos os valores monetários enviados são em Reais Brasileiros. Os valores devem ser enviados como inteiro em centavos.

## Data e Hora com Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12-03:00
2018-05-01T13:32:11+00:00
2019-05-01T00:00:00+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será valido. Por exemplo, se um aluguel estiver marcado para começar às 09:30 no aeroporto de Brasília, o horário enviado deverá ser representado por 09:30-03:00, se o aluguel estiver marcado para começar às 09:30 em Manaus, deverá ser representado por 09:30-04:00.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss±hh:mm`

## Data e Hora sem Fuso Horario
> Alguns exemplos:

```
2019-10-15T22:35:12Z
2018-05-01T13:32:11Z
2019-05-01T00:00:00Z
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão ser enviados sem ele, sempre em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ssZ`

## Data
> Alguns exemplos

``` 
2019-10-15
2019-01-01
2017-03-20
```

No caso de campos que recebem somente data, uma data de nascimento, por exemplo, somente a data, sem nenhum horário deve ser enviada com o seguinte formato:

`YYYY-MM-dd`
 

## Documentos
Uma vez que os números de documento são bastante variados e muitos deles possuem caracteres que não se enquadram como numéricos, definem-se todos os números de documento como string. Outro bom motivo para definí-los como string é evitar que os zeros à esquerda desapareçam. Documentos previstos nesta página possuem uma máscara bem definida e estarão sujeitos a validação. O restante dos documentos, como RG, dada sua falta de padronização, não serão validados.

## CPF

> Exemplos de CPFs válidos contra a máscara definida:

```
123.456.789-12
321.987.543-23
111.283.333-00
```

> Exemplos de CPFs inválidos contra a máscara definida:

```
8.577.477-8
08.104.627/0001-23
123.456.789-1
23.456.789-01
```

O CPF é sempre definido como uma string e será validado conta a máscara:

`###.###.###-##`

## CNPJ

> Exemplos de CNPJs válidos contra a máscara definida:

```
08.104.627/0001-02
01.079.210/0114-67
32.402.502/0001-35
```

> Exemplos de CNPJs inválidos contra a máscara definida:

```
8.577.477-8
123.456.789-12
321.987.543-23
32.402.502/0001-3
032.402.502/0001-3
```

O CNPJ é sempre definido como uma string e será validado conta a máscara:

`##.###.###/####-##`

## IP

> Exemplos de IPs válidos contra a máscara definida:

```
201.81.161.86
201.081.161.86
201.81.161.086
201.81.0.1
```

> Exemplos de IPs inválidos:

```
201.81..86
358.81.161.86
201.81.161
```

IPs deverão ser enviados sempre em IPv4, zeros à esquerda poderão ou não ser enviados, respeitando a seguinte máscara:

`###.###.###.###`

---

# Dinâmica dos Status

URL: /documentation/caas/limits/status_dynamics

## Status de Análise (analysis_status)

O "analysis_status" indica o status da decisão da Política de Limites.

Os possíveis valores do "analysis_status" são os seguintes:

analysis_status | Descrição
:---------: | ---------
automatically_approved | a Política de Limites aprovou automaticamente esta solicitação de modificação de limite.
automatically_reproved | a Política de Limites reprovou automaticamente esta solicitação de modificação de limite.
in_manual_analysis | a Política de Limites delegou esta solicitação de modificação de limite para análise manual de mesa.
manually_approved | Após análise manual, o analista decidiu aprovar a modificação de limite.
manually_reproved | Após análise manual, o analista decidiu reprovar a modificação de limite.
reproved_by_time | A requisição foi reprovada pois o tempo de análise expirou.
pending | A requisição está pendente para ser processada.

## Status de Notificação do Cliente (client_notification_status)

O "client_notification_status" está relacionado ao período em que o cliente deve ser notificado sobre o andamento da solicitação de modificação de limite.

client_notification_status | Descrição
:---------: | ---------
awaiting_notification_period | Indica que a Janela de tempo para notificação do cliente ainda não iniciou.
in_notification_period | Indica que estamos na Janela de tempo para notificação do cliente.
notification_period_expired | Indica que a Janela de tempo para notificação do cliente já expirou.

## Status de Alteração de Limite (limit_update_request_status)

O "limit_update_request_status" está relacionado ao status da solicitação de modificação de limite.

limit_update_request_status | Descrição
:---------: | ---------
created | Indica que a requisição de mudança de limite foi criada.
applied | Indica que a requisição de mudança de limite foi aplicada.
canceled | Indica que a requisição de mudança de limite foi cancelada.

## Status de Alteração na lista de Beneficiários (recipient_list_append_request_status)

O "recipient_list_append_request_status" está relacionado ao status da solicitação de modificação na lista de beneficiários.

recipient_list_append_request_status | Descrição
:---------: | ---------
created | Indica que a requisição de mudança na lista de beneficiários foi criada.
applied | Indica que a requisição de mudança na lista de beneficiários foi aplicada.
canceled | Indica que a requisição de mudança na lista de beneficiários foi cancelada.

---

# Webhook

URL: /documentation/caas/limits/webhook

Webhook

Atualizações no status de fraude (Para Orders que sejam derivados para análise manual ou que sejam respondidos como Pendente) e para Sellers bloqueados, são notificados por meio de Webhook. Para tanto, é necessário, por meio da equipe do [suporte](mailto:suporte.caas@qitech.com.br), configurar um endereço do endpoint por onde vamos notificar as atualizações e também uma *signature_key* que será utilizada para assinar a requisição. Vale ressaltar que todos os envios de webhook serão feitos para um único endpoint.

No caso da atualização do status do pedido, o cliente pode também utilizar a técnica de [polling](https://en.wikipedia.org/wiki/Polling_(computer_science)). Neste caso, basta não configurar o endpoint de webhook e utilizar os endpoints de recuperação de Order para proceder com o polling.

:::info **Atenção**

Por questões de segurança, todas as requisições de Webhook serão somente realizadas em endpoints servidos por HTTPS.
:::

## Assinatura do Webhook

## Webhook de Atualização de Evento

Request Body

```json
    {
        "id": "123456",
        "analysis_status": "automatically_approved",
        "event_date": "2019-10-01T10:37:25-03:00"
    }
```

A requisição de atualização do status de análise de um evento possui o formato acima e notifica a mudança no status de fraude. O método utilizado é um PUT e o endereço do endpoint pode conter também o id do evento, de acordo com a necessidade do cliente. É importante ressaltar que o corpo da requisição é enviado como texto codificado em UTF-8.

## Retentativas

A notificação é considerada realizada quando recebe como resposta um HTTP Status 200. Caso as notificações falhem, serão feitas 7 retentativas, com os seguintes intervalos, até que um 200 seja retornado ou as tentativas terminem:

* 10 segundos
* 40 segundos
* 160 segundos
* 640 segundos
* 2560 segundos
* 10240 segundos
* 40960 segundos

---

# Coletando os Retornos

URL: /documentation/caas/ocr/android/collecting_response

Para obter o objeto **RequestResponseObject**, que contém as capturas obtidas pelo SDK, sobrescreva o método *onActivityResult* na mesma *activity* que você iniciou a **DocumentRecognitionActivity**:

```java
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        DocumentRecognition.RequestResponseObject result;
        if (requestCode == REQUEST_CODE){
            if (resultCode == RESULT_OK && data != null){
                DocumentRecognition.RequestResponseObject mRequestResponseObject = data.ParcelableExtra("result");
            }
        }
    }
```

### Descrição dos Atributos do Objeto RequestResponseObject

Atributo | Descrição
--------- | ---------
ocr_key | Chave de identificação da imagem fornecida que pode ser utilizada em qualquer outro serviço do sistema QI Tech.
template | Identifica a qual foto aquela OCR Key se refere.

---

# DocumentRecognitionStep

URL: /documentation/caas/ocr/android/document_step

O fluxo de captura de documentos que o usuário será submetido é definido através de um array de objetos do tipo **DocumentRecognitionStep** (disponível no SDK), em que cada elemento é um dos passos de captura realizado pelo usuário. 

```java
DocumentSteps = new DocumentRecognitionStep[]{
        new DocumentRecognitionStep(Document.cnh_front),
        new DocumentRecognitionStep(Document.cnh_back)
};
```

Acima, é implementado um fluxo que coletará do usuário primeiro a frente de seu CNH (cnh_front) e, depois de validada a coleta de uma foto de qualidade, o verso do CNH.

O objeto DocumentRecognitionStep pode assumir os seguintes valores:

```java
public enum Document {
    cnh, // Carteira Nacional de Habilitação brasileira completa
    cnh_front, // Carteira Nacional de Habilitação brasileira frente (Lado da foto)
    cnh_back, // Carteira Nacional de Habilitação brasileira frente (Lado da assinatura)
    cnh_digital, // PDF da Carteira Nacional de Habilitação brasileira digital
    rg_front, // Carteira de Identidade brasileira frente (Lado da foto)
    rg_back, // Carteira de Identidade brasileira verso (Lado dos dados)
    proof_of_address, // Comprovante de Residência
    other // Outros documentos de identificação
}
```

---

# Soluções híbridas

URL: /documentation/caas/ocr/android/hybrid_solutions

Além de oferecer integração nativa em Java, nossas SDKs também são compatíveis com diversos frameworks híbridos. Isso é possível através da integração de plugins nativos específicos para cada um desses frameworks. Utilizando o sistema nativo de cada solução, é viável incorporar nosso SDK nativa no ambiente Android.

Algumas das tecnologias híbridas mais utilizadas são o React Native ([Native Modules](https://reactnative.dev/docs/turbo-native-modules-introduction)), Cordova ([Plugin Development Guide](https://cordova.apache.org/docs/en/latest/guide/hybrid/plugins/index.html)), Ionic ([Native](https://ionicframework.com/docs/v3/native/)), Unity ([Native Plug-in para Android](https://docs.unity3d.com/Manual/PluginsForAndroid.html)), Xamarin ([Native Libraries](https://learn.microsoft.com/en-us/xamarin/android/platform/native-libraries)), Appcelerator, Phonegap e Node.

Para facilitar o processo de integração com nossas soluções nativas, disponibilizamos plugins para os frameworks React Native e Flutter. Caso tenha interesse, provemos a documentação e um exemplo de integração em nossos repositórios privados. Para as demais tecnologias híbridas, temos alguns exemplos de implementação dessa ponte para o código nativo. Fique à vontade para entrar em contato com nosso suporte para obter acesso.

---

# Introdução

URL: /documentation/caas/ocr/android/introduction

Bem vindo ao SDK Android de OCR (Optical Character Recognition) para leitura de documentos da QI Tech. Este SDK realiza a captura de documentos e envio a API de OCR da QI Tech . Você pode utilizá-lo para capturar através do seu aplicativo uma imagem de um documento de seu cliente a ser reconhecido, como uma Carteira de Habilitação ou Cédula de identidade, e referenciá-lo através de uma chave nos demais produtos do sistema QI Tech.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso [suporte](mailto:suporte.caas@qitech.com.br) e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

---

# Integração nativa

URL: /documentation/caas/ocr/android/native_java

Para importar nossas SDKs, é necessário realizar alteração no _build.gradle_ de Projeto e de Aplicativo.

## Adicionando ao Projeto

Adicione o endereço de nosso repositório maven no _build.gradle_ do projeto (no Android Studio este arquivo aparece como: **"Project: \{nome_do_projeto\}"**), conforme exemplo abaixo.

```java
maven { url 'https://sdks.qitech.com.br/' }
```

## Adicionando ao Aplicativo

Após isso, adicione a biblioteca que você pretende importar em seu build.gradle do app (no Android Studio este arquivo aparece como: **"Module: \{nome_do_projeto\}.app"**), incluindo a dependência apresentada abaixo.

```java
dependencies {
    implementation 'com.qitech.android:documentrecognition:v5.0.0'
}
```

:::warning
Desde **abril de 2025**, novas políticas da Google Play requerem **Android API Level 35** para que aplicativos possam ser publicados
ou atualizados na Google Play Store. Por isso recomendamos fortemente que utilize **targetSdkVersion na versão 35** pelo menos.
:::

:::info
A utilização de **targetSdkVersion 35** implica na utilização do **compileSdkVersion 35**, o que desencadeia alguns **requisitos mínimos** para ferramentas
do ecossistema do Android:
* compileSdkVersion 35 --> AGP 8.6.0
* AGP 8.6.0 --> Gradle 8.7
* AGP 8.6.0 --> Java 17 (JDK 17)
* AGP 8.6.0 --> Kotlin 2+
:::

## Iniciando o SDK

Para incorporar o SDK ao seu aplicativo você deve realizar a configuração do seu aplicativo de captura personalizado através de um componente Builder e submetê-lo como parâmetro via Intent Extra para a DocumentRecognitionActivity.

```java
Intent intent = new Intent(context, DocumentRecognitionActivity.class);

var onboardingTextConfiguration = new OnboardingTextConfiguration(
    "Conselhos relevantes",                   // Título
    "Esteja com o documento visível",         // Primeira Instrução
    "Encaixe seu documento nas marcas",       // Segunda Instrução
    "Retire o plastico que cobre o documento" // Terceira Instrução
);

DocumentRecognition mDocumentRecognition = new DocumentRecognition.Builder(sand_mobile_token)
    .setDocumentSteps(DocumentSteps)
    .setSandboxEnvironment()
    .setSessionId("SESSION_ID")
    .setFontColor("#000000")
    .setBackgroundColor("#FFFFFF")
    .setFontFamily(DocumentRecognition.FontFamily.open_sans)
    .setShowIntroductionScreens(true)
    .setShowSuccessScreen(true)
    .setOnboardingTextConfiguration(onboardingTextConfiguration)
    .setLogLevel(DocumentRecognition.LogLevel.debug)
    .build();

intent.putExtra("settings", mDocumentRecognition);
startActivityForResult(intent, REQUEST_CODE);
```

**Versões anteriores à v4.0.0**
    ```java
    Intent intent = new Intent(context, DocumentRecognitionActivity.class);

    VisualConfiguration visualConfiguration = new VisualConfiguration()
            .setOnboardingDrawable(R.drawable.introscreen,500)
            .setDocumentFrontDrawable(R.drawable.documentfront, 500)
            .setDocumentBackDrawable(R.drawable.documentback, 500);

    TextConfiguration textConfiguration = new TextConfiguration()
            .setCustomText(TextConfiguration.CustomLabel.onboardingTitle, "Vamos começar!")
            .setCustomText(TextConfiguration.CustomLabel.onboardingFirstLabel, "- Vá para um local iluminado")
            .setCustomText(TextConfiguration.CustomLabel.onboardingSecondLabel, "- Retire o documento do plástico")
            .setCustomText(TextConfiguration.CustomLabel.onboardingThirdLabel, "- Insira seu documento na moldura, aguardando que fique verde para realizar a captura.");

    DocumentRecognition mDocumentRecognition = new DocumentRecognition.Builder("YOUR_MOBILE_TOKEN_SENT_BY_QITECH")
            .setDocumentSteps(DocumentSteps)
            .setVisualConfiguration(visualConfiguration)
            .setTextConfiguration(textConfiguration)
            .showIntroductionScreens(true)
            .setShowSuccessScreen(false)
            .setBackgroundColor("#000000")
            .setFontColor("#FFFFFF")
            .setFontFamily(DocumentRecognition.FontFamily.open_sans)
            .setSessionId("SESSION_ID")
            .setLogLevel(DocumentRecognition.LogLevel.debug)
            .build();
    intent.putExtra("settings", mDocumentRecognition);
    startActivityForResult(intent, REQUEST_CODE);
    ```

Utilizamos um Mobile Token para permitir o acesso autenticado do seu aplicativo a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso ainda não tenha recebido o seu token, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber o Mobile Token em todas as requisições ao nosso servidor vindas do SDK, portanto, este deve ser obrigatoriamente incluido como parâmetro de configuração através do método mencionado anteriormente.

:::info **Atenção**

Você deve substituir "YOUR_MOBILE_TOKEN_SENT_BY_QITECH" com o Mobile Token recebido do suporte.
:::

## DocumentRecognition.Builder

| Parâmetro | Função | Obrigatório |
|------------|--------------|--------------|
|mobileToken |Chave do cliente que identifica que os dados coletados são provenientes do seu aplicativo. Caso ainda não tenha recebido o seu mobile-token, entre em contato com o mailto: suporte.caas@qitech.com.br.|Sim.|
|.setDocumentSteps(DocumentRecognitionStep[] documentSteps)|Define o fluxo de captura de documentos realizado pelo usuário. Mais informações [aqui](/documentation/caas/ocr/android/document_step)|Sim.|
|.setSandboxEnvironment()|Caso este parâmetro seja utilizado no construtor, a biblioteca será configurada para enviar os dados ao ambiente de sandbox. Caso ausente, as requisições são enviadas para o ambiente production.|Não.|
|.setSessionId(String sessionId)| Utilizado para definir a chave que identifica a sessão iniciada no SDK. É usada para rastrear todo fluxo percorrido pelo usuário na execução da OCR através de logs. Este campo aceita até 255 caracteres. |Não.|
|.setFontColor(String fontColor)|Permite a configuração da cor da fonte e dos ícones das activities do SDK.|Não. O padrão é "#1C49A5".|
|.setBackgroundColor(String backgroundColor)|Permite a configuração da cor de background das activities do SDK.|Não. O padrão é "#FCFCFC".|
|.setFontFamily(FontFamily fontFamily)| Permite a configuração da fonte das activities do SDK.| Não. Caso não seja informada o padrão é FontFamily.open_sans. Fontes disponíveis: FontFamily.open_sans, FontFamily.futura, FontFamily.verdana, FontFamily.roboto, FontFamily.poppins e FontFamily.helvetica.|Não.|
|.showIntroductionScreens(Boolean showIntroductionScreens)|Quando "false" desativa as telas de introdução à coleta de foto do documento que aparecem para o usuário.|Não. O padrão é "true".|
|.setShowSuccessScreen(Boolean showSuccessScreen)|Quando "false" desativa a tela de sucesso após a coleta da foto.|Não. O padrão é "true".|
|.setOnboardingTextConfiguration(OnboardingTextConfiguration onboardingTextConfiguration) |Permite a customização das instruções na tela de introdução. | Não.|
|.setLogLevel(DocumentRecognition.LogLevel logLevel)| Utilizado para customizar o nível de verbosidade dos logs do SDK. Níveis disponíveis: LogLevel.debug, LogLevel.info, LogLevel.warn, LogLevel.error e LogLevel.trace. O padrão é LogLevel.debug. |Não.|

**Versões anteriores à v4.0.0**
    | Parâmetro | Função | Obrigatório |
    |------------|--------------|--------------|
    |mobileToken |Chave do cliente que identifica que os dados coletados são provenientes do seu aplicativo. Caso ainda não tenha recebido o seu mobile-token, entre em contato com o mailto: suporte.caas@qitech.com.br.|Sim.|
    |.setDocumentSteps(DocumentRecognitionStep[] documentSteps)|Define o fluxo de captura de documentos realizado pelo usuário. Mais informações [aqui](/documentation/caas/ocr/android/document_step)|Sim.|
    |.setSandboxEnvironment()|Caso este parâmetro seja utilizado no construtor, a biblioteca será configurada para enviar os dados ao ambiente de sandbox. Caso ausente, as requisições são enviadas para o ambiente production.|Não.|
    |.showIntroductionScreens(Boolean showIntroductionScreens)|Quando "false" desativa as telas de introdução à coleta de foto do documento que aparecem para o usuário.|Não. O padrão é "true".|
    |.setShowSuccessScreen(Boolean showSuccessScreen)|Quando "false" desativa a tela de sucesso após a coleta da foto.|Não. O padrão é "true".|
    |.setBackgroundColor(String backgroundColor)|Permite a configuração da cor de background das activities do SDK.|Não. O padrão é "#ffffff".|
    |.setFontColor(String fontColor)|Permite a configuração da cor da fonte e dos ícones das activities do SDK.|Não. O padrão é "#000000".|
    | .setFontFamily(FontFamily fontFamily)| Permite a configuração da fonte das activities do SDK.| Não. Caso não seja informada o padrão é FontFamily.open_sans. Fontes disponíveis: FontFamily.open_sans, FontFamily.futura, FontFamily.verdana, FontFamily.roboto, FontFamily.poppins e FontFamily.helvetica.|Não.|
    |.setVisualConfiguration(VisualConfiguration visualConfiguration)| Utilizado para customizar as imagens mostradas para o usuário ao longo da execução do SDK.|Não.|
    |.setTextConfiguration(TextConfiguration textConfiguration) | Utilizado para customizar os textos da tela introdutória de onboarding mostradas para o usuário ao longo da execução do SDK.|Não.|
    |.setSessionId(String sessionId)| Utilizado para definir a chave que identifica a sessão iniciada no SDK. É usada para rastrear todo fluxo percorrido pelo usuário na execução da OCR através de logs. Este campo aceita até 255 caracteres. |Não.|
    |.setLogLevel(DocumentRecognition.LogLevel logLevel)| Utilizado para customizar o nível de verbosidade dos logs do SDK. Níveis disponíveis: LogLevel.debug, LogLevel.info, LogLevel.warn, LogLevel.error e LogLevel.trace. O padrão é LogLevel.debug. |Não.|

## O Objeto VisualConfiguration
:::warning
__DEPRECADO__ A PARTIR DA **v4.0.0**!
:::

| Parâmetro                                                                      | Função                                                                                                                                                                                                                                                              | Obrigatório             |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| .setOnboardingDrawable(int onboarding_drawable, int onboarding_width)          | Utilizado para configurar a imagem mostrada para o usuário na tela de onboarding do SDK. O parâmetro _onboarding_drawable_ deve referenciar o id da imagem a ser mostrada e _onboarding_width_ é o tamanho desejado de exibição desta imagem.                       | Não.                    |
| .setDocumentFullDrawable(int documentfull_drawable, int documentfull_width)    | Utilizado para configurar a imagem mostrada para o usuário na tela de captura de CNH inteira do SDK. O parâmetro _documentfull_drawable_ deve referenciar o id da imagem a ser mostrada e _documentfull_width_ é o tamanho desejado de exibição desta imagem.       | Não.                    |
| .setDocumentFrontDrawable(int documentfront_drawable, int documentfront_width) | Utilizado para configurar a imagem mostrada para o usuário na tela de captura de CNH e RG frente do SDK. O parâmetro _documentfront_drawable_ deve referenciar o id da imagem a ser mostrada e _documentfront_width_ é o tamanho desejado de exibição desta imagem. | Não.                    |
| .setDocumentBackDrawable(int documentback_drawable, int documentback_width)    | Utilizado para configurar a imagem mostrada para o usuário na tela de captura de CNH e RG verso do SDK. O parâmetro _documentback_drawable_ deve referenciar o id da imagem a ser mostrada e _documentback_width_ é o tamanho desejado de exibição desta imagem.    | Não.                    |
| .setButtonBorderSize(int border_size)                                          | Utilizado para configurar a largura de borda dos botões do SDK.                                                                                                                                                                                                     | Não. O padrão é _1_.    |
| .setButtonShadow(boolean button_shadow)                                        | Quando setado para _false_ remove o efeito de sombra, padrão no android, utilizado pelos botões do SDK.                                                                                                                                                             | Não. O padrão é _true_. |

## O Objeto TextConfiguration
:::warning
__DEPRECADO__ A PARTIR DA **v4.0.0**!
:::

| Parâmetro                                      | Função                                                                                    | Obrigatório |
| ---------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------- |
| .setCustomText(CustomLabel label, String text) | Utilizado para configurar os textos mostrados para o usuário na tela de onboarding do SDK | Não.        |

---

# Status HTTP

URL: /documentation/caas/ocr/api/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Introdução

URL: /documentation/caas/ocr/api/introduction

Bem vindo à API de OCR (Optical Character Recognition) para leitura de documentos da QI Tech. Você pode utilizar esta API para enviar uma imagem de um documento a ser reconhecido, como uma Carteira de Habilitação ou Cédula de identidade, e referenciá-lo através de uma chave nos demais produtos do sistema QI Tech.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/ocr/`
* Sandbox - `https://api.sandbox.caas.qitech.app/ocr/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

## Autenticação
> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE_API_KEY"
```

> Substitua a API key 'EXAMPLE_API_KEY' com a sua chave adquirida com o nosso suporte.

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE_API_KEY`

:::info **Atenção**

Você deve substituir EXAMPLE_API_KEY com a API Key recebida do suporte.
:::

---

# Enviando um Documento

URL: /documentation/caas/ocr/api/send_image

Envie um documento utilizando o endpoint `/image` conforme indicado abaixo. Este endpoint retornará um identificador GUID (Globally Unique Identifier) para o documento, que poderá então ser referenciado nos demais serviços do sistema QI Tech.

## Envio
Para enviar um documento, basta realizar via método POST o envio do código base64 da imagem em formato json para o seguinte endereço:

`https://api.caas.qitech.app/ocr/image`

Request Body

```json
  {
    "document_b64": "\<BASE64_IMAGE\>",
    "template": "cnh",
    "file_type": "jpeg"
  }
```

Substitua o código base64 de seu documento documento no lugar do placeholder.

### Descrição dos Atributos de Envio

Atributo | Descrição
--------- | ---------
document_b64 | Campo obrigatório. Imagem do documento a ser análisado em formato base64.
template | Campo obrigatório. Declara o template que deve ser aplicado para análise da imagem.
file_type | Campo facultativo. Identifica o formato do arquivo enviado, `jpeg` ou `pdf`. Caso não seja enviado, o valor `jpeg` é assumido.

### Templates disponíveis
Neste momento, a QI Tech apresenta os seguintes templates disponíveis para análise OCR. Caso o seu documento necessário não esteja incluso nesta lista, envie um e-mail para suporte.caas@qitech.com.br e informe-se dos detalhes quanto a implementação desta feature.

Template | Descrição
--------- | ---------
cnh | Carteira Nacional de Habilitação brasileira completa.
cnh_front | Carteira Nacional de Habilitação brasileira frente (Lado da foto).
cnh_back | Carteira Nacional de Habilitação brasileira frente (Lado da assinatura).
cnh_digital | PDF da Carteira Nacional de Habilitação brasileira digital.
rg_front | Carteira de Identidade brasileira frente (Lado da foto).
rg_back | Carteira de Identidade brasileira verso (Lado dos dados).
danfe | Documento Auxiliar da Nota Fiscal Eletrônica (NF-e).
proof_of_address | Comprovante de residência.
letter_of_attorney | Procuração que concede poderem com relação a uma empresa.
company_statute | Contrato social ou estatudo de uma empresa.

## Imagem
Visando garantir uma maior confiabilidade das análises executadas, é necessário que o cliente siga algumas regras na hora de tirar a foto:

* Remova o documento do plástico;
* Garanta que o documento encontra-se centralizado na foto;
* Garanta que o documento esteja iluminado;
* Garanta que todos os dados do documento estejam nítidos, visíveis e legíveis;
* Garanta que a foto esteja visível e nítida.

## Requisitos da Imagem
Para o funcionamento adequado da API, atente-se aos seguintes parâmetros.

* A imagem deve estar em formato JPEG ou PDF;
* A imagem deve possuir, ao menos, 500 pixels de altura e 500 pixels de largura;
* A API não suporta a leitura de documentos escritos à mão;
* O tamanho máximo da imagem varia de acordo com o formato escolhido, seguindo os limites a seguir:

Formato | Tamanho máximo suportado
--------- | ---------
.JPEG | 3MB
.PNG | 10MB
.PDF | 30MB

## Resposta
Caso sua requisição de leitura de documento seja processada com sucesso, será retornado um HTTP status 200 e um objeto JSON com o identificador que aponta para o documento que foi enviada.

Response Body

```json
    {
        "ocr_key": "f1c0d2e1-f950-4360-896d-36588e443fc9"
    }   
```

### Descrição dos Atributos de Resposta

Atributo | Descrição
--------- | ---------
ocr_key | Chave de identificação da imagem fornecida que pode ser utilizada em qualquer outro serviço do sistema QI Tech.

## Recuperação de um documento
> Recuperação de imagem

```shell
    curl "https://api.caas.qitech.app/ocr/image/f4b5337a-7b50-406e-8c8e-7d0e77b5aa02/file" \
         -H "Authorization: EXAMPLE_API_KEY"
```

Em qualquer momento é possível recuperar as imagens enviadas. Para isso, basta enviar  uma requisição **GET** adequadamente autenticada no endpoint:

`https://api.caas.qitech.app/ocr/image/{image_key}/file`

Onde image_key é o valor retornado durante o envio da imagem.

## Validação de qualidade da imagem

Response Body: Caso de imagem inválida

```json
    {
        "title": "document_quality",
        "description": "A imagem enviada não pode ser processada com êxito."
    }
```

Ao realizar um post no endpoint de imagem, caso a imagem não seja suficiente para validação, um HTTP Status Code 400 será retornado, como pode ser visto no exemplo ao lado. O Status Code 400 também é retornado quando o documento não atende aos requisitos de imagem, citados anteriormente.

**Atenção -** Existem outros motivos pelos quais retornamos 400 (Todos relacionados a dados inválidos). Somente os retornos com o title "document_quality" são resultantes de uma validação de má qualidade da imagem e portanto devem ser repassados ao usuário.

## Validação de qualidade do rosto

A validação de qualidade da imagem é aplicada **exclusivamente a documentos que contêm rostos**, como RG, CNH e passaportes. Quando uma imagem é enviada ao sistema, se ela for identificada como um dos tipos abaixo, uma **análise de face é realizada automaticamente**:

- `national_migration_registry_front`
- `passport_front`
- `ctps_front`
- `regional_nursing_council_registry_front`
- `regional_nursing_council_registry`
- `national_registry_of_foreigners_back`
- `passport`
- `national_migration_registry`
- `national_registry_of_foreigners`
- `cnh_digital`
- `rg_front`
- `rg`
- `cnh_front`
- `cnh`

Durante essa análise, o sistema verifica se há **um rosto visível na imagem** e avalia aspectos como:

- Iluminação adequada (brilho);
- Presença de acessórios como óculos escuros;
- Proximidade ou distância excessiva do rosto;
- Ausência total de rostos na imagem.

Se algum desses critérios indicar que a imagem não está adequada, será retornado um erro com `title: "face_validation"` e o respectivo `description`, conforme detalhado abaixo.

```json
{
    "title": "face_validation",
    "description": "<código_de_erro>"
}
```

### Exemplo de retorno:

**Nenhum rosto detectado**

```json
{
    "title": "face_validation",
    "description": "no_faces"
}
```

---

### Tabela de tradução de mensagens para exibição ao usuário

| Código de erro (`description`) | Mensagem amigável |
|-------------------------------|-------------------|
| `close_face`                  | A imagem foi capturada muito próxima do rosto. Reposicione o documento. |
| `distant_face`                | A imagem foi capturada muito distante do rosto. Reposicione o documento. |
| `wearing_acessories`          | A pessoa na imagem está usando óculos escuros ou acessórios que cobrem os olhos. |
| `brightness_problem`          | A imagem está muito escura. Reenvie com mais iluminação. |
| `no_faces`                    | Não foi possível detectar um rosto na imagem. Verifique se o rosto está visível. |

---

# Coletando os Retornos

URL: /documentation/caas/ocr/ios/collecting_response

```swift
class ViewController: UIViewController, QITechIosOcrControllerDelegate {
    
    // Do something if QI Tech OCR's SDK succesfully collected document picture
    func qitechIosOcrController(_ ocrViewController: QITechIosOcrController, didFinishWithResults response: QITechIosOcrControllerResponse) {
    
    }
    
    // Do something if QI Tech OCR's SDK found any error when collecting document picture
    func qitechIosOcrController(_ ocrViewController: QITechIosOcrController, didFailWithError error: QITechIosOcrControllerError) {
        
    }
    
    // Do something if the user canceled the picture collection on any steps
    func qitechIosOcrControllerDidCancel(_ ocrViewController: QITechIosOcrController) {

    }
}
```
Para obter as respostas do SDK , você deve implementar o delegate **QITechIosOcrControllerDelegate** em seu controller, conforme exemplo ao lado.

## QITechIosOcrControllerResponse

A classe **QITechIosOcrControllerResponse** é utilizada para que você possa receber a resposta do SDK da QI Tech.

Na tabela abaixo você encontra o detalhe de todas as propriedades desta classe:

nome | tipo | descrição 
---- | :----: | --------- 
OcrResponses | Lista de OcrResponse | Identifica

## Objeto OcrResponse

nome | tipo | descrição 
---- | :----: | --------- 
OcrKey | string | Identificador único da imagem na QI Tech. Você deve armazenar esse identificador para enviar na API da QI Tech que realizará a validação (ex.: API de Onboarding)
DocumentTemplate | QITechIosOcrDocumentTemplate | Enumerador que identifica a qual foto aquela OCR Key se refere.

Os valores possíveis do enumerador **QITechIosOcrDocumentTemplate** podem ser:

* `QITechIosOcrDocumentTemplate.CnhFull` - Identifica o resultado da validação da CNH inteira.
* `QITechIosOcrDocumentTemplate.CnhFront` - Identifica o resultado da validação da frente da CNH.
* `QITechIosOcrDocumentTemplate.CnhBack` - Identifica o resultado da validação do verso da CNH.
* `QITechIosOcrDocumentTemplate.RgFront` - Identifica o resultado da validação da frente do RG.
* `QITechIosOcrDocumentTemplate.RgBack` - Identifica o resultado da validação do verso do RG.
* `QITechIosOcrDocumentTemplate.NationalRegistryOfForeignersFront` - Identifica o resultado da validação da frente do Registro Nacional de Estrangeiros.
* `QITechIosOcrDocumentTemplate.NationalRegistryOfForeignersBack` - Identifica o resultado da validação do verso do Registro Nacional de Estrangeiros.

## QITechIosOcrControllerError

A classe **QITechIosOcrControllerError** é acionada no caso de algum erro que leve ao encerramento do SDK. Quando isso ocorrer, a QI Tech retornará uma subclasse que terá um nome correspondente ao erro que levou ao encerramento do SDK, conforme tabela abaixo:

classe | descrição 
---- | --------- 
InvalidMobileToken | MobileToken enviado nas configurações é inválido.
MissingPermission | Alguma das permissões necessárias para a validação não foi suficiente.
NetworkFailure | O usuário perdeu a conexão com a internet durante a validação.
ServerFailure | O servidor da QI Tech devolveu alguma resposta de erro para o SDK.
MissingStorage | Não há espaço de armazenamento suficiente no dispositivo do usuário para que seja realizada a coleta da imagem.
LowImageQuality | Por algum motivo a qualidade da imagem coletada não foi o suficiente para realização da validação.

Para mapear qual a subclasse, e portanto, qual o motivo do erro, utilize o método *isKindOfClass()* do swift.

---

# QITechIosOcrConfiguration

URL: /documentation/caas/ocr/ios/configuration

```swift
let onboardingTextConfiguration = OnboardingTextConfiguration(
        onboardingTitle: "Conselhos relevantes",
        onboardingFirstLabel: "Esteja em um local iluminado",
        onboardingSecondLabel: "Tire o documento do envelope",
        onboardingThirdLabel: "Enquadre o documento nas marcas"
)

let ocrConfig = QITechIosOcrConfiguration(
        environment: QITechIosOcrEnvironment.sandbox,
        mobileToken: "41fb4755-9bcf-4ae3-b981-b6009e51ce4a",
        sessionId: "288eb399-4936-4133-ab2c-5611d6e5bb7a",
        documentSteps: documentSteps,
        fontColor: "#337DFF",
        backgroundColor: "#C9CCD3",
        fontFamily: .open_sans,
        showIntroductionScreens: true,
        showSuccessScreen: false,
        onboardingTextConfiguration: onboardingTextConfiguration,
        logLevel: .debug
)
```

**Versões anteriores à v7.0.0**
```swift

let visualConfiguration = VisualConfiguration()
        visualConfiguration.setOnboarding(onboardingFilePath: Bundle.main.path(forResource: "onboarding", ofType: "png")!, onboardingWidth: 200)

let textConfiguration = TextConfiguration()
        textConfiguration.setCustomText(on: .onboardingTitle, text: "Vamos começar!")
        textConfiguration.setCustomText(on: .onboardingFirstLabel, text: "- Vá para um local com boa luminosidade")
        textConfiguration.setCustomText(on: .onboardingSecondLabel, text: "- Retire o documento do plástico")

let ocrConfig = QITechIosOcrConfiguration(environment: QITechIosOcrEnvironment.Sandbox,
                                            mobileToken: "41fb4755-9bcf-4ae3-b981-b6009e51ce4a",
                                            sessionId: "288eb399-4936-4133-ab2c-5611d6e5bb7a",
                                            documentSteps: documentSteps,
                                            backgroundColor: "#C9CCD3",
                                            fontColor: "#337DFF",
                                            fontFamily: .open_sans,
                                            showIntroductionScreens: true,
                                            showSuccessScreen: false,
                                            logLevel: .debug
                                            )

ocrConfig.setVisualConfiguration(visualConfiguration: visualConfiguration)
ocrConfig.setTextConfiguration(textConfiguration: textConfiguration)

```

A classe **QITechIosOcrConfiguration** é utilizada para que você possa configurar ambiente, credenciais, aspectos visuais e textuais, e o fluxo de coleta de imagens dos documentos, ou seja, todas as configurações necessárias para personalização e funcionamento do SDK.

Na tabela abaixo você encontra o detalhe de todos os argumentos que devem ser utilizados na sua instanciação:

| nome                    |          tipo          | descrição                                                                                                                                                                                                                              |
| ----------------------- | :--------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| environment             | QITechIosOcrEnvironment  | _(obrigatório)_ Enumerador que descreve o ambiente.                                                                                                                                                                                    |
| mobileToken             |         string         | _(obrigatório)_ Token enviado pela QI Tech para autenticação do SDK.                                                                                                                                                                      |
| sessionId               |         string         | _(opcional)_ ID único usado para rastrear todo fluxo percorrido pelo usuário na execução da OCR através de logs. Este campo aceita até 255 caracteres.                                                                                 |
| documentSteps           | QITechIosOcrDocumentFlow | _(obrigatório)_ Enumerador que descreve qual fluxo de validação será seguido, definindo qual documento e qual ordem de captura de imagem será realizado.                                                                               |
| fontColor               |         string         | _(opcional)_ Hexadecimal da cor da fonte. Caso não seja informada o padrão é #1C49A5.                                                                                                                                              |
| backgroundColor         |         string         | _(opcional)_ Hexadecimal da cor de fundo das telas. Caso não seja informada o padrão é #FCFCFC.                                                                                                                                        |
| fontFamily              |       FontFamily       | _(opcional)_ Familia da fonte. Caso não seja informada o padrão é .open_sans. Fontes disponíveis: .open_sans, .futura, .verdana, .trebuchetms, .tamilsangammn e .system_font.                                                          |
| showIntroductionScreens |        booleano        | _(opcional)_ Flag que indica se as telas de introdução, com instruções de como a foto deve ser capturada, devem ser mostradas. Caso não seja informada o padrão é _true_.                                                              |
| showSuccessScreen |             booleano              | _(opcional)_ Flag que indica se a tela de sucesso, com a mensagem de sucesso na captura, deve ser mostrada. Caso não seja informada o padrão é _true_.                                                                                                                                                                   |
| onboardingTextConfiguration | OnboardingTextConfiguration | _(opcional)_ Permite configurar os textos da tela de instruções |
| logLevel                |        LogLevel        | _(opcional)_ . Utilizado para customizar o nível de verbosidade dos logs do SDK. Níveis disponíveis: LogLevel.debug, LogLevel.info, LogLevel.warn, LogLevel.error e LogLevel.trace. Caso não seja informada o padrão é LogLevel.debug. |

Na tabela abaixo você encontra todos os métodos aceitos pela instância para configuração:
:::warning
__DEPRECADO__ A PARTIR DA **v7.0.0**!
:::

| método                 |                                                 argumentos                                                  | descrição                                                                                     |
| ---------------------- | :---------------------------------------------------------------------------------------------------------: | --------------------------------------------------------------------------------------------- |
| setVisualConfiguration | visualConfiguration : VisualConfiguration | _(opcional)_ Classe que permite a modificação das imagens exibidas durante a execução do SDK; |
| setTextConfiguration   |                                    textConfiguration : TextConfiguration                                    | _(opcional)_ Classe que permite a modificação dos textos exibidos durante a execução do SDK;  |

---

# Soluções híbridas

URL: /documentation/caas/ocr/ios/hybrid_solutions

Além de oferecer integração nativa em Swift, nossas SDKs também são compatíveis com diversos frameworks híbridos. Isso é possível através da integração de plugins nativos específicos para cada um desses frameworks. Utilizando o sistema nativo de cada solução, é viável incorporar nosso SDK nativa no ambiente iOS.

Algumas das tecnologias híbridas mais utilizadas são o React Native ([Native Modules](https://reactnative.dev/docs/turbo-native-modules-introduction)), Cordova ([Plugin Development Guide](https://cordova.apache.org/docs/en/latest/guide/hybrid/plugins/index.html)), Ionic ([Native](https://ionicframework.com/docs/v3/native/)), Unity ([Native Plug-in para Android](https://docs.unity3d.com/Manual/PluginsForAndroid.html)), Xamarin ([Native Libraries](https://learn.microsoft.com/en-us/xamarin/android/platform/native-libraries)), Appcelerator, Phonegap e Node.

Para facilitar o processo de integração com nossas soluções nativas, disponibilizamos plugins para os frameworks React Native e Flutter. Caso tenha interesse, provemos a documentação e um exemplo de integração em nossos repositórios privados. Para as demais tecnologias híbridas, temos alguns exemplos de implementação dessa ponte para o código nativo. Fique à vontade para entrar em contato com nosso suporte para obter acesso.

---

# Introdução

URL: /documentation/caas/ocr/ios/introduction

Bem vindo ao SDK iOS de OCR (Optical Character Recognition) para leitura de documentos da QI Tech. Este SDK realiza a captura de documentos e envio a API de OCR da QI Tech . Você pode utilizá-lo para capturar através do seu aplicativo uma imagem de um documento de seu cliente a ser reconhecido, como uma Carteira de Habilitação ou Cédula de identidade, e referenciá-lo através de uma chave nos demais produtos do sistema QI Tech.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso [suporte](mailto:suporte.caas@qitech.com.br) e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

---

# Importando o SDK

URL: /documentation/caas/ocr/ios/native_swift

## Remotamente

> Iniciando a instalação

```shell
  pod init
```

Nosso SDK pode ser importado utilizando CocoaPods.

| SDK        | Versão atual                   |
| ---------- | ------------------------------ |
| QITechIosOCR | `pod 'QITechIosOCR', '~> 8.0.0'` |

:::info iOS Minimum Deployment Target
15.5
:::

:::danger Utilização de simuladores em MacBooks com chip arm64
Atualmente, nosso SDK de OCR para iOS infelizmente não suporta ser compilada para simuladores que estejam rodando
em um MacBook com **chip de arquitetura arm64** (M1/M2/M3/M4), **a não ser que seja utilizado Rosetta**, que faz a tradução
da arquitetura x86_64 para arm64.
:::

Para iniciar a instalação, execute o comando ao lado na pasta raiz do seu projeto.

> Adicionando a source no podfile

```ruby
   source 'https://github.com/QITechSDKs/iOS.git'
```

O próximo passo é adicionar no arquivo `podfile` o source da QI Tech.

> Adicionando o pod no podfile

```ruby
  pod 'QITechIosOCR', '~> <version>'
```

Por fim, basta adicionar o nome do `pod` de acordo com o formato ao lado.

:::danger Atenção: 
Mudança de Arquitetura (v6.0.0+) A partir da versão 6.0.0, o SDK passou a ser distribuída exclusivamente de forma estática. No seu Podfile, você deve utilizar a configuração :linkage => :static. 
:::

> Exemplo de podfile (Versão 6.0.0 ou superior)

```ruby
  source 'https://github.com/QITechSDKs/iOS.git'
  source 'https://cdn.cocoapods.org/'
  target 'ExampleApp' do
    use_frameworks! :linkage => :static
    pod 'QITechIosOCR', '~> 8.0.0'
  end

  post_install do |installer|
    installer.pods_project.targets.each do |target|
      if ['DatadogCore', 'DatadogInternal', 'DatadogCrashReporting', 'DatadogLogs'].include?(target.name)
        target.build_configurations.each do |config|
          config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'
          config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
        end
      end
    end
  end
```

> Exemplo de podfile (Versões Anteriores)

```ruby
  source 'https://github.com/QITechSDKs/iOS.git'
  source 'https://cdn.cocoapods.org/'
  target 'ExampleApp' do
    use_frameworks! 
    pod 'QITechIosOCR', '~> 4.0.0'
  end

  post_install do |installer|
    installer.pods_project.targets.each do |target|
      if ['DatadogCore', 'DatadogInternal', 'DatadogCrashReporting', 'DatadogLogs'].include?(target.name)
        target.build_configurations.each do |config|
          config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.5'
          config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
        end
      end
    end
  end
```

:::warning Atenção
Ao integrar dependências no iOS, pode surgir a necessidade de usar linkagem estática para algumas bibliotecas e dinâmica para outras. Essa configuração é relevante para garantir compatibilidade, evitar erros de build e otimizar o desempenho do projeto. 
:::

### Linkagem Híbrida de Dependências (caso necessário)
A necessidade de linkagem híbrida surge porque algumas bibliotecas têm requisitos específicos, sendo que algumas precisam de linkagem estática para evitar conflitos internos e duplicação de símbolos e outras dependências podem precisar linkagem dinâmica, pois são projetadas para modularidade e compartilhamento entre projetos.

Diferenças Entre Linkagem Estática e Dinâmica
* Estática (static_framework): O código da biblioteca é incorporado diretamente no binário final, reduzindo o tempo de carregamento em runtime e eliminando dependências externas durante a execução.
* Dinâmica (dynamic_framework): A biblioteca é carregada em tempo de execução como um arquivo separado. Isso reduz o tamanho do binário final e facilita atualizações/modificações independentes.

> Configurando linkagem híbrida no Podfile

```ruby
...

use_frameworks! :linkage => :dynamic # CONFIGURANDO O MODO PADRÃO DE LINKAGEM PARA DINÂMICO

...

static_frameworks = ['framework_1', 'framework_2', ...] # INCLUIR TODAS AS DEPENDÊNCIAS QUE PRECISAM SER LINKADAS DE MODO ESTÁTICO
pre_install do |installer|
  installer.pod_targets.each do |pod|
    if static_frameworks.include?(pod.name)
      def pod.static_framework?;
        true
      end
      def pod.build_type;
        Pod::BuildType.static_framework
      end
    end
  end
end
```

> Instalando as dependências

```shell
  pod install
```

Por fim, execute o comando `pod install` para baixar e instalar as dependências.

## Permissões Necessárias

Para que o SDK possa acessar os recursos do dispositivo para coletar a foto, é necessário que sejam solicitadas permissões ao usuário.

No arquivo **info.plist**, adicione as permissões abaixo:

| Permissão                          | Motivo                                               |
| ---------------------------------- | ---------------------------------------------------- |
| Privacy - Camera Usage Description | Acesso à câmera para capturar as fotos do documento. |

## Iniciando o SDK

```swift

import QITechIosOcr

class ViewController: UIViewController, QITechIosOcrControllerDelegate {

    var qitechOcrConfiguration : QITechIosOcrConfiguration?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.setupOcr()
    }

    func setupOcr() -> Void
    {
        let onboardingTextConfiguration = OnboardingTextConfiguration(
          onboardingTitle: "Conselhos relevantes",                // Título
          onboardingFirstLabel: "Esteja em um local iluminado",   // Primeira Instrução
          onboardingSecondLabel: "Tire o documento do envelope",  // Segunda Instrução
          onboardingThirdLabel: "Enquadre o documento nas marcas" // Terceira Instrução
        )

        // The environment can be 'sandbox' ou 'production'
        let environment: QITechIosOcrEnvironment = .sandbox

        // MobileToken is the key sent to you by QI Tech. Each environment requires a different MobileToken.
        let mobileToken: String = "YOUR_MOBILE_TOKEN"

        // The documentFlow can be 'CnhFull' , 'CnhFrontAndBack' ou 'RgFrontAndBack'
        let documentFlow = QITechIosOcrDocumentFlow.CnhFrontAndBack

        let sessionId: String = "SESSION_ID"
        let fontColor: String = "#ED6C2D"
        let backgroundColor: String = "#EEEEEE"
        let fontFamily: FontFamily? = .verdana
        let showIntroductionScreens: Bool = true
        let showSuccessScreen: Bool = true
        let logLevel: QITechIosOCR.LogLevel = .debug

        self.ocrConfig = QITechIosOcrConfiguration(
          environment: environment,
          mobileToken: mobileToken,
          documentSteps: documentFlow,
          sessionId: sessionId,
          fontColor: fontColor,
          backgroundColor: backgroundColor,
          fontFamily: fontFamily,
          showIntroductionScreens: showIntroductionScreens,
          showSuccessScreen: showSuccessScreen,
          onboardingTextConfiguration: onboardingTextConfiguration,
          logLevel: logLevel
        )
    }

    // Event where you intend to call QI Tech OCR View Controller - on this example, when the user press 'next' button

    @IBAction func pressNext(_ sender: Any) {
        let qitechOcrController =  QITechIosOcrController(ocrConfiguration: self.ocrConfig)
        qitechOcrViewController.delegate = self
        let qitechOcrViewController = qitechOcrController.getViewController()
        present(qitechOcrViewController, animated: true, completion: nil)
    }

    // Do something if QI Tech OCR's SDK succesfully collected document picture
    func qitechIosOcrController(_ ocrViewController: QITechIosOcrController, didFinishWithResults results: QITechIosOcrControllerResponse) {

    }

    // Do something if QI Tech OCR's SDK found any error when collecting document picture
    func qitechIosOcrController(_ ocrViewController: QITechIosOcrController, didFailWithError error: QITechIosOcrControllerError) {

    }

    // Do something if the user canceled the picture collection on any steps
    func qitechIosOcrControllerDidCancel(_ ocrViewController: QITechIosOcrController) {

    }
}
```

**Versões anteriores à v7.0.0**
  ```swift
    import QITechIosOcr

    class ViewController: UIViewController, QITechIosOcrControllerDelegate {

        var qitechOcrConfiguration : QITechIosOcrConfiguration?

        override func viewDidLoad() {
            super.viewDidLoad()
            self.setupOcr()
        }

        func setupOcr() -> Void
        {
            // The environment can be 'Sandbox' ou 'Production'
            let environment = QITechIosOcrEnvironment.Sandbox

            // MobileToken is the key sent to you by QI Tech. Each environment requires a different MobileToken.
            let mobileToken = "YOUR_MOBILE_TOKEN_SENT_BY_QITECH"

            // The documentFlow can be 'CnhFull' , 'CnhFrontAndBack' ou 'RgFrontAndBack'
            let documentFlow = QITechIosOcrDocumentFlow.CnhFrontAndBack

            self.ocrConfig = QITechIosOcrConfiguration(environment: environment,
                                                mobileToken: mobileToken,
                                                sessionId: "UNIQUE_SESSION_ID",
                                                documentFlow: documentFlow,
                                                backgroundColor: "#000000",
                                                fontColor: "#FFFFFF",
                                                fontFamily: .open_sans,
                                                showIntroductionScreens: true,
                                                logLevel: .debug
                                                )
        }

        // Event where you intend to call QI Tech OCR View Controller - on this example, when the user press 'next' button

        @IBAction func pressNext(_ sender: Any) {
            let qitechOcrController =  QITechIosOcrController(ocrConfiguration: self.ocrConfig)
            qitechOcrViewController.delegate = self
            let qitechOcrViewController = qitechOcrController.getViewController()
            present(qitechOcrViewController, animated: true, completion: nil)
        }

        // Do something if QI Tech OCR's SDK succesfully collected document picture
        func qitechIosOcrController(_ ocrViewController: QITechIosOcrController, didFinishWithResults results: QITechIosOcrControllerResponse) {

        }

        // Do something if QI Tech OCR's SDK found any error when collecting document picture
        func qitechIosOcrController(_ ocrViewController: QITechIosOcrController, didFailWithError error: QITechIosOcrControllerError) {

        }

        // Do something if the user canceled the picture collection on any steps
        func qitechIosOcrControllerDidCancel(_ ocrViewController: QITechIosOcrController) {

        }
    }
  ```

Para incorporar o SDK ao seu aplicativo você deve realizar a configuração do seu aplicativo de captura personalizado através da classe **QITechIosOcrConfiguration** e depois instanciar o **ViewController QITechIosOcrController** passando como argumento as configurações personalizadas.

Para iniciar o processo de análise de documento, basta chamar a função _present_ para chamar o ViewController da QI Tech que realizará a coleta das imagens.

Importante implementar o _Delegate_ responsável por receber os retornos em caso de sucesso, erro ou no caso de o usuário interromper a jornada em qualquer etapa da validação.

Acima temos um exemplo completo da implementação.

:::info **Atenção**

Habilite o suporte as orientações _Portrait_ e _Landscape Right_ em sua aplicação para um funcionamento correto do SDK.
:::

## Mobile Token

Utilizamos um Mobile Token para permitir o acesso autenticado do seu aplicativo a nossa API. Ele provavelmente já foi enviado por e-mail para você. Caso ainda não tenha recebido o seu token, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber o Mobile Token em todas as requisições ao nosso servidor vindas do SDK, portanto, este deve ser obrigatoriamente incluido como parâmetro de configuração através do método mencionado anteriormente.

:::info **Atenção**

Você deve substituir "YOUR_MOBILE_TOKEN_SENT_BY_QITECH" pelo Mobile Token recebido do suporte.
:::

---

# Coletando os Retornos

URL: /documentation/caas/ocr/web/collecting_results

A Web OCR SDK devolve uma _Promise_ que, em caso de sucesso, retorna um **array de objetos**, onde cada objeto representa um lado do documento capturado (frente e/ou verso). Em caso de erro, a Promise é rejeitada com uma string descrevendo o problema.

Abaixo está um exemplo de como mapear cada caso e coletar seus resultados:

```html
<script>
    webOCR.initialize(allowed_templates)
    .then((ocr_results) => {
        console.log(ocr_results)
        // Exemplo de retorno:
        // [
        //   { template: "rg_front", ocr_key: "abc123...", document_capture_session_key: "uuid..." },
        //   { template: "rg_back",  ocr_key: "def456...", document_capture_session_key: "uuid..." }
        // ]
    })
    .catch((error) => {
        console.log(error)
    })
</script>
```

## Descrição do retorno da Web OCR

### Sucesso

O retorno de sucesso é um **array** de objetos, um por lado do documento capturado:

Atributo | Tipo | Descrição
--------- | --------- | ---------
ocr_results | Array | Lista de objetos com as informações de cada captura realizada.

### Atributos de cada objeto no array

Atributo | Tipo | Descrição
--------- | --------- | ---------
ocr_key | String | Chave de identificação da imagem capturada. Pode ser utilizada em qualquer outro serviço do sistema QI Tech.
template | String | Tipo e lado do documento capturado (ex: `rg_front`, `rg_back`, `cnh_front`, `cnh_back`, `cin_digital`).
document_capture_session_key | String | Chave que identifica a sessão de captura do documento.

### Tipos de Erro

Erro | Descrição
--------- | ---------
Invalid Web Token! Please verify your Web Token. | Web Token utilizado é inválido. Caso tenha certeza que esteja utilizando corretamente o Web Token provido pela QI Tech, entre em contato com nosso suporte (suporte.caas@qitech.com.br).
Invalid Document Type! Please provide a valid document type. | Tipo de documento passado para **WebOCR.initialize()** não é válido. Verifique os tipos permitidos na página da [função initialize](./initialize_info.md).
User left Web OCR. | O usuário saiu da Web OCR SDK antes de concluir o envio do documento.

---

# O construtor QiTechWebOCR.WebOCR()

URL: /documentation/caas/ocr/web/constructor_info

:::info Novidade na versão 4.0.0
A partir da versão **4.0.0**, o construtor não recebe mais o `htmlComponent` como primeiro parâmetro — o SDK cria e gerencia seu próprio nó DOM internamente, adicionado ao `document.body`.
:::

O método `.WebOCR()` é responsável pela configuração da instância do seu componente de documentoscopia. O construtor recebe dois parâmetros obrigatórios:

| Parâmetro | Descrição | Obrigatório |
|----------|----------|----------|
| webToken | Chave do cliente que identifica que os dados coletados são provenientes do seu aplicativo. Caso ainda não tenha recebido o seu web-token, entre em contato com o <a href='mailto:suporte.caas@qitech.com.br'>suporte</a>. | Sim |
| sessionId | Utilizado para definir a chave que identifica a sessão iniciada no SDK. É usada para rastrear todo fluxo percorrido pelo usuário na execução da Web OCR através de logs. Este campo aceita uma string de até 255 caracteres. Deve ser único para cada sessão. | Sim |

Após a instanciação, utilize os seguintes métodos encadeados para personalizar o comportamento:

| Nome | Descrição | Obrigatório |
|----------|----------|----------|
| `.setThemeConfiguration(object)` | Personaliza a identidade visual do SDK. | Não |
| `.setShowInstructionScreen(boolean)` | Exibe a tela de introdução com dicas de captura. Padrão: `true`. | Não |
| `.setShowAllowedTemplatesScreen(boolean)` | Exibe a tela que informa os documentos aceitos. Recomendamos ativá-la para que o usuário saiba quais documentos pode enviar. | Não |
| `.setShowSuccessScreen(boolean)` | Exibe a tela de sucesso ao final da captura. Padrão: `true`. | Não |
| `.setSandboxEnvironment()` | Configura o SDK para apontar para o ambiente de Sandbox. | Não |

O método `.setThemeConfiguration` deve receber um objeto com os seguintes campos:

| Nome | Tipo | Descrição |
| -------- | -------- | -------- |
| primaryColor | String | _(recomendado)_ Hexadecimal da cor principal do SDK — usada em botões, ícones e elementos de destaque. Caso não seja informada, o padrão é `#555555`. |
| companyLogo | String | _(recomendado)_ Caminho ou **URL pública** do logo da sua empresa (**PNG**). Caso não seja informado, será exibido um placeholder. |
| fontFamily | String | _(recomendado)_ Nome da _Font Family_ a ser configurada nos textos do SDK. Caso não seja informada, será utilizada a fonte padrão. |

:::caution Compatibilidade
Os campos `backgroundColor` e `buttonColor` ainda são aceitos pelo método `.setThemeConfiguration`, mas são utilizados apenas como fallback para derivar o `primaryColor` quando este não for informado. Prefira usar `primaryColor` diretamente.
:::

## Versões Anteriores (< 4.0.0)

Nas versões anteriores, o construtor recebia o `htmlComponent` como primeiro parâmetro:

```js
var htmlComponent = document.getElementById('webOCR');
var webOCR = new QiTechWebOCR.WebOCR(
    htmlComponent,
    "<WEB_TOKEN>",
    "<SESSION_ID>"
)
```

---

# Implementação

URL: /documentation/caas/ocr/web/example

:::info Novidade na versão 4.0.0
A partir da versão **4.0.0**, o construtor `WebOCR` não recebe mais o `htmlComponent` — o SDK cria e gerencia seu próprio nó DOM internamente.
:::

A inicialização da Web OCR SDK é realizada através da chamada do método `.initialize()`, que pertence à classe `WebOCR`. O processo é dividido em duas etapas principais:

1. **Configuração e Instanciação:** Preparar e configurar a instância do SDK.
2. **Inicialização da Captura:** Iniciar o fluxo de captura de documentos para o usuário final.

## Exemplo completo

```html
<script>
    var webOCR = new QiTechWebOCR.WebOCR(
        "<WEB_TOKEN>",
        "<SESSION_ID>"
    )
    .setThemeConfiguration({
        "companyLogo": "<PATH_OR_URL_TO_YOUR_COMPANY_LOGO>",
        "primaryColor": "<PRIMARY_COLOR_HEX>",
        "fontFamily": "<FONT_FAMILY>"
    })
    .setShowInstructionScreen(true)
    .setShowSuccessScreen(true)
    .setShowAllowedTemplatesScreen(false)
    .setSandboxEnvironment()
    .build()

    function initOCR(allowed_templates) {
        webOCR.initialize(allowed_templates)
        .then((ocr_results) => {
            console.log(ocr_results)
        })
        .catch((error) => {
            console.log(error)
        })
    }

    initOCR(['cnh', 'rg', 'rg_digital'])
</script>
```

## Configuração e Instanciação

Para começar, crie uma nova instância da classe `WebOCR`. O construtor exige dois parâmetros obrigatórios, na ordem especificada abaixo:

- **webToken** `(String)`: Seu token de autenticação para uso da API.
- **sessionId** `(String)`: Um identificador único para a sessão do usuário.

### Personalização (Opcional)

Após criar a instância, utilize os seguintes métodos encadeados para personalizar a experiência:

- **`setThemeConfiguration`** `(object)`: Personaliza a aparência do SDK. Campos aceitos:
    - `primaryColor` `(String)`: Cor principal em formato hexadecimal — usada em botões, ícones e destaques (ex: `'#0000FF'`).
    - `companyLogo` `(String)`: URL ou path para o logo da sua empresa.
    - `fontFamily` `(String)`: Família da fonte (ex: `'Arial'`).

- **`setShowInstructionScreen`** `(boolean)`: Define se a tela inicial de instruções será exibida.

- **`setShowAllowedTemplatesScreen`** `(boolean)`: Define se a tela que informa os documentos aceitos será exibida. Recomendamos ativá-la para que o usuário saiba quais documentos pode enviar.

- **`setShowSuccessScreen`** `(boolean)`: Define se a tela de sucesso ao final da captura será exibida.

- **`setSandboxEnvironment`**: Configura o SDK para apontar para o ambiente de homologação (Sandbox).

### Build

Por fim, você **deve** chamar a função **build()** para instanciar a classe **WebOCR** com as configurações passadas. Para mais detalhes sobre o construtor, veja a página sobre o [construtor](./constructor_info.md).

## Inicializando a Captura de Documentos

Com a instância da `WebOCR` devidamente configurada, chame o método `initialize()` para iniciar o fluxo de captura. Este método recebe como parâmetro uma lista (array) de strings, onde cada string representa um tipo de documento que o usuário poderá enviar.

### Tabela com templates aceitos

Nome | Tipo | Descrição
---- | ---- | ---------
cnh | String | Captura de CNH física (fechada), em duas etapas, FRENTE e VERSO
rg | String | Captura de RG físico (fechado), em duas etapas, FRENTE e VERSO
cin_digital | String | Envio da CIN **digital** (pdf) emitida por um aplicativo oficial
rg_digital | String | Envio do RG **digital** (pdf) emitido por um aplicativo oficial
rne | String | Captura do RNE físico, em duas etapas, FRENTE e VERSO
crnm | String | Captura da CRNM física, em duas etapas, FRENTE e VERSO
others | String | Deve ser usado para permitir o envio de outros documentos além dos listados acima

:::caution Atenção
Adicionar o tipo `others` nos templates permitidos faz com que todo documento enviado seja aceito. Assim, mesmo documentos não oficiais serão aceitos.
:::

### Tratamento do Retorno

O método `initialize()` retorna uma Promise:

- **Sucesso:** A Promise é resolvida com um **array de objetos**, onde cada objeto representa um lado do documento capturado. Consulte a página [Coletando os Retornos](./collecting_results.md) para detalhes sobre o formato.
- **Erro:** A Promise é rejeitada. Você pode capturar esses erros utilizando o método `.catch()`.

---

# Importando a biblioteca

URL: /documentation/caas/ocr/web/import

Para importar a nossa biblioteca, adicione a URL no _src_ de uma TAG **script** no HTML de seu website, assim como o exemplo abaixo:

```html
    <script src="https://ocr.caas.qitech.app/4-1-1/ocr.js"></script>
```

---

# A função initialize()

URL: /documentation/caas/ocr/web/initialize_info

Para iniciar a Web OCR SDK, após ter instanciado a classe **WebOCR**, chame a função **initialize()** passando uma lista de documentos permitidos como parâmetro.

Abaixo temos o detalhamento de cada um dos possíveis tipos de documento:

Nome | Tipo | Descrição
---- | ---- | ---------
cnh | String | Captura de CNH física (fechada), em duas etapas, FRENTE e VERSO
rg | String | Captura de RG físico (fechado), em duas etapas, FRENTE e VERSO
cin_digital | String | Envio da CIN **digital** (pdf) emitida por um aplicativo oficial
rg_digital | String | Envio do RG **digital** (pdf) emitido por um aplicativo oficial
rne | String | Captura do RNE físico, em duas etapas, FRENTE e VERSO
crnm | String | Captura da CRNM física, em duas etapas, FRENTE e VERSO
others | String | Deve ser usado para permitir o envio de outros documentos além dos listados acima

:::caution Atenção
Adicionar o tipo `others` nos templates permitidos faz com que todo documento enviado seja aceito. Assim, mesmo documentos não oficiais serão aceitos.
:::

## Exemplo de Implementação

Um exemplo de implementação da Web OCR SDK pode ser visto abaixo:

```html
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web OCR</title>
    <script src="https://ocr.caas.qitech.app/4-1-1/ocr.js"></script>
</head>
<body>
    <div class="demo-app-container">
        <button onclick="initOCR(['rg', 'cnh', 'rg_digital'])">
            Iniciar coleta do documento
        </button>
    </div>
</body>

<script>
    var webOCR = new QiTechWebOCR.WebOCR(
        "<WEB_TOKEN>",
        "<SESSION_ID>"
    )
    .setThemeConfiguration({
        "companyLogo": "https://my_company/logo.png",
        "primaryColor": "#FF9900",
        "fontFamily": "Verdana"
    })
    .setShowInstructionScreen(true)
    .setShowSuccessScreen(true)
    .setShowAllowedTemplatesScreen(true)
    .setSandboxEnvironment()
    .build()

    function initOCR(allowed_templates) {
        webOCR.initialize(allowed_templates)
        .then((ocr_results) => {
            console.log(ocr_results)
        })
        .catch((error) => {
            console.log(error)
        })
    }
</script>
</html>
```

No exemplo acima, a instância da classe **WebOCR** é criada com os parâmetros obrigatórios e opcionais. Com o SDK instanciado, a função **initOCR()** inicializa o fluxo de captura e, ao final, registra em log o array de resultados retornados ou o erro, caso ocorra.

## Tratamento do Retorno

O método `initialize()` retorna uma Promise:

- **Sucesso:** A Promise é resolvida com um **array de objetos**, onde cada objeto representa um documento capturado. Consulte a página [Coletando os Retornos](./collecting_results.md) para detalhes sobre o formato.

- **Erro:** A Promise é rejeitada. Você pode capturar esses erros utilizando o método `.catch()`.

---

# Introdução

URL: /documentation/caas/ocr/web/introduction

Bem-vindo à Web OCR SDK (Optical Character Recognition) da QI Tech para leitura de documentos. Este SDK realiza a captura de documentos e o envio a API de OCR da QI Tech . Você pode utilizá-lo para capturar através do seu aplicativo web uma imagem de um documento de seu cliente a ser reconhecido, como uma Carteira de Habilitação ou Cédula de Identidade, e referenciá-lo através de uma chave nos demais produtos do sistema QI Tech.

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso [suporte](mailto:suporte.caas@qitech.com.br) e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já entendeu), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

---

# Autenticação

URL: /documentation/caas/onboarding/authentication

> Para autenticar uma chamada, utilize o código seguinte:

```shell
# No shell, você somente precisa adicionar o header adequado em cada requisição
curl "api_endpoint_here"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> Substitua a API Key 'EXAMPLE-OF-API-KEY' pela sua chave, que deve ser obtida através do nosso time de suporte.

Utilizamos uma API Key para permitir acesso a nossa API. Ela provavelmente já foi enviada por e-mail para você. Caso você ainda não tenha recebido a sua chave, envie um e-mail para suporte.caas@qitech.com.br .

Nossa API espera receber a API Key em todas as requisições ao nosso servidor em um header como o abaixo:

`Authorization: EXAMPLE-OF-API-KEY`

:::info **Atenção**

Você deve substituir EXAMPLE-OF-API-KEY pela sua chave, que deve ser obtida através do nosso time de suporte.
:::

---

# Status HTTP

URL: /documentation/caas/onboarding/http_status

Todas as APIs da QI Tech utilizam a seguinte padronização nos status HTTP de retorno, de acordo com o RFC 7231 :

Status HTTP | Significado | Descrição
---------- | ------- | ---------------------------------
400 | Bad Request | A requisição enviada possui algum erro de formatação. Na maioria dos casos, retornamos no corpo da mensagem uma explicação de onde está o erro.
401 | Unauthorized | Houve algum problema na autenticação, verifique se a API Key está correta e no header correto, de acordo com a seção Autenticação .
403 | Forbidden | O endpoint acessado é de uso interno e não está disponível para esta API Key.
404 | Not Found | O dado requisitado não foi encontrado usando a chave utilizada. Este status também é retornado quando um endpoint inválido é requisitado.
405 | Method Not Allowed | O método HTTP utilizado não se aplica ao endpoint utilizado.
406 | Not Acceptable | Os dados enviados no corpo da requisição são inválidos. Em geral, isso significa que os dados enviados não são um JSON válido.
409 | Conflict | O id da requisição corresponde a um id já processado anteriormente. Este status é retornado no caso de requisições duplicadas enviadas ao servidor.
500 | Internal Server Error | Tivemos um problema para processar esta requisição, ao encontrarmos esse erro nossos especialistas são automaticamente notificados e iniciam a análise e solução imediatamente.
503 | Service Unavailable | Você se deparou com uma indisponibilidade, planejada ou não, de infraestrutura dos nossos servidores.

---

# Integrações

URL: /documentation/caas/onboarding/integrations

Nossas soluções mobile são compatíveis com as mais diversas tecnologias como Flutter, Ionic Cordova, Capacitor, React Native, Java, Swift entre outras. Caso tenha interesse em alguma dessas integrações, entre em contato com nosso suporte para liberarmos acesso aos nossos repositórios privados.

---

# Introdução

URL: /documentation/caas/onboarding/introduction

Bem vindo à API de Onboarding da QI Tech! Esta API dá acesso aos serviços de Prevenção a Fraudes, à lavagem de dinheiro e de KYC em um Cadastro da sua plataforma! 

Esta API pode ser utilizada para a validação cadastral de clientes para:

* Abertura de Contas Digitais ou Wallets
* Emissão de Cartão
* Validação de Usuários de Aplicativos
* Cadastro para Concessão de Crédito
* Cadastro para Contratação de Seguros
* Validação de Dados Cadastrais

Você pode utilizar a nossa API para acessar os endpoints para avaliar os seguintes tipos de Cadastro:

* **Natural Person** - utilizado para validação cadastral de Pessoas Físicas
* **Legal Person** - utilizado para validação cadastral de Pessoas Jurídicas

Os diferentes tipos de Cadastro acima possuem objetos e endpoints específicos com o intuito de cobrir as particularidades de cada entidade. 

## Como funciona

| Passo | Chamada | O que faz |
| --- | --- | --- |
| 1 | `POST /onboarding/natural_person` ou `/legal_person` | Envia o cadastro; a QI Tech executa a sua árvore de decisão e devolve o resultado em `analysis_status`. |
| 2 | `PUT /onboarding/{tipo}/{id}` | Informa o desfecho na sua plataforma (`client_status`). Retroalimenta os modelos. |
| 3 | `GET /onboarding/{tipo}/{id}` | Consulta o estado atual e o histórico de eventos. |

Resultados assíncronos chegam por [Webhook](/documentation/caas/onboarding/webhook).

:::tip Integre em minutos
São apenas **3 campos obrigatórios** em cada tipo de cadastro. Comece pelo payload mínimo em [Natural Person](/documentation/caas/onboarding/natural_person#payload-minimo) ou [Legal Person](/documentation/caas/onboarding/legal_person#payload-minimo), com exemplos em Python, PHP, Node.js, Java, C# e curl.
:::

:::info Usa os SDKs de biometria, OCR ou Device Scan?
As chaves devolvidas pelos SDKs entram em lugares diferentes em PF e PJ. Veja [Dados do SDK](/documentation/caas/onboarding/sdk_integration).
:::

## Problemas?

Nós não somos uma companhia que se esconde atrás de uma API! Entre em contato com o nosso suporte e nós responderemos o mais rápido possível. Fique à vontade para nos ligar caso deseje uma resposta rápida!

### Adoramos Feedback

Mesmo que você já tenha resolvido o seu problema ou que ele seja muito simples (Até mesmo um typo ou uma organização inadequada que você já notou), envie-nos um e-mail, assim nós tornamos a documentação cada vez mais prática e a próxima pessoa não vai precisar sofrer as dores que você sofreu!

## Ambientes

Possuímos dois ambientes para os nossos clientes. As URLs base das APIs são:

* Produção - `https://api.caas.qitech.app/onboarding/`
* Sandbox - `https://api.sandbox.caas.qitech.app/onboarding/`

:::danger Aviso Importante!
Não devem ser usados dados reais de pessoas físicas e/ou jurídicas nos ambientes de Sandbox da QI Tech.  
:::

No ambiente de Sandbox, as análises enviadas não são cobradas e são respondidas de acordo com a seguinte regra baseada no primeiro dígito do documento - CPF para Pessoas Físicas e CNPJ para Pessoas Jurídicas:

Dígito | Decisão
------ | -------
0 | Em Análise Manual
1 | Em Análise Manual
2 | Em Análise Manual
3 | Em Análise Manual
4 | Contestado Automaticamente
5 | Derivado para Análise Manual - Com reprovação posterior
6 | Derivado para Análise Manual - Com aprovação posterior
7 | Pendente
8 | Reprovado Automaticamente
9 | Aprovado Automaticamente

Nos casos de CPF ou CNPJ com início nos dígitos 1 ou 2, deve-se entrar em contato com nosso suporte para que a tratativa manual seja feita corretamente.

## Somente HTTPS

Por questão de segurança, toda a comunicação com as APIs da QI Tech deve ser realizada utilizando a comunicação HTTPS. Para evitar que, por desatenção ou outro motivo, sejam feitas chamadas HTTP, este servidor somente disponibiliza a porta 443 com comunicação TLS 1.2. Chamadas realizadas utilizando outros protocolos serão automaticamente negadas.

---

# Objeto Legal Person

URL: /documentation/caas/onboarding/legal_person

Objeto Legal Person

Envia o cadastro de uma **pessoa jurídica** para análise de fraude e KYC. A QI Tech executa a sua árvore de decisão contra os dados enviados e devolve em `analysis_status` o resultado que a **sua política** determinou — veja [Dinâmica dos status](/documentation/caas/onboarding/status_dynamics).

:::tip Comece pelo payload mínimo
São apenas **3 campos obrigatórios**. Vá direto para [Payload mínimo](#payload-minimo).
:::

:::danger Onde entram as chaves do SDK
Em Legal Person, `face` e documentos de identidade ficam **dentro de `legal_representatives[]`**, e o `source.session_id` fica na **raiz**. Essa é a principal diferença em relação a Pessoa Física — veja [Integrando os dados do SDK](/documentation/caas/onboarding/sdk_integration).
:::

---

## Payload mínimo

```json title="Payload mínimo — 3 campos obrigatórios"
{
  "id": "87654321",
  "registration_date": "2026-08-07T11:37:15-03:00",
  "document_number": "11.111.111/0001-11"
}
```

Resposta:

```json
{
  "id": "87654321",
  "analysis_status": "automatically_approved",
  "reason": "rule_decision_enum"
}
```

:::info Campos adicionais
Quanto mais dados forem enviados, mais validações são possíveis de se fazer no motor de regras.
:::

---

## Enviar um cadastro

ENDPOINT /onboarding/legal_person
MÉTODO POST

### Query parameters

analyze
boolean
opcional — padrão true
Com true , a sua árvore de decisão é executada. Com false , o cadastro é apenas registrado (sem cobrança) e a resposta retorna not_analysed .

**Python**

```python
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**

```php
<?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 retornou HTTP {$status}: {$body}");
}

echo json_decode($body, true)['analysis_status'];
```

**Node.js**

```javascript
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 retornou HTTP ${response.status}`);
  }

  const result = await response.json();
  console.log(result.analysis_status);
  return result;
}

createLegalPerson();
```

**Java**

```java
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 retornou HTTP " + response.statusCode() + ": " + response.body());
        }

        System.out.println(response.body());
    }
}
```

**C#**

```csharp
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 retornou HTTP {(int)response.StatusCode}: {body}");
        }

        Console.WriteLine(body);
    }
}
```

**curl**

```bash
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"
  }'
```

---

## Campos do objeto

### Obrigatórios

id
string
obrigatório
Identificador da análise. 1 a 50 caracteres. Único por requisição — repetido retorna HTTP 409.

registration_date
datetime
obrigatório
Data e hora do cadastro, com fuso horário. Mesmo formato de Natural Person.

document_number
string
obrigatório
CNPJ com pontuação , no formato XX.XXX.XXX/XXXX-XX . 18 caracteres.

### Dados da empresa

registration_id
string
opcional
Identificador do cadastro no seu sistema. Assume o valor de id quando omitido.

legal_name
string
opcional
Razão social.

trading_name
string
opcional
Nome fantasia.

foundation_date
date
opcional
Data de constituição no formato YYYY-MM-DD .

website
string
opcional
Site da empresa. Até 10.000 caracteres.

activity
string
opcional
Descrição da atividade econômica.

activity_code
string
opcional
CNAE no formato XX.XX-X-XX . Exatamente 10 caracteres.

merchant_category_code
enum
opcional
MCC de 4 dígitos conforme ISO 18245. Aceita apenas códigos da lista oficial.

tier
string
opcional
Porte da empresa. Até 10 caracteres. Ex.: mei , epp , me .

annual_revenues
integer
opcional
Faturamento anual em centavos .

monthly_revenues
integer
opcional
Faturamento mensal em centavos .

### Contato e localização

emails
array
opcional
Lista de objetos Email . Cada item exige email .

phones
array
opcional
Lista de objetos Phone . Cada item exige international_dial_code , area_code e number .

address
object
opcional
Objeto Address . Se enviado, exige postal_code .

documents
object
opcional
Documentos da empresa . Aceita apenas ie , company_statute e proof_of_address — veja o aviso abaixo, Dados do SDK e Objetos compartilhados .

source
object
opcional
Origem da requisição. É aqui na raiz que o session_id do Device Scan deve ser enviado — veja Dados do SDK .

### Quadro societário

legal_representatives
array
opcional
Lista de objetos LegalRepresentative . É dentro deste array que entram face e documentos de identidade (RG, CNH) — veja Dados do SDK .

partners
array
opcional
Lista de objetos Partner com os sócios da empresa.

final_beneficiaries
array
opcional
Lista de objetos FinalBeneficiary com os beneficiários finais.

### Classificação e extras

analysis_type
string
opcional
Tipo de análise, quando sua conta tem mais de um fluxo configurado.

client_category
string
opcional
Categoria do cliente na sua plataforma.

partnership_key
string
opcional
Identificador da parceria associada.

related_account_type
string
opcional
Tipo de conta relacionada.

custom_data
object
opcional
Campos personalizados. Requer schema previamente cadastrado pela QI Tech.

```json title="Payload completo"
{
  "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"
    }
  ]
}
```

:::warning Campos não previstos são rejeitados
O schema usa `additionalProperties: false`. Qualquer campo fora dos listados retorna **HTTP 400**.
:::

:::danger RG e CNH não vão na raiz
Na raiz de Legal Person, `documents` aceita **apenas** `ie`, `company_statute` e `proof_of_address`. Documentos de identidade pertencem ao representante legal, dentro de `legal_representatives[].documents`. Enviá-los na raiz retorna **HTTP 400**.
:::

---

## Formatos de campo

### `document_number` — CNPJ

Formato `XX.XXX.XXX/XXXX-XX`, com pontuação, 18 caracteres. Apenas dígitos é rejeitado.

### `activity_code` — CNAE

Formato `XX.XX-X-XX`, exatamente 10 caracteres. Ex.: `96.02-5-01`.

### `registration_date`

Mesmo formato de Natural Person: ISO 8601 com fuso horário, offset terminado em `:00`/`:30` ou sufixo `Z`.

### Valores monetários

`annual_revenues` e `monthly_revenues` são inteiros em **centavos**. R$ 150.000,00 → `15000000`.

---

## Representantes, sócios e beneficiários

Os três arrays aceitam os mesmos campos de identificação de uma pessoa física (`name`, `document_number`, `birthdate`, `gender`, `nationality`, `mother_name`, `occupation`, `emails`, `phones`, `address`, `pleaded_pep`).

**Somente `legal_representatives[]` aceita `face` e `documents`** — é ali que entram as chaves de biometria e OCR do representante. Veja [Integrando os dados do SDK](/documentation/caas/onboarding/sdk_integration).

---

## Testando no Sandbox

A decisão é determinística, definida pelo **primeiro dígito do CNPJ**:

| Primeiro dígito | Resultado |
| --- | --- |
| `9` | `automatically_approved` |
| `8` | `automatically_reproved` |
| `7` | `pending` |
| `6` | Análise manual, com aprovação posterior |
| `5` | Análise manual, com reprovação posterior |
| `4` | `automatically_challenged` |
| `0` a `3` | `in_manual_analysis` |

:::danger Aviso importante
Não utilize dados reais de pessoas jurídicas no ambiente de Sandbox.
:::

---

## Erros

| Status | Situação | Como resolver |
| --- | --- | --- |
| 400 | Campo obrigatório ausente, formato inválido ou campo não previsto. | Veja a `description` da resposta. |
| 400 | `rg`/`cnh` na raiz de `documents`. | Mova para `legal_representatives[]`. |
| 400 | `custom_data` sem schema cadastrado. | Solicite o cadastro ao suporte. |
| 401 | Header `Authorization` ausente ou chave desativada. | Verifique a chave. |
| 403 | API Key inválida. | Confirme com o suporte. |
| 409 | `id` já utilizado. | Gere um `id` único. |
| 500 | Erro interno. | Notificação automática à nossa equipe. |

Lista completa em [Status HTTP](/documentation/caas/onboarding/http_status).

---

## Checklist de integração

- [ ] `POST /onboarding/legal_person` com o payload mínimo retornando `200` no Sandbox.
- [ ] CNPJ com pontuação e CNAE no formato `XX.XX-X-XX`.
- [ ] `source.session_id` preenchido **na raiz** (sem isso, o device não aparece na dashboard de PJ).
- [ ] `face` e documentos de identidade dentro de `legal_representatives[]`.
- [ ] Na raiz de `documents`, apenas `ie`, `company_statute`, `proof_of_address`.
- [ ] Valores monetários em centavos.
- [ ] [Webhook](/documentation/caas/onboarding/webhook) configurado para o resultado assíncrono.

---

# Objeto Natural Person

URL: /documentation/caas/onboarding/natural_person

Objeto Natural Person

Envia o cadastro de uma **pessoa física** para análise de fraude e KYC. A QI Tech executa a sua árvore de decisão contra os dados enviados e devolve em `analysis_status` o resultado que a **sua política** determinou — veja [Dinâmica dos status](/documentation/caas/onboarding/status_dynamics).

:::tip Comece pelo payload mínimo
São apenas **3 campos obrigatórios**. Vá direto para [Payload mínimo](#payload-minimo) e depois adicione o que fizer sentido para o seu caso.
:::

:::caution Envie dados finais
Os dados enviados devem ser os definitivos. CPF, nome e data de nascimento não devem mudar depois desta chamada — isso garante consistência da base antifraude e uma avaliação realista de risco.
:::

:::info Usa os SDKs de biometria, OCR ou Device Scan?
As chaves devolvidas pelos SDKs entram nos blocos `face`, `documents` e `source` deste payload. Onde cada uma vai — e o que muda em relação a Pessoa Jurídica — está em **[Dados do SDK (face, documentos e device)](/documentation/caas/onboarding/sdk_integration)**.
:::

---

## Payload mínimo

Este é o menor corpo aceito pelo `POST /onboarding/natural_person`.

```json title="Payload mínimo — 3 campos obrigatórios"
{
  "id": "12345678",
  "registration_date": "2026-08-07T11:37:15-03:00",
  "document_number": "111.111.111-11"
}
```

Resposta:

```json
{
  "id": "12345678",
  "analysis_status": "automatically_approved",
  "reason": "rule_decision_enum"
}
```

:::info Campos adicionais
Quanto mais dados forem enviados, mais validações são possíveis de se fazer no motor de regras.
:::

---

## Enviar um cadastro

ENDPOINT /onboarding/natural_person
MÉTODO POST

### Query parameters

analyze
boolean
opcional — padrão true
Com true , a sua árvore de decisão é executada e a resposta traz o resultado. Com false , o cadastro é apenas registrado (sem cobrança) e passa a compor o histórico usado em análises futuras — a resposta retorna not_analysed .

### Exemplos de requisição

**Python**

```python
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
```

**PHP**

```php
<?php

$baseUrl = 'https://api.sandbox.caas.qitech.app';
$apiKey  = 'YOUR_API_KEY';

$payload = [
    'id'                => '12345678',
    'registration_date' => '2026-08-07T11:37:15-03:00',
    'document_number'   => '111.111.111-11'
];

$ch = curl_init($baseUrl . '/onboarding/natural_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 retornou HTTP {$status}: {$body}");
}

$result = json_decode($body, true);
echo $result['analysis_status'];
```

**Node.js**

```javascript
const BASE_URL = "https://api.sandbox.caas.qitech.app";
const API_KEY = "YOUR_API_KEY";

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

async function createRegistration() {
  const response = await fetch(
    `${BASE_URL}/onboarding/natural_person?analyze=true`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: API_KEY
      },
      body: JSON.stringify(payload)
    },
  );

  if (!response.ok) {
    throw new Error(`Onboarding retornou HTTP ${response.status}`);
  }

  const result = await response.json();
  console.log(result.analysis_status);
  return result;
}

createRegistration();
```

**Java**

```java
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 CreateNaturalPerson {

    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": "12345678",
              "registration_date": "2026-08-07T11:37:15-03:00",
              "document_number": "111.111.111-11"
            }
            """;

        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(BASE_URL + "/onboarding/natural_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 retornou HTTP " + response.statusCode() + ": " + response.body());
        }

        System.out.println(response.body());
    }
}
```

**C#**

```csharp
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class CreateNaturalPerson
{
    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 = "12345678",
            registration_date = "2026-08-07T11:37:15-03:00",
            document_number = "111.111.111-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/natural_person?analyze=true", content);

        var body = await response.Content.ReadAsStringAsync();

        if (!response.IsSuccessStatusCode)
        {
            throw new InvalidOperationException(
                $"Onboarding retornou HTTP {(int)response.StatusCode}: {body}");
        }

        Console.WriteLine(body);
    }
}
```

**curl**

```bash
curl -X POST \
  'https://api.sandbox.caas.qitech.app/onboarding/natural_person?analyze=true' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: YOUR_API_KEY' \
  -d '{
    "id": "12345678",
    "registration_date": "2026-08-07T11:37:15-03:00",
    "document_number": "111.111.111-11"
  }'
```

### Resposta

id
string
O mesmo id enviado na requisição.

analysis_status
enum
Resultado da execução da sua árvore de decisão. Veja Dinâmica dos status .

reason
string
Motivo da decisão, quando disponível.

```json
{
  "id": "12345678",
  "analysis_status": "automatically_approved",
  "reason": "rule_decision_enum"
}
```

:::info Resposta assíncrona
Quando a análise demora mais que o esperado, a resposta vem como `in_queue` ou `pending` e o resultado final chega por [Webhook](/documentation/caas/onboarding/webhook). Trate esses dois status como "aguardando" — não como recusa.
:::

---

## Campos do objeto

### Obrigatórios

id
string
obrigatório
Identificador da análise no seu sistema. 1 a 50 caracteres. Deve ser único por requisição — um id repetido retorna HTTP 409.

registration_date
datetime
obrigatório
Data e hora do cadastro, com fuso horário . Veja o formato aceito .

document_number
string
obrigatório
CPF com pontuação , no formato XXX.XXX.XXX-XX . Exatamente 14 caracteres.

### Identificação

registration_id
string
opcional
Identificador do cadastro no seu sistema. Use o mesmo valor em análises diferentes do mesmo cadastro para agrupá-las. Quando omitido, assume o valor de id .

name
string
opcional
Nome completo. 1 a 500 caracteres.

birthdate
date
opcional
Data de nascimento no formato YYYY-MM-DD .

gender
enum
opcional
male ou female .

nationality
string
opcional
País em ISO 3166-1 alpha-3, 3 letras maiúsculas. Ex.: BRA .

mother_name
string
opcional
Nome completo da mãe. 1 a 500 caracteres. Sinal relevante para validação em bureaus.

father_name
string
opcional
Nome completo do pai. 1 a 500 caracteres.

### Perfil financeiro

monthly_income
integer
opcional
Renda mensal bruta em centavos . R$ 5.000,00 → 500000 .

declared_assets
integer
opcional
Patrimônio declarado em centavos .

occupation
string
opcional
Profissão. 1 a 100 caracteres.

is_us_person
boolean
opcional
Indica se a pessoa tem obrigações fiscais nos EUA (relevante para FATCA).

pleaded_pep
boolean
opcional
Indica se a pessoa se declarou politicamente exposta (PEP).

### Contato e localização

emails
array
opcional
Lista de objetos Email . Dentro de cada item, apenas email é obrigatório.

phones
array
opcional
Lista de objetos Phone . Se enviado, cada item exige international_dial_code , area_code e number .

address
object
opcional
Objeto Address . Se enviado, apenas postal_code é obrigatório dentro dele.

documents
object
opcional
Documentos de identificação (RG, CNH, passaporte e outros). As chaves de OCR entram aqui — veja Dados do SDK e Objetos compartilhados .

face
object
opcional
Dados de validação facial. A chave devolvida pelo SDK de biometria entra aqui — veja Dados do SDK .

source
object
opcional
Origem da requisição (canal, plataforma, IP, sessão). É aqui que entra o session_id do Device Scan — veja Dados do SDK .

### Classificação e extras

analysis_type
string
opcional
Tipo de análise a aplicar, quando sua conta tem mais de um fluxo configurado. Combine com o suporte antes de usar.

client_category
string
opcional
Categoria do cliente na sua plataforma ou programa de fidelidade. 1 a 100 caracteres.

partnership_key
string
opcional
Identificador da parceria associada ao cadastro. 1 a 500 caracteres.

related_account_type
string
opcional
Tipo de conta relacionada ao cadastro. 1 a 50 caracteres.

vehicle_plate
string
opcional
Placa de veículo associada ao cadastro. 1 a 50 caracteres.

custom_data
object
opcional
Campos personalizados da sua conta. Requer um schema previamente cadastrado pela QI Tech — veja o aviso abaixo.

```json title="Payload completo"
{
  "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"
  }
}
```

:::warning Campos não previstos são rejeitados
O schema usa `additionalProperties: false`. Qualquer campo fora dos listados acima faz a requisição retornar **HTTP 400**, mesmo que o resto do payload esteja correto.
:::

:::caution `custom_data` exige schema próprio
`custom_data` é validado contra um schema específico da sua empresa, registrado pela QI Tech. Se você enviar esse campo sem ter o schema cadastrado, a resposta é **HTTP 400** com a mensagem *"Custom data not available for you account"*. Fale com o [suporte](mailto:suporte.caas@qitech.com.br) antes de usar.
:::

---

## Formatos de campo

### Formato de `registration_date`

Formato ISO 8601 **com fuso horário obrigatório**. O validador aceita offsets terminados em `:00` ou `:30`, ou o sufixo `Z`:

```text
2026-08-07T11:37:15-03:00          ✅
2026-08-07T11:37:15.123456-03:00   ✅  fração de 1 a 6 dígitos
2026-08-07T14:37:15Z               ✅  UTC
2026-08-07T11:37:15                ❌  sem fuso horário
2026-08-07T11:37:15-03:15          ❌  offset não permitido
```

### `document_number` — CPF

Deve ir **com pontuação**: `XXX.XXX.XXX-XX`, exatamente 14 caracteres. Enviar apenas dígitos (`11111111111`) retorna HTTP 400.

### `postal_code` — CEP

Dentro de `address`, o CEP exige o formato `XXXXX-XXX` (com hífen). `00000000` é rejeitado.

### Valores monetários

`monthly_income` e `declared_assets` são inteiros em **centavos de reais**. Multiplique por 100: R$ 5.000,00 → `500000`.

---

## Enumeradores

### `gender`

| Valor | Significado |
| --- | --- |
| `male` | Masculino |
| `female` | Feminino |

### `phones[].type`

| Valor | Significado |
| --- | --- |
| `mobile` | Celular |
| `residential` | Residencial |
| `commercial` | Comercial |

| `visit` | Confirmado por visita presencial |
| `zaig_sdk` | Confirmado pelo SDK da QI Tech |
| `zaig_ocr` | Confirmado por OCR de comprovante |

### `face.type`

| Valor | Significado |
| --- | --- |
| `zaig_sdk` | Captura via SDK da QI Tech (use `registration_key`) |
| `base_64` | Imagem enviada diretamente no campo `image` |

Para `analysis_status`, `client_status` e `risk_level`, veja [Dinâmica dos status](/documentation/caas/onboarding/status_dynamics).

---

## Testando no Sandbox

No Sandbox a decisão é determinística, definida pelo **primeiro dígito do CPF**:

| Primeiro dígito | Resultado |
| --- | --- |
| `9` | `automatically_approved` |
| `8` | `automatically_reproved` |
| `7` | `pending` |
| `6` | Análise manual, com aprovação posterior |
| `5` | Análise manual, com reprovação posterior |
| `4` | `automatically_challenged` |
| `0` a `3` | `in_manual_analysis` |

:::danger Aviso importante
Não utilize dados reais de pessoas físicas no ambiente de Sandbox.
:::

---

## Erros

| Status | Situação | Como resolver |
| --- | --- | --- |
| 400 | Campo obrigatório ausente, formato inválido, enum fora da lista ou campo não previsto. | Veja a `description` da resposta, que aponta o campo. |
| 400 | `custom_data` sem schema cadastrado. | Solicite o cadastro do schema ao suporte. |
| 401 | Header `Authorization` ausente ou API Key desativada. | Verifique a chave. |
| 403 | API Key inválida. | Confirme a chave com o suporte. |
| 409 | `id` já utilizado. | Gere um `id` único por requisição. |
| 500 | Erro interno. | Nossos especialistas são notificados automaticamente. |

Lista completa em [Status HTTP](/documentation/caas/onboarding/http_status).

---

## Checklist de integração

- [ ] `POST /onboarding/natural_person` com o payload mínimo retornando `200` no Sandbox.
- [ ] `id` único por requisição (teste o `409` reenviando o mesmo `id`).
- [ ] `registration_id` estável para agrupar análises do mesmo cadastro.
- [ ] CPF com pontuação e CEP com hífen.
- [ ] Valores monetários em centavos.
- [ ] `in_queue` e `pending` tratados como "aguardando", não como recusa.
- [ ] [Webhook](/documentation/caas/onboarding/webhook) configurado para receber o resultado assíncrono.

---

# Objetos Compartilhados

URL: /documentation/caas/onboarding/objects

Boa parte dos dados são compartilhados entre várias APIs. Abaixo as definições destes objetos podem ser localizadas de maneira facilitada.

## Objeto *email*

Request Body

```json
{
  "email": "johnsample@test.com"
}
```

O objeto *email* é utilizado para representar os e-mails em toda a API bem como se foi utilizado algum meio de validação dos mesmos. Eles são representados da seguinte maneira:

nome | tipo | restrições | descrição
---- | :----: | :----: | ---------
email | string | 1–100 caracteres | Endereço de e-mail cadastrado. *(obrigatório)*

## Objeto *cnh*

Request Body

```json
{
  "register_number": "05163811694",
  "issuer_state": "PR",
  "first_issuance_date":"2011-03-21",
  "issuance_date":"2016-06-29",
  "expiration_date":"2021-06-25",
  "category": "AB",
  "ocr_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76"
}
```

O objeto *cnh* é utilizado para representar as CNHs em toda a API bem como se foi utilizado algum meio de validação dos mesmos. Eles são representados da seguinte maneira:

nome | tipo | descrição
---- | :----: | ---------
register_number | string | Número do registro da CNH cadastrada.
issuer_state | enum | Enumerador do estado onde a CNH foi emitida
first_issuance_date | date | Data de primeira habilitação.
issuance_date | date | Data de emissão
expiration_date | date | Data de vencimento
category | enum | Categoria da CNH em letras maiúsculas
ocr_key | guid | Id retornado pela API de validação de documento da QI Tech.

## Objeto *rg*

Request Body

```json
{
  "number": "4.366.477-8",
  "issuer": "II",
  "issuer_state": "PR",
  "issuance_date":"2002-01-12",
  "ocr_front_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76",
  "ocr_back_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76"
}
```

O objeto *rg* é utilizado para representar os RGs em toda a API bem como se foi utilizado algum meio de validação dos mesmos. Eles são representados da seguinte maneira:

nome | tipo | descrição
---- | :----: | ---------
number | string | Número do documento cadastrado, incluindo formatação (Pontos, Hífens, Barras e outros).
issuer | string | Órgão emissor do documento (Sigla, e.g.: II, SESP...)
issuer_state | enum | UF emissor do documento.
issuance_date | date | Data de emissão do documento.
ocr_key | guid | Id retornado pela API de validação de documento da QI Tech.

## Objeto *ie*

Request Body

```json
{
  "number": "388.108.598.269",
  "issuer": "JUCESP",
  "issuer_state": "SP",
  "issuance_date":"2002-01-12",
  "ocr_key": "c64627db-1ba4-48b6-979d-06222a25d5e9"
}
```

O objeto *ie* é utilizado para representar as Inscrições Estaduais dentro do objeto de *documents* no endpoint de *legal_person*, bem como se foi utilizado algum meio de validação do mesmo. Ele é representado da seguinte maneira:

nome | tipo | descrição
---- | :----: | ---------
number | string | Número do documento cadastrado, incluindo formatação (Pontos, Hífens, Barras e outros).
issuer | string | Órgão emissor do documento (Sigla, e.g.: JUCESP, JUCEGO...)
issuer_state | enum | UF emissor do documento.
issuance_date | date | Data de emissão do documento.
ocr_key | guid | Id retornado pela API de validação de documento da QI Tech.

## Objeto *company_statute*

Request Body

```json
{
  "ocr_key": "60ed79c4-5aba-4cc7-aebb-5de5f92b7d0d"
}
```

O objeto *company_statute* é utilizado para representar documentos de constituição de empresas, como por exemplo um Contrato Social dentro do objeto de *documents* no endpoint de *legal_person*. Ele é representado da seguinte maneira:

nome | tipo | descrição
---- | :----: | ---------
ocr_key | guid | Id retornado pela API de OCR da QI Tech após envio da imagem ou PDF de um documento de constuição de uma empresa.

## Objeto *letter_attorney*

Request Body

```json
{
  "ocr_key": "13571175-b1d9-4507-82e0-d266516fc5ae"
}
```

O objeto *letter_attorney* é utilizado para representar procurações que instituem poderes a representantes legais dentro do objeto de *documents* no endpoint de *legal_person*. Ele é representado da seguinte maneira:

nome | tipo | descrição
---- | :----: | ---------
ocr_key | guid | Id retornado pela API de OCR da QI Tech após envio da imagem ou PDF de uma procuração.
## Objeto *address*

Request Body

```json
{
  "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",
  "ocr_key": "265b1b74-4b93-41dc-ac78-e1c37467225d"
}
```

O objeto *address* é utilizado para representar endereços em toda a API, endereços no território brasileiro são representados da seguinte maneira:

nome | tipo | restrições | descrição
---- | :----: | :----: | ---------
street | string | 1–100 caracteres | Rua do endereço, incluindo o logradouro, evitando, se possível, abreviações.
number | string | 1–50 caracteres | Número do imóvel, incluindo letras caso possua.
neighborhood | string | 1–100 caracteres | Bairro, sem abreviações. **e.g.: Santa Felicidade**
city | string | 1–100 caracteres | Nome completo da cidade, sem abreviações
uf | enum | sigla UF (2 letras) | A unidade federativa brasileira. Aceita as 27 UFs mais `EX` (exterior), em maiúsculas ou minúsculas. **e.g.: SP, GO, MG, EX**
complement | string | 1–500 caracteres | Quaisquer complementos para localizar o imóvel. **e.g.: Apartamento 101, Conjunto 12**
postal_code | string | Formato `XXXXX-XXX` | CEP brasileiro com hífen, exatamente 9 caracteres. Exemplo: `01310-100` *(obrigatório)*
country | string | 3 letras maiúsculas | Código ISO 3166-1 alfa-3 do país do endereço. Exemplo: `BRA`
ocr_key | guid | UUID (`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`) | Id retornado pela API ou SDK de OCR da QI Tech após o envio da imagem do comprovante de residência.

No caso dos endereços cujo país não seja Brasil (`BRA`), o `postal_code` e a unidade federativa poderão ser preenchidos livremente.

## Objeto *phone*

Request Body

```json
{
  "international_dial_code": "1",
  "area_code": "11",
  "number": "999999999",
  "type": "mobile"
}
```

Um objeto *phone* representa um número telefônico, dentro ou fora do Brasil e sua classificação. Para isso, os campos são:

nome | tipo | restrições | descrição
---- | :----: | :----: | ---------
international_dial_code | string | 1–7 caracteres, somente dígitos | Código de discagem internacional, sem zero ou `+`. Exemplo: `55` para Brasil *(obrigatório)*
area_code | string | 1–10 caracteres, somente dígitos | Código de área, sem zero. Exemplo: `11` *(obrigatório)*
number | string | 1–20 caracteres | Número do telefone, sem o hífen *(obrigatório)*
type | enum | `residential`, `commercial` ou `mobile` | Tipo de número telefônico.

## Objeto *source*

Request Body

```json
  {
    "channel": "app",
    "platform": "android",
    "ip":"211.7.142.62",
    "session_id": "733adf2c-a994-4113-aa59-beb646091fea"
  }
```

Um objeto *source* representa o conjunto de informações da plataforma utilizada pelo cliente para seu cadastramento. Para isso, os campos são:

nome | tipo | descrição
---- | :----: | ---------
channel | string | Canal de venda/cadastro do cliente
platform | string | Plataforma utilizada pelo cliente para realizar seu cadastro
ip | string | IP coletado do device que o cliente foi cadastrado
session_id | string | Identificador único da sessão, utilizado para fazer o cruzamento do device scan com o cadastro em questão

## Objeto *face*

Request Body

```json
  {
    "type":"zaig_face_sdk",
    "registration_key":"46f38cf4-07b2-4de6-93e9-64b51a68378a"
  }
```

Um objeto *face* representa uma validação de reconhecimento facial feita através das APIs ou SDKs da QI Tech por você para verificar a autenticidade do cliente prévio ao envio do cadastro. Para isso, os campos são:

nome | tipo | descrição
---- | :----: | ---------
registration_key | guid | Identificador que a API ou SDK da QI Tech retornou para identificar aquele registro.

## Objeto *partner*

Request Body

```json
  {
    "name": "John Partner",
    "document_number": "111.111.111-11",
    "birthdate": "1992-09-15",
    "gender": "male",
    "nationality": "BRA",
    "mother_name": "Maria Partner's Mother",
    "occupation": "Teacher",
    "emails":[
      {
        "email": "johnsample@test.com"
      }
    ],
    "documents": {
      "rg": {
        "number": "4.366.477-8",
        "issuer": "II",
        "issuer_state": "PR",
        "issuance_date":"2002-01-12",
        "ocr_front_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76",
        "ocr_back_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76"
      },
      "cnh": {
        "register_number": "05163811694",
        "issuer_state": "PR",
        "first_issuance_date":"2011-03-21",
        "issuance_date":"2016-06-29",
        "expiration_date":"2021-06-25",
        "category": "AB",
        "ocr_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76"
      }
    },
    "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": "1",
        "area_code": "11",
        "number": "999999999",
        "type": "mobile"
      }
    ],
    "source": {
      "channel": "app",
      "platform": "android",
      "ip":"255.321.321.1",
      "session_id": "54b8e3cf-15de-41e5-9305-0ecf059d6e2a"
    },
    "face":
    {
      "type":"zaig_sdk",
      "registration_key":"46f38cf4-07b2-4de6-93e9-64b51a68378a"
    }
  }
```

Um objeto *partner* representa os dados de um sócio da empresa que está sendo cadastrada, bem como informações referentes às validações que o sócio foi submetido durante seu processo de cadastro. Para isso, os campos são:

nome | tipo | descrição
:----: | :----: | ---------
name | string | Nome completo do sócio sendo cadastrado
document_number | string | CPF do sócio sendo cadastrado, com pontos e hífens, de acordo com a padronização *(obrigatório)*
birthdate | date | Data de nascimento do sócio de acordo com a padronização
gender | enum | Gênero do sócio: 'male' ou 'female'
nationality | string | A nacionalidade do sócio, em ISO 3166-1 alfa-3
mother_name | string | Nome completo da mãe do sócio
occupation | string | Profissão do sócio sendo cadastrado
emails | Email | Lista de objetos do tipo Email que descreve o endereço de e-mail do sócio
documents | Document | Objeto do tipo Document de quaisquer documentos enviados no momento do cadastro do sócio
address | Address | Objeto do tipo Address que descreve o endereço da moradia do sócio
phones | Lista de Phone | Lista de objetos do tipo phone que possui a lista de telefones do sócio
source | Source | Objeto do tipo Source que descreve as características da aplicação utilizada para envio do cadastro
face | Face | Objeto do tipo Face que descreve as informações da validação facial 

## Objeto *legal_representative*

Request Body

```json
  {
    "name": "Frederic Attorney",
    "document_number": "111.111.111-11",
    "birthdate": "1987-06-12",
    "gender": "male",
    "nationality": "BRA",
    "mother_name": "Jackie Attorney Mother",
    "occupation": "Accountant",
    "emails":[
      {
        "email": "frederic@attorney.com"
      }
    ],
    "documents": {
      "letter_of_attorney": {
        "ocr_key": "6972894d-d2ef-4b5f-b54f-10f178bf3e5d"
      },
      "cnh": {
        "register_number": "05163811694",
        "issuer_state": "PR",
        "first_issuance_date":"2011-03-21",
        "issuance_date":"2016-06-29",
        "expiration_date":"2021-06-25",
        "category": "AB",
        "ocr_key":"a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76"
      }
    },
    "address": {
      "street": "Avenida de Exemplo",
      "number": "99",
      "neighborhood": "Vila do Exemplo",
      "city": "Jundiaí",
      "uf": "SP",
      "complement": "Ap 82",
      "postal_code": "00000-000",
      "country": "BRA",
      "ocr_key": "265b1b74-4b93-41dc-ac78-e1c37467225d"
    },
    "phones": [
      {
        "international_dial_code": "55",
        "area_code": "11",
        "number": "999998877",
        "type": "mobile"
      }
    ],
    "source": {
      "channel": "app",
      "platform": "ios",
      "ip":"175.92.122.2",
      "session_id": "93c68588-7a41-472f-95b3-835ea6ee1ede"
    },
    "face":
    {
      "type":"zaig_sdk",
      "registration_key":"d2677a8c-d575-44e1-a54d-ec00f9310f34"
    }
  }
```

Um objeto *legal_representative* representa os dados de um representante legal da empresa que está sendo cadastrada, bem como informações referentes às validações que o representante legal foi submetido durante seu processo de cadastro. Para isso, os campos são:

nome | tipo | descrição
:----: | :----: | ---------
name | string | Nome completo do representante legal sendo cadastrado
document_number | string | CPF do representante legal sendo cadastrado, com pontos e hífens, de acordo com a padronização
birthdate | date | Data de nascimento do representante legal de acordo com a padronização
gender | enum | Gênero do representante legal: 'male' ou 'female'
nationality | string | A nacionalidade do representante legal, em ISO 3166-1 alfa-3
mother_name | string | Nome completo da mãe do representante legal
occupation | string | Profissão do representante legal sendo cadastrado
emails | Email | Lista de objetos do tipo Email que descreve o endereço de e-mail do representante legal
documents | Document | Objeto do tipo Document de quaisquer documentos enviados no momento do cadastro do representante legal
address | Address | Objeto do tipo Address que descreve o endereço da moradia do representante legal
phones | Lista de Phone | Lista de objetos do tipo phone que possui a lista de telefones do representante legal
source | Source | Objeto do tipo Source que descreve as características da aplicação utilizada para envio do cadastro
face | Face | Objeto do tipo Face que descreve as informações da validação facial 
## Objeto *final_beneficiary*

Request Body

```json
  {
    "id": "benef-001",
    "name": "Maria Sample",
    "document_number": "222.222.222-22",
    "declared_income": 1200000,
    "address": {
      "street": "Rua do Teste",
      "number": "111",
      "city": "São Paulo",
      "uf": "SP",
      "postal_code": "04570-140",
      "country": "BRA"
    }
  }
```

Um objeto *final_beneficiary* representa um beneficiário final da empresa que está sendo cadastrada. Todos os campos são opcionais. Para isso, os campos são:

nome | tipo | descrição
:----: | :----: | ---------
id | string | Identificador do beneficiário final no seu sistema
name | string | Nome completo do beneficiário final
document_number | string | CPF do beneficiário final, com pontos e hífen, de acordo com a padronização
declared_income | inteiro | Renda declarada do beneficiário final, em centavos
address | Address | Objeto do tipo Address que descreve o endereço do beneficiário final

---

# Recuperar um Cadastro

URL: /documentation/caas/onboarding/query_registration

## Buscar Cadastro específico

A fim de recuperar um Cadastro específico, basta realizar uma requisição GET. O resultado retornado é o json mais atualizado do Cadastro em questão. Caso este identificador não esteja relacionado a nenhum objeto, o HTTP Status 404 é retornado.

* **Natural Person:**

`GET https://api.caas.qitech.app/onboarding/natural_person/12345678`

* **Legal Person:**

`GET https://api.caas.qitech.app/onboarding/legal_person/12345678`

```shell
curl "https://api.caas.qitech.app/onboarding/natural_person/12345678"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> O comando acima retorna o JSON que representa um objeto de Natural Person.

```shell
curl "https://api.caas.qitech.app/onboarding/legal_person/12345678"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> O comando acima retorna o JSON que representa um objeto de Legal Person.

## Buscar PDF

A fim de recuperar um PDF de um cadastro, basta realizar uma requisição GET. O resultado retornado é o arquivo PDF resultante da análise. Caso seja desejado, basta adicionar uma query string denominada base64 com o valor true para que o arquivo PDF seja retornado em base64.

:::info **Atenção**

A geração de PDF pela plataforma é assíncrona e toma alguns segundos, caso o GET seja realizado antes da geração efetiva do PDF, um erro 404 será retornado com uma descrição que aponta esta situação. Basta retentar após alguns segundos e o PDF será retornado.
:::

* **Natural Person:**

`GET https://api.caas.qitech.app/onboarding/natural_person/12345678/pdf`

`GET https://api.caas.qitech.app/onboarding/natural_person/12345678/pdf?base64=true`

* **Legal Person:**

`GET https://api.caas.qitech.app/onboarding/legal_person/12345678/pdf`

`GET https://api.caas.qitech.app/onboarding/legal_person/12345678/pdf?base64=true`

```shell
curl "https://api.caas.qitech.app/onboarding/natural_person/12345678/pdf"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> O comando acima retorna o arquivo PDF gerado pela consulta.

```shell
curl "https://api.caas.qitech.app/onboarding/legal_person/12345678/pdf"
  -H "Authorization: EXAMPLE-OF-API-KEY"
```

> O comando acima retorna o arquivo PDF gerado pela consulta.

---

# Integrando os dados do SDK (face, documentos e device)

URL: /documentation/caas/onboarding/sdk_integration

Integrando os dados do SDK

Os SDKs da QI Tech (biometria facial, OCR de documentos e Device Scan) não enviam dados direto para a análise cadastral. Cada um devolve uma **chave** para o seu backend, e é você que anexa essas chaves ao payload de onboarding.

Esta página trata de onde cada chave entra — que é diferente entre Pessoa Física e Pessoa Jurídica.

| Bloco | O que carrega | Origem da chave |
| --- | --- | --- |
| `face` | Biometria facial | SDK de biometria |
| `documents` | OCR de documentos | SDK/API de OCR |
| `source` | Dados de dispositivo e sessão | SDK de Device Scan |

:::danger A diferença que mais causa retrabalho
Em **Pessoa Física**, os três blocos ficam na **raiz** do payload.

Em **Pessoa Jurídica**, `face` e `documents` de identidade ficam **dentro de `legal_representatives[]`** — mas o `source` continua na **raiz**. Detalhes em [Pessoa Jurídica](#pessoa-juridica-legal-person).
:::

---

## Onde cada bloco entra

| Bloco | Pessoa Física | Pessoa Jurídica |
| --- | --- | --- |
| `source` (`session_id`) | Raiz | **Raiz** — obrigatório para aparecer na dashboard |
| `face` | Raiz | Dentro de `legal_representatives[]` |
| `documents` (RG, CNH, passaporte) | Raiz | Dentro de `legal_representatives[]` |
| `documents` (`ie`, `company_statute`, `proof_of_address`) | — | Raiz |

---

## `source` — Device Scan e `session_id`

O `session_id` é a chave devolvida pelo SDK de Device Scan. É ele que conecta a análise cadastral aos dados de dispositivo, geolocalização e comportamento coletados no app ou no site.

session_id
string
opcional — mas veja o aviso
Identificador da sessão gerado pelo SDK de Device Scan. 1 a 500 caracteres.

channel
string
opcional
Canal de origem do cadastro. Ex.: app , web , backoffice . 1 a 100 caracteres.

platform
string
opcional
Plataforma. Ex.: android , ios , web . 1 a 100 caracteres.

ip
string
opcional
IP de origem. Aceita IPv4 e IPv6 . Um valor mal formatado retorna HTTP 400.

os_version
string
opcional
Versão do sistema operacional. 1 a 100 caracteres.

gps_data
object
opcional
Coordenadas da captura.

**Campos de `gps_data`:**

lat
number
opcional
Latitude, entre -90 e 90 .

lon
number
opcional
Longitude, entre -180 e 180 .

```json title="source — sempre na raiz, PF e PJ"
{
  "source": {
    "channel": "app",
    "platform": "android",
    "ip": "255.201.26.1",
    "session_id": "54b8e3cf-15de-41e5-9305-0ecf059d6e2a",
    "os_version": "14",
    "gps_data": {
      "lat": -23.5613,
      "lon": -46.6565
    }
  }
}
```

:::danger Pessoa Jurídica: `session_id` precisa estar na raiz
Em **Legal Person**, o `source.session_id` deve estar no **objeto `source` da raiz** do payload — não dentro de `legal_representatives[]`.

**Se esse campo não estiver preenchido na raiz, os dados de device não aparecem na dashboard de análise cadastral de PJ.** O schema aceita `source` dentro de `legal_representatives[]`, mas não é de lá que a dashboard de PJ lê a sessão — colocar apenas ali faz o dado ser silenciosamente ignorado na análise.
:::

---

## `face` — biometria facial

type
enum
opcional
Como a biometria foi capturada. Define qual dos campos abaixo você deve preencher.

registration_key
string
opcional
Chave devolvida pelo SDK de biometria. Use com type: "zaig_sdk" . Formato UUID.

image
string
opcional
Imagem em Base64. Use com type: "base_64" quando não houver SDK envolvido.

### Valores de `type`

| Valor | Campo a preencher |
| --- | --- |
| `zaig_sdk` | `registration_key` |
| `base_64` | `image` |

```json title="face via SDK"
{
  "face": {
    "type": "zaig_sdk",
    "registration_key": "46f38cf4-07b2-4de6-93e9-64b51a68378a"
  }
}
```

```json title="face via Base64"
{
  "face": {
    "type": "base_64",
    "image": "iVBORw0KGgoAAAANSUhEUg..."
  }
}
```

---

## `documents` — OCR

As chaves de OCR (`ocr_key`, `ocr_front_key`, `ocr_back_key`) vêm do SDK/API de OCR e entram dentro do documento correspondente.

### Documentos aceitos em Pessoa Física

Na raiz do payload de Natural Person, `documents` aceita:

| Campo | O que é | Chaves aceitas |
| --- | --- | --- |
| `rg` | Registro Geral | `ocr_front_key`, `ocr_back_key`, `ocr_key` |
| `cnh` | Carteira Nacional de Habilitação | `ocr_key`, `ocr_front_key`, `ocr_back_key` |
| `passport` | Passaporte | `ocr_key` *(obrigatório)* |
| `ctps` | Carteira de Trabalho | `ocr_front_key` e `ocr_back_key` *(ambos obrigatórios)* |
| `cin_digital` | Carteira de Identidade Nacional digital | `ocr_key` |
| `national_registry_of_foreigners` | RNE — Registro Nacional de Estrangeiros | `ocr_key`, `ocr_front_key`, `ocr_back_key` |
| `national_migration_registry` | RNM — Registro Nacional Migratório | `ocr_key`, `ocr_front_key`, `ocr_back_key` |
| `class_entity_registry` | Carteira de entidade de classe (OAB, CRM…) | `ocr_key` *(obrigatório)* |
| `military_registry` | Documento militar | `ocr_key` *(obrigatório)* |
| `letter_of_emancipation` | Carta de emancipação | `ocr_key` *(obrigatório)* |
| `company_statute` | Contrato social / estatuto | `ocr_key`, `document_analysis_id` |
| `proof_of_address` | Comprovante de endereço | `document_analysis_id` |
| `others` | Outros documentos | `ocr_front_key` e `ocr_back_key` *(ambos obrigatórios)* |

### Documentos aceitos em Pessoa Jurídica

Na **raiz** do payload de Legal Person, `documents` aceita **apenas** documentos da empresa:

| Campo | O que é | Chaves aceitas |
| --- | --- | --- |
| `ie` | Inscrição estadual | `ocr_key` — exige o campo `number` |
| `company_statute` | Contrato social / estatuto | `ocr_key`, `document_analysis_id` |
| `proof_of_address` | Comprovante de endereço | `document_analysis_id` |

:::danger RG e CNH não existem na raiz de Legal Person
Documentos de identidade (`rg`, `cnh`, `passport`…) **não são aceitos** na raiz do payload de PJ — o schema usa `additionalProperties: false` e a requisição retorna **HTTP 400**.

Eles pertencem ao representante legal, dentro de `legal_representatives[]`.
:::

### Chaves de OCR por documento

As chaves aceitas por documento estão nas tabelas acima. Vale destacar:

- **Frente e verso:** em documentos com dois lados (`rg`, `ctps`, `others`), o padrão é enviar `ocr_front_key` e `ocr_back_key`. Em `ctps` e `others` os dois são **obrigatórios**.
- **Chave única:** quando o OCR devolve uma única chave para o documento inteiro, use `ocr_key`.
- **`document_analysis_id`:** usado em `company_statute` e `proof_of_address`, que passam pela [Análise de Documentos](/documentation/caas/document_analysis/introduction) e não por OCR de identidade.

Em `rg` e `cnh`, o campo `issuer_state` aceita as siglas de UF em maiúsculas ou minúsculas.

```json title="documents com chaves de OCR (PF)"
{
  "documents": {
    "rg": {
      "number": "4.366.477-8",
      "issuer": "SSP",
      "issuer_state": "PR",
      "issuance_date": "2002-01-12",
      "ocr_front_key": "a5cf9c8f-2f66-4490-a7db-8a5bc70c1b76",
      "ocr_back_key": "b6df0d9e-3f77-45a1-b8ec-9b6cd81d2c87"
    },
    "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",
      "ocr_key": "c7ef1eaf-4088-46b2-c9fd-ac7de92e3d98"
    }
  }
}
```

---

## Pessoa Física (Natural Person)

Os três blocos ficam na raiz:

```json title="POST /onboarding/natural_person"
{
  "id": "12345678",
  "registration_date": "2026-08-07T11:37:15-03:00",
  "document_number": "111.111.111-11",
  "name": "John Sample",

  "source": {
    "channel": "app",
    "platform": "android",
    "ip": "255.201.26.1",
    "session_id": "54b8e3cf-15de-41e5-9305-0ecf059d6e2a"
  },

  "face": {
    "type": "zaig_sdk",
    "registration_key": "46f38cf4-07b2-4de6-93e9-64b51a68378a"
  },

  "documents": {
    "cnh": {
      "register_number": "05163811694",
      "issuer_state": "PR",
      "ocr_key": "c7ef1eaf-4088-46b2-c9fd-ac7de92e3d98"
    }
  }
}
```

---

## Pessoa Jurídica (Legal Person)

`source` na raiz; `face` e documentos de identidade dentro de `legal_representatives[]`:

```json title="POST /onboarding/legal_person"
{
  "id": "87654321",
  "registration_date": "2026-08-07T11:37:15-03:00",
  "document_number": "11.111.111/1111-11",
  "legal_name": "Empresa Exemplo LTDA",

  "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",

      "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"
        }
      }
    }
  ]
}
```

:::tip Por que a biometria fica no representante
A biometria e o documento de identidade pertencem a uma **pessoa**, não à empresa. Em PJ, quem passa pela validação biométrica é o representante legal — por isso `face` e `documents` de identidade vivem dentro de `legal_representatives[]`.

Já os dados de device pertencem à **sessão** em que o cadastro foi feito, que é única para toda a requisição — por isso `source` fica na raiz.
:::

---

## Erros comuns

| Sintoma | Causa | Correção |
| --- | --- | --- |
| Dados de device não aparecem na dashboard de PJ | `session_id` ausente na raiz, ou enviado apenas dentro de `legal_representatives[]` | Preencha `source.session_id` na **raiz** do payload |
| HTTP 400 ao enviar `rg`/`cnh` em PJ | Documento de identidade na raiz do Legal Person | Mova para `legal_representatives[].documents` |
| HTTP 400 no `passport` | Objeto enviado sem `ocr_key` | `ocr_key` é obrigatório em `passport` |
| HTTP 400 em `source.ip` | IP mal formatado | Envie IPv4 ou IPv6 válido |
| HTTP 400 sem campo aparente | Campo fora do schema (`additionalProperties: false`) | Confira a `description` da resposta |

---

## Checklist

- [ ] `source.session_id` na **raiz**, tanto em PF quanto em PJ.
- [ ] Em PJ, confirmado que os dados de device aparecem na dashboard de análise cadastral.
- [ ] Em PJ, `face` e documentos de identidade dentro de `legal_representatives[]`.
- [ ] Em PJ, apenas `ie`, `company_statute` e `proof_of_address` na raiz de `documents`.
- [ ] `passport`, quando enviado, com `ocr_key`.

---

# Padrões

URL: /documentation/caas/onboarding/standards

Para facilitar a integração e garantir a integridade da informação, foram definidos alguns padrões que são seguidos em toda a API.

## Valores Monetários
> Exemplos:

```
10000
12345
98741
1223
1
0
```

As APIs assumem que todos os valores monetários enviados são em Reais Brasileiros. Os valores devem ser enviados como inteiro em centavos.

## Data e Hora com Fuso Horário
> Alguns exemplos:

```
2019-10-15T22:35:12.232-03:00
2018-05-01T13:32:11.297+00:00
2019-05-01T00:00:00.000+00:00
```

É representada conforme a ISO 8601. Neste caso, o fuso-horário é colocado logo após o horário e deve representar o fuso do local onde aquele dado será valido.

A máscara utilizada para validação é a seguinte:

`YYYY-MM-ddThh:mm:ss.sss±hh:mm`

## Data e Hora sem Fuso Horario
> Alguns exemplos:

```
2019-10-15T22:35:12
2018-05-01T13:32:11
2019-05-01T00:00:00
```

É representada conforme a ISO 8601. Dados que independem de fuso-horário deverão ser enviados sem ele, sempre em UTC, com a letra Z indicando que este dado está em UTC. O seguinte formato, portanto, será validado:

`YYYY-MM-ddThh:mm:ss.sssZ`

## Data
> Alguns exemplos

``` 
2019-10-15
2019-01-01
2017-03-20
```

No caso de campos que recebem somente data, uma data de nascimento, por exemplo, somente a data, sem nenhum horário deve ser enviada com o seguinte formato:

`YYYY-MM-dd`
 

## Documentos
Uma vez que os números de documento são bastante variados e muitos deles possuem caracteres que não se enquadram como numéricos, definem-se todos os números de documento como string. Outro bom motivo para definí-los como string é evitar que os zeros à esquerda desapareçam. Documentos previstos nesta página possuem uma máscara bem definida e estarão sujeitos a validação. O restante dos documentos, como RG, dada sua falta de padronização, não serão validados.

## CPF

> Exemplos de CPFs válidos contra a máscara definida:

```
123.456.789-12
321.987.543-23
111.283.333-00
```

> Exemplos de CPFs inválidos contra a máscara definida:

```
8.577.477-8
08.104.627/0001-23
123.456.789-1
23.456.789-01
```

O CPF é sempre definido como uma string e será validado contra a máscara:

`###.###.###-##`

## CNPJ

> Exemplos de CNPJs válidos contra a máscara definida:

```
08.104.627/0001-02
01.079.210/0114-67
32.402.502/0001-35
```

> Exemplos de CNPJs inválidos contra a máscara definida:

```
8.577.477-8
123.456.789-12
321.987.543-23
32.402.502/0001-3
032.402.502/0001-3
```

O CNPJ é sempre definido como uma string e será validado contra a máscara:

`##.###.###/####-##`

## IP

> Exemplos de IPs válidos contra a máscara definida:

```
201.81.161.86
201.081.161.86
201.81.161.086
201.81.0.1
```

> Exemplos de IPs inválidos:

```
201.81..86
358.81.161.86
201.81.161
```

IPs deverão ser enviados sempre em IPv4, zeros à esquerda poderão ou não ser enviados, respeitando a seguinte máscara:

`###.###.###.###`

---

# Dinâmica dos status

URL: /documentation/caas/onboarding/status_dynamics

Dinâmica dos status

A API de Análise cadastral trabalha com **três** enumeradores de status independentes. Entender a diferença entre eles é o passo que mais evita erro de integração:

| Enumerador | Quem define o valor | Quem devolve | O que representa |
| --- | --- | --- | --- |
| `analysis_status` | **Você**, na sua política | **QI Tech** | O resultado da execução da sua árvore de decisão. |
| `risk_level` | **Você**, na sua política | **QI Tech** | O nível de risco atribuído pela sua árvore de decisão. |
| `client_status` | **Você** | — | A situação do cliente na sua plataforma. |

:::info `analysis_status` e `risk_level` saem da sua própria política
Esses dois campos **não** são um veredito nosso sobre o cadastro. Eles são definidos por você, no motor de regras, através das **caixinhas de decisão** e de **nível de risco** que você posiciona ao longo da sua árvore.

A cada requisição, a QI Tech executa essa árvore contra os dados analisados e devolve o resultado que a **sua** política determinou. Se você quer que um cenário passe a cair em `in_manual_analysis` em vez de `automatically_reproved`, ou que um perfil receba `risk_level: high` em vez de `medium`, a mudança é no motor de regras — não há nada a alterar na integração.
:::

:::tip A regra prática
`analysis_status` é o **resultado da sua política**, executada por nós. `client_status` é a **sua decisão de negócio**, que você registra via [PUT](/documentation/caas/onboarding/update_registration) conforme a jornada do cliente evolui.
:::

### Como a decisão é produzida

1. Você desenha a árvore de decisão no motor de regras, posicionando as caixinhas de **decisão** (`analysis_status`) e de **nível de risco** (`risk_level`) conforme a sua política.
2. Você envia o cadastro para a API.
3. A QI Tech executa a árvore contra os dados do cadastro e os enriquecimentos disponíveis.
4. A resposta traz o `analysis_status` e o `risk_level` que a sua árvore determinou para aquele caso.

Por isso, dois clientes que enviam exatamente o mesmo cadastro podem receber respostas diferentes: cada um tem a sua própria política configurada.

---

## `analysis_status`

Resultado da execução da sua árvore de decisão. Os status abaixo se dividem em três grupos pelo que você deve fazer com cada um.

### Decisões finais

| Status | Significado | Ação |
| --- | --- | --- |
| `automatically_approved` | A sua árvore de decisão terminou em uma caixinha de aprovação automática. | Pode aprovar o cadastro. |
| `automatically_reproved` | A sua árvore de decisão terminou em uma caixinha de reprovação automática. | Recuse o cadastro. |
| `manually_approved` | Aprovado por um analista. | Pode aprovar o cadastro. |
| `manually_reproved` | Reprovado por um analista. | Recuse o cadastro. |
| `approved_by_time` | Aprovado automaticamente após expirar o prazo de análise. | Pode aprovar o cadastro. |
| `reproved_by_time` | Reprovado automaticamente após expirar o prazo de análise. | Recuse o cadastro. |

### Aguardando — o resultado chega por webhook

| Status | Significado | Ação |
| --- | --- | --- |
| `in_queue` | Análise assíncrona em fila. | Aguarde o [Webhook](/documentation/caas/onboarding/webhook). |
| `pending` | As consultas estão demorando mais que o esperado. | Aguarde o Webhook. |
| `in_manual_analysis` | Derivado para análise manual por um analista. | Aguarde o Webhook. |
| `waiting_for_data` | Aguardando dados complementares para processar. | Aguarde o Webhook. |
| `on_hold` | Análise pausada, aguardando retorno do cliente. | Aguarde o Webhook. |

:::danger Não trate "aguardando" como recusa
`in_queue`, `pending`, `in_manual_analysis`, `waiting_for_data` e `on_hold` **não são negativas**. Tratá-los como reprovação é o erro de integração mais comum nesta API — recusa cadastros legítimos que seriam aprovados minutos depois.
:::

### Contestação e casos especiais

| Status | Significado | Ação |
| --- | --- | --- |
| `automatically_challenged` | A sua árvore terminou em uma caixinha de contestação. | O cadastro precisa passar pelo fluxo de contestação. |
| `manually_challenged` | Contestado por um analista. | Idem. |
| `manually_cancelled` | Análise cancelada. | Nenhuma decisão será emitida. |
| `failed` | A análise falhou durante o processamento. | Reenvie com um novo `id` ou acione o suporte. |
| `not_analysed` | Enviado com `analyze=false`. | Nenhuma recomendação será emitida; siga sua própria decisão. |

---

## `client_status`

Situação cadastral do cliente na **sua** plataforma. Você é responsável por manter esse status atualizado via [PUT](/documentation/caas/onboarding/update_registration) — ele alimenta os modelos e melhora análises futuras.

| Status | Significado |
| --- | --- |
| `registered` | Registrado, sem decisão de aprovação ainda. |
| `approved` | Aprovado na sua plataforma. |
| `reproved` | Reprovado na sua plataforma. |
| `fraud_blocked` | Bloqueado por suspeita ou confirmação de fraude. |
| `default_blocked` | Bloqueado por inadimplência. |
| `cancelled` | O cliente cancelou o uso do serviço. |

:::info Grafia do enumerador
O valor correto é `cancelled`, com dois L. Versões antigas desta documentação grafavam `canceled` — esse valor é rejeitado com HTTP 400.
:::

### Quais valores podem ser enviados

O método usado determina os valores aceitos:

| Tipo de cadastro | Valores aceitos no `PUT` |
| --- | --- |
| Natural Person | `approved`, `reproved`, `fraud_blocked`, `default_blocked`, `cancelled` |
| Legal Person | `fraud_blocked`, `default_blocked`, `cancelled` |

:::caution Legal Person aceita menos valores
Em **Legal Person**, o `PUT` **não** aceita `approved` nem `reproved` — apenas os três valores de bloqueio e cancelamento. Enviar `approved` em um cadastro PJ retorna **HTTP 400**.
:::

Detalhes em [Atualizar um cadastro](/documentation/caas/onboarding/update_registration).

---

## `risk_level`

Nível de risco atribuído ao cadastro pela caixinha de nível de risco que a sua árvore percorreu. Presente na resposta do `GET` e nos eventos de análise.

| Valor | Significado |
| --- | --- |
| `low` | Risco baixo. |
| `medium` | Risco médio. |
| `high` | Risco alto. |
| `critical` | Risco crítico. |
| `undefined` | Nenhuma avaliação de risco foi realizada. |

---

## Fluxo típico

1. Você envia o cadastro — `POST /onboarding/natural_person`.
2. A resposta traz um `analysis_status`.
   - Se for uma **decisão final**, siga o que a sua política determinou.
   - Se for **aguardando**, espere o webhook.
3. Ao decidir na sua plataforma, envie o `client_status` via `PUT`.

---

# Atualizar um cadastro

URL: /documentation/caas/onboarding/update_registration

Atualizar um cadastro

Use o método `PUT` para atualizar o **status** de um cadastro — tanto o `client_status` (situação na sua plataforma) quanto o `analysis_status` (decisão manual de análise).

:::tip Retroalimentação importa
Informar o desfecho real via `PUT` é o que mantém a qualidade das recomendações. Sem esse retorno, os modelos não aprendem com os casos da sua carteira.
:::

O endpoint aceita os dois tipos de cadastro:

```text
/onboarding/natural_person/{external_id}
/onboarding/legal_person/{external_id}
```

O `{external_id}` é o `id` que você enviou no `POST`.

---

## PUT — atualizar status

ENDPOINT /onboarding/natural_person/ EXTERNAL_ID
MÉTODO PUT

O corpo aceita **duas formas mutuamente exclusivas**: uma para `client_status`, outra para `analysis_status`.

**client_status**

Atualiza a situação do cliente na sua plataforma.

client_status
enum
obrigatório
Em Natural Person aceita approved , reproved , fraud_blocked , default_blocked ou cancelled . Em Legal Person , apenas fraud_blocked , default_blocked ou cancelled .

event_date
datetime
obrigatório
Data e hora do evento, com fuso horário. Offset terminado em :00 / :30 ou sufixo Z .

```json title="Bloqueio por fraude"
{
  "client_status": "fraud_blocked",
  "event_date": "2026-08-07T13:34:12-03:00"
}
```

```json title="Bloqueio por inadimplência"
{
  "client_status": "default_blocked",
  "event_date": "2026-08-07T13:34:12-03:00"
}
```

```json title="Cancelamento pelo cliente"
{
  "client_status": "cancelled",
  "event_date": "2026-08-07T13:34:12-03:00"
}
```

**analysis_status**

Registra uma decisão manual de análise.

analysis_status
enum
obrigatório
Aceita manually_approved , manually_reproved , manually_challenged , manually_cancelled ou on_hold .

risk_level
enum
opcional
low , medium , high ou critical .

observation
string
opcional
Justificativa da decisão. Até 3.000 caracteres.

user_name
string
opcional
Nome do analista responsável. Até 50 caracteres.

user_email
string
opcional
E-mail do analista responsável.

```json title="Aprovação manual"
{
  "analysis_status": "manually_approved",
  "risk_level": "low",
  "observation": "Documentação conferida e validada.",
  "user_name": "Ana Analista",
  "user_email": "ana@exemplo.com.br"
}
```

### Exemplos de requisição

**Python**

```python
import requests

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

response = requests.put(
    f"{BASE_URL}/onboarding/natural_person/{EXTERNAL_ID}",
    json={
        "client_status": "approved",
        "event_date": "2026-08-07T13:34:12-03:00",
    },
    headers={"Authorization": API_KEY},
    timeout=30,
)

response.raise_for_status()
```

**PHP**

```php
<?php

$baseUrl    = 'https://api.sandbox.caas.qitech.app';
$apiKey     = 'YOUR_API_KEY';
$externalId = '12345678';

$payload = [
    'client_status' => 'approved',
    'event_date'    => '2026-08-07T13:34:12-03:00',
];

$ch = curl_init("{$baseUrl}/onboarding/natural_person/{$externalId}");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    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("Falha ao atualizar: HTTP {$status} — {$body}");
}
```

**Node.js**

```javascript
const BASE_URL = "https://api.sandbox.caas.qitech.app";
const API_KEY = "YOUR_API_KEY";
const EXTERNAL_ID = "12345678";

async function updateStatus() {
  const response = await fetch(
    `${BASE_URL}/onboarding/natural_person/${EXTERNAL_ID}`,
    {
      method: "PUT",
      headers: {
        "Content-Type": "application/json",
        Authorization: API_KEY,
      },
      body: JSON.stringify({
        client_status: "approved",
        event_date: "2026-08-07T13:34:12-03:00",
      }),
    },
  );

  if (!response.ok) {
    throw new Error(`Falha ao atualizar: HTTP ${response.status}`);
  }
}

updateStatus();
```

**Java**

```java
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 UpdateClientStatus {

    private static final String BASE_URL = "https://api.sandbox.caas.qitech.app";
    private static final String API_KEY = "YOUR_API_KEY";
    private static final String EXTERNAL_ID = "12345678";

    public static void main(String[] args) throws Exception {
        String payload = """
            {
              "client_status": "approved",
              "event_date": "2026-08-07T13:34:12-03:00"
            }
            """;

        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(BASE_URL + "/onboarding/natural_person/" + EXTERNAL_ID))
                .header("Content-Type", "application/json")
                .header("Authorization", API_KEY)
                .timeout(Duration.ofSeconds(30))
                .PUT(HttpRequest.BodyPublishers.ofString(payload))
                .build();

        HttpResponse<String> response =
                client.send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 200) {
            throw new IllegalStateException(
                    "Falha ao atualizar: HTTP " + response.statusCode());
        }
    }
}
```

**C#**

```csharp
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class UpdateClientStatus
{
    private const string BaseUrl = "https://api.sandbox.caas.qitech.app";
    private const string ApiKey = "YOUR_API_KEY";
    private const string ExternalId = "12345678";

    public static async Task Main()
    {
        var payload = new
        {
            client_status = "approved",
            event_date = "2026-08-07T13:34:12-03:00"
        };

        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.PutAsync(
            $"{BaseUrl}/onboarding/natural_person/{ExternalId}", content);

        if (!response.IsSuccessStatusCode)
        {
            throw new InvalidOperationException(
                $"Falha ao atualizar: HTTP {(int)response.StatusCode}");
        }
    }
}
```

**curl**

```bash
curl -X PUT \
  'https://api.sandbox.caas.qitech.app/onboarding/natural_person/12345678' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: YOUR_API_KEY' \
  -d '{
    "client_status": "approved",
    "event_date": "2026-08-07T13:34:12-03:00"
  }'
```

## Erros

| Status | Situação | Como resolver |
| --- | --- | --- |
| 400 | Enum fora da lista aceita. | Confira os valores aceitos para `client_status` e `analysis_status`. |
| 400 | `client_status` sem `event_date`. | Envie os dois juntos. |
| 400 | Campo não previsto no schema. | O schema usa `additionalProperties: false`. |
| 404 | Cadastro não encontrado para a sua API Key. | Verifique o `external_id` do path. |

Lista completa em [Status HTTP](/documentation/caas/onboarding/http_status).

---

# Webhook

URL: /documentation/caas/onboarding/webhook

Webhook

Atualizações no status de fraude (Para cadastros que sejam derivados para análise manual ou que sejam respondidos como Pendente), são notificados por meio de Webhook. Para tanto, é necessário, por meio da equipe do [suporte](mailto:suporte.caas@qitech.com.br), configurar um endereço do endpoint por onde vamos notificar as atualizações e também um *secret_token* que será utilizado para assinar a requisição.

O cliente pode, apesar de não recomendável, também utilizar a técnica de [polling](https://en.wikipedia.org/wiki/Polling_(computer_science)). Neste caso, basta não configurar o endpoint de webhook e utilizar os endpoints de recuperação de cadastro para proceder com o polling.

## Assinatura do Webhook

## Requisição

```bash
curl --location 'YOUR-ENDPOINT-HERE' \
--header 'Signature: CALCULATED-HASH-HMAC' \
--data '{"natural_person_id": "538509",  "analysis_status": "manually_approved", "event_date": "2024-11-13T17:52:50Z", "reason": "manually_approved"}'
```

A requisição possui o formato acima e notifica a mudança no status de fraude. É importante ressaltar que a requisição utiliza o verbo HTTP POST e o corpo da requisição é enviado como texto codificado em UTF-8.

## Retentativas

A notificação é considerada realizada quando recebe como resposta um HTTP Status 200. Caso as notificações falhem, serão feitas 5 retentativas, com os seguintes intervalos, até que um 200 seja retornado ou as tentativas terminem:

* 30 segundos
* 60 segundos
* 120 segundos
* 240 segundos
* 360 segundos