# Business Contract AI

Read articles of incorporation, board minutes and other corporate documents with AI — and get back a structured, machine-readable description of who can sign on behalf of the company, what their powers are, and how votes are combined.

Stark Infra runs OCR over each PDF, calls the AI Model to extract the company data, signing rules and eligible signers, and returns the result asynchronously through a webhook.

Each analysis is composed of one Business Identity (the legal entity) and up to two Business Attachment files (the corporate documents).

NOTE: Read Core Concepts before continuing this guide.

**RESOURCE SUMMARY**

Business IdentityRegister the legal entity that will have its corporate documents read by the AI Model.Business AttachmentUpload the PDFs (articles of incorporation, amendments, board minutes) tied to the identity.

## Setup

1. Get in touch with your account manager to enable the Business Contract AI product to your account.

2. Create a Webhook resource subscribed to business-identity events to be notified when the AI Model finishes.

3. Have the corporate PDFs ready before calling the API — articles of incorporation and the most recent amendment are typically mandatory.

## Typical flow

1. Create a Business Identity with the company's CNPJ. Save the returned id — you'll reference it as businessIdentityId in every subsequent call.

2. Upload each corporate PDF as a Business Attachment, passing the saved businessIdentityId. Each call returns an attachment in created status.

3. Once the attachments are uploaded, send the identity to processing with PATCH /business-identity/{id} and status=processing — this triggers the AI Model analysis.

4. The identity ends in success or failed. On success, the webhook payload includes the validated organization name, CNPJ, document type and the list of rules with eligible signers and required signatures.

## Use cases

KYB onboarding: read the articles of incorporation submitted by the customer and pre-fill the partner list, signing rules and beneficial owners.

Credit underwriting: before signing a Credit Note with a legal entity, check that the candidate signer has the power to bind the company.

Document review: spot inconsistencies between what a customer declared and what the corporate documents actually say.

## Business Identity Overview

A Business Identity represents the legal entity whose corporate documents will be read by the AI Model. Create it first to obtain the id that ties together every Business Attachment and triggers the analysis.

### The Business Identity Object

**Parameters**

| Name | Type | Description |
| --- | --- | --- |
| `id` | STRING | Unique id for the Business Identity. |
| `taxId` | STRING | CNPJ of the legal entity, with or without punctuation. Example: "20.018.183/0001-80". |
| `name` | STRING | Official corporate name (razão social) fetched from the bureau at creation time. |
| `taxIdStatus` | STRING | Current status of the CNPJ at the bureau, normalized from the Receita Federal value to a stable, language-agnostic option. Mapping: active = "ATIVA", blocked = "SUSPENSA", pending = "INAPTA", canceled = "BAIXADA", voided = "NULA". |
| `insightTaxId` | STRING | CNPJ extracted from the corporate document by the AI Model. Empty string until the analysis succeeds. |
| `insightDocumentType` | STRING | Type of document detected by the AI Model (e.g., articles of incorporation, amendment, board minute). Empty string until the analysis succeeds. |
| `representatives` | LIST OF OBJECTS | List of representative objects (sócios) fetched from the bureau. Each entry carries at least name, qualification and taxId. |
| `attachments` | LIST OF STRINGS | References to the documents tied to the identity, in the format "attachment/<id>". A Business Identity holds at most two attachments. |
| `rules` | LIST OF OBJECTS | List of signature rule objects extracted by the AI Model — each entry lists a valid signature combination (clause reference, literal text, required signatures and eligible signers). Empty list until status=success. |
| `tags` | LIST OF STRINGS | Free-form tags used to label the identity for future queries. |
| `status` | STRING | Current lifecycle status of the Business Identity. Options: created, pending, processing, success, failed, canceled. |
| `created` | STRING | Creation datetime. Example: "2026-06-12T12:00:00.000000+00:00". |
| `updated` | STRING | Last update datetime. Example: "2026-06-12T12:00:00.000000+00:00". |

### Create Business Identities

`POST /v2/business-identity`

Create one or more Business Identities. Each entry must include the CNPJ of the legal entity.

The identity is created in pending status. Save the returned id — you'll use it as identityId when uploading the Business Attachments and as the path parameter when sending the identity to processing.

Validations: the CNPJ must be valid, must be active in the official bureau and must return non-empty representatives (sócios).

**Request**

```python
import starkinfra

identities = starkinfra.businessidentity.create([
    starkinfra.BusinessIdentity(
        tax_id="20.018.183/0001-80",
        tags=["onboarding-123"]
    )
])

for identity in identities:
    print(identity)
```

**Response**

```python
[
    BusinessIdentity(
        id="5740539971076096",
        tax_id="20.018.183/0001-80",
        name="STARK BANK S.A.",
        tax_id_status="active",
        insight_tax_id="",
        insight_document_type="",
        representatives=[{"name": "Daenerys Targaryen Stormborn", "qualification": "Diretor", "taxId": "012.345.678-90"}],
        attachments=[],
        rules=[],
        tags=["onboarding-123"],
        status="pending",
        created="2026-06-12T12:00:00+00:00",
        updated="2026-06-12T12:00:00+00:00"
    )
]
```

### Send Business Identity to processing

`PATCH /v2/business-identity/:id`

Patch a Business Identity to trigger the AI Model analysis. The identity must be in pending status and must already have at least one Business Attachment associated with it.

Once status=processing is set, Stark Infra runs OCR and AI extraction. The business-identity webhook fires when the identity reaches success or failed.

**Request**

```python
import starkinfra

identity = starkinfra.businessidentity.update(
    id="5740539971076096",
    status="processing"
)

print(identity)
```

**Response**

```python
BusinessIdentity(
    id="5740539971076096",
    tax_id="20.018.183/0001-80",
    name="STARK BANK S.A.",
    tax_id_status="active",
    insight_tax_id="",
    insight_document_type="",
    representatives=[{"name": "Daenerys Targaryen Stormborn", "qualification": "Diretor", "taxId": "012.345.678-90"}],
    attachments=["attachment/5104320788332544"],
    rules=[],
    tags=["onboarding-123"],
    status="processing",
    created="2026-06-12T12:00:00+00:00",
    updated="2026-06-12T12:05:00+00:00"
)
```

### Get a Business Identity

`GET /v2/business-identity/:id`

Retrieve a Business Identity by its id. Use this to inspect the current status of the analysis and, when status=success, read the structured rules extracted by the AI Model.

Each rules entry describes a valid signature combination — the clause reference in the original document, the literal text, the number of required signatures and the eligible signers. Every signer carries isSignatureRequired (whether they must sign in that specific combination) and isRepresentative (whether they appear in the company's representative board).

**Request**

```python
import starkinfra

identity = starkinfra.businessidentity.get("5740539971076096")
print(identity)
```

**Response**

```python
BusinessIdentity(
    id="5740539971076096",
    tax_id="20.018.183/0001-80",
    name="STARK BANK S.A.",
    tax_id_status="active",
    insight_tax_id="20.018.183/0001-80",
    insight_document_type="articles-of-incorporation",
    representatives=[{"name": "Daenerys Targaryen Stormborn", "qualification": "Diretor", "taxId": "012.345.678-90"}],
    attachments=["attachment/5104320788332544"],
    rules=[{"reference": "Artigo 16, item (a)", "content": "pela assinatura isolada do Diretor Presidente", "signaturesRequired": 1, "eligibles": [{"name": "Daenerys Targaryen Stormborn", "taxId": "012.345.678-90", "role": "Diretor Presidente", "isSignatureRequired": True, "isRepresentative": True}]}, {"reference": "Artigo 16, item (b)", "content": "pela assinatura de quaisquer 2 (dois) diretores em conjunto", "signaturesRequired": 2, "eligibles": [{"name": "Daenerys Targaryen Stormborn", "taxId": "012.345.678-90", "role": "Diretor Presidente", "isSignatureRequired": False, "isRepresentative": True}, {"name": "Jon Snow", "taxId": "098.765.432-10", "role": "Diretor de Riscos e Compliance", "isSignatureRequired": False, "isRepresentative": True}, {"name": "Arya Stark", "taxId": "111.222.333-44", "role": "Diretor Financeiro", "isSignatureRequired": False, "isRepresentative": True}]}, {"reference": "Artigo 16, item (c)", "content": "pela assinatura de 1 (um) diretor em conjunto com 1 (um) procurador", "signaturesRequired": 2, "eligibles": [{"name": "Procurador", "taxId": "", "role": "Procurador", "isSignatureRequired": True, "isRepresentative": False}, {"name": "Daenerys Targaryen Stormborn", "taxId": "012.345.678-90", "role": "Diretor Presidente", "isSignatureRequired": False, "isRepresentative": True}, {"name": "Jon Snow", "taxId": "098.765.432-10", "role": "Diretor de Riscos e Compliance", "isSignatureRequired": False, "isRepresentative": True}]}],
    tags=["onboarding-123"],
    status="success",
    created="2026-06-12T12:00:00+00:00",
    updated="2026-06-12T12:10:00+00:00"
)
```

### Deleting a Business Identity

`DELETE /v2/business-identity/:id`

Cancel a Business Identity before it has been sent to processing. The identity transitions to canceled and is no longer eligible to receive new attachments or be patched to processing.

Validations: the identity must exist and belong to your workspace; its current status must be created or pending — identities already in processing, success, failed or canceled cannot be canceled again.

Canceling an identity does not cancel the Business Attachments tied to it. If you also need to discard the uploaded documents, call DELETE /v2/business-attachment/:id on each one before they leave created status.

**Request**

```python
import starkinfra

identity = starkinfra.businessidentity.cancel("5740539971076096")
print(identity)
```

**Response**

```python
BusinessIdentity(
    id="5740539971076096",
    tax_id="20.018.183/0001-80",
    name="STARK BANK S.A.",
    tax_id_status="active",
    insight_tax_id="",
    insight_document_type="",
    representatives=[{"name": "Daenerys Targaryen Stormborn", "qualification": "Diretor", "taxId": "012.345.678-90"}],
    attachments=[],
    rules=[],
    tags=["onboarding-123"],
    status="canceled",
    created="2026-06-12T12:00:00+00:00",
    updated="2026-06-12T12:03:00+00:00"
)
```

## Business Attachment Overview

A Business Attachment is a single corporate document (articles of incorporation, most recent amendment, board minute) tied to a Business Identity.

Up to two attachments per identity. Each attachment is registered with status=created and must be in place before the identity can be sent to processing.

### The Business Attachment Object

**Parameters**

| Name | Type | Description |
| --- | --- | --- |
| `id` | STRING | Unique id for the Business Attachment. |
| `name` | STRING | File name. Unique among the identity's other created attachments. |
| `businessIdentityId` | STRING | Id of the Business Identity that owns this attachment. |
| `attachmentId` | STRING | Id of the underlying document on Stark Infra's Attachment microservice — used internally to fetch and validate the file. |
| `content` | STRING | Base64-encoded file payload. Returned only when the attachment is fetched with expand=content. |
| `tags` | LIST OF STRINGS | Free-form tags used to label the attachment for future queries. |
| `status` | STRING | Current lifecycle status of the Business Attachment. Options: created, approved, denied, canceled. |
| `created` | STRING | Creation datetime. Example: "2026-06-12T12:02:00.000000+00:00". |
| `updated` | STRING | Last update datetime. Example: "2026-06-12T12:02:00.000000+00:00". |

### Upload a Business Attachment

`POST /v2/business-attachment`

Send a single corporate document tied to a previously created Business Identity. The identityId must match the id returned by POST /v2/business-identity.

Validations: only PDF, JPG and PNG are accepted, ≤ 8 MB per attachment; the name must be unique among the identity's other created attachments; the identity must be in pending status and have fewer than 2 attachments.

**Request**

```python
import starkinfra

attachments = starkinfra.businessattachment.create([
    starkinfra.BusinessAttachment(
        name="contrato-social.pdf",
        content="data:application/pdf;base64,JVBERi0xLjQK...",
        identity_id="5740539971076096",
        tags=["doc-principal"]
    )
])

for attachment in attachments:
    print(attachment)
```

**Response**

```python
[
    BusinessAttachment(
        id="6710539971076096",
        name="contrato-social.pdf",
        business_identity_id="5740539971076096",
        attachment_id="5104320788332544",
        tags=["doc-principal"],
        status="created",
        created="2026-06-12T12:02:00+00:00",
        updated="2026-06-12T12:02:00+00:00"
    )
]
```

### Deleting a Business Attachment

`DELETE /v2/business-attachment/:id`

Cancel a Business Attachment that was uploaded by mistake or that you no longer want to send to the AI Model. The attachment transitions to canceled and stops counting toward the identity's two-attachment limit, so you can upload a replacement in its place.

Validations: the attachment must exist and belong to your workspace; its current status must be created — attachments already approved, denied or canceled cannot be canceled again.

Canceling an attachment does not cancel the parent Business Identity. If the identity has not yet been sent to processing and you want to discard it as well, call DELETE /v2/business-identity/:id separately.

**Request**

```python
import starkinfra

attachment = starkinfra.businessattachment.cancel("6710539971076096")
print(attachment)
```

**Response**

```python
BusinessAttachment(
    id="6710539971076096",
    name="contrato-social.pdf",
    business_identity_id="5740539971076096",
    attachment_id="5104320788332544",
    tags=["doc-principal"],
    status="canceled",
    created="2026-06-12T12:02:00+00:00",
    updated="2026-06-12T12:03:30+00:00"
)
```

---

## Other Languages

- [Python](https://docs.starkinfra.com/get-started/contract-ai-python.md)
- [Node.js](https://docs.starkinfra.com/get-started/contract-ai-node.md)
- [PHP](https://docs.starkinfra.com/get-started/contract-ai-php.md)
- [Java](https://docs.starkinfra.com/get-started/contract-ai-java.md)
- [Ruby](https://docs.starkinfra.com/get-started/contract-ai-ruby.md)
- [Elixir](https://docs.starkinfra.com/get-started/contract-ai-elixir.md)
- [.NET](https://docs.starkinfra.com/get-started/contract-ai-dotnet.md)
- [Go](https://docs.starkinfra.com/get-started/contract-ai-go.md)
- [Clojure](https://docs.starkinfra.com/get-started/contract-ai-clojure.md)
- [cURL](https://docs.starkinfra.com/get-started/contract-ai-curl.md)
