> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gu1.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Create an entity (person or company)

> Create a new person or company with custom data — in the gu1 universal entity model for KYC, KYB, and risk analysis, with examples for create use cases.

## Overview

Creates a new entity with the specified type and attributes. Entities represent the core data objects you want to analyze for risk and compliance.

## Endpoint

```
POST http://api.gu1.ai/entities
```

## Authentication

Requires a valid API key in the Authorization header:

```bash theme={null}
Authorization: Bearer YOUR_API_KEY
```

## Request Body

<ParamField body="type" type="string" required>
  The type of entity to create. Available types:

  * `person` - Individual person/customer
  * `company` - Business entity
</ParamField>

<ParamField body="externalId" type="string">
  Your unique identifier for this entity in your system. **Optional** — gu1 assigns one automatically when omitted (see table below).
</ParamField>

<ParamField body="name" type="string" required>
  Display name for the entity
</ParamField>

<ParamField body="countryCode" type="string" required>
  ISO 3166-1 alpha-2 country code (e.g., "US", "BR", "AR")
</ParamField>

<ParamField body="taxId" type="string">
  Tax identification number (validated based on country). Within an organization, an active normalized `taxId` may belong to **only one** entity (`person` or `company`). Conflicts return **`409`** with code **`DUPLICATE_TAX_ID`**.
</ParamField>

<Note>
  **When `externalId` is omitted**

  | You send                             | Stored `externalId`                                                                                                                    |
  | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
  | `taxId` (with or without formatting) | Normalized tax ID: **letters and digits only, uppercase** — no dots, dashes, or spaces. Example: `30-12345678-9` → `30123456789`       |
  | No `taxId`                           | `{name-slug}-{timestamp-ms}` derived from `name` (lowercase, non-alphanumeric → `-`, max 20 chars). Example: `acme-corp-1719345678901` |

  The **`taxId` column** is still saved in the [country display format](/en/api-reference/entities/tax-id-formats) when you provide a tax ID. Send an explicit `externalId` when you need your own CRM or user ID independent of the tax document.
</Note>

<ParamField body="email" type="string | null">
  Optional primary contact email stored on the entity row (nullable). Existing entities keep `null` until set. Send `null` on PATCH to clear.
</ParamField>

<ParamField body="phone" type="string | null">
  Optional primary contact phone stored on the entity row (nullable). Existing entities keep `null` until set. Send `null` on PATCH to clear.
</ParamField>

<ParamField body="operationalHours" type="object | null">
  Optional weekly operational hours for KYT rules (`outside_entity_operational_hours`). Root-level field (not inside `attributes`).

  * `timezone` (required when `operationalHours` is sent): must be one of the **transaction\_time\_zone** enum values. **Full list:** [Transaction Time Zone Enum](/en/api-reference/transactions/time-zone-enum).
  * `weekly`: keys `monday` … `sunday`. Each day: `{ "start": "09:00", "end": "18:00" }` or `{ "closed": true }`. Omitted days are treated as closed.
  * Used by transaction rules that compare `transactedAt` to this schedule in the entity's local timezone.
</ParamField>

<ParamField body="nationality" type="string | null">
  Optional root-level nationality: ISO 3166-1 alpha-2, or a recognized label the API maps to ISO2. If omitted, the root field may still be derived from `entityData.person.nationality` or `entityData.company.nationality` when mappable.
</ParamField>

<ParamField body="registrationDate" type="string | number | Date">
  Registration or incorporation date of the entity. Accepts:

  * ISO 8601 datetime string (e.g., "2020-06-15T00:00:00Z")
  * Unix timestamp (number)
  * JavaScript Date object
</ParamField>

<ParamField body="attributes" type="object">
  **Optional** — Custom attributes. Accepts **flat** (`{ "phone": "..." }`) or **category-nested** (`{ "contact": { "phone": "..." } }`) input. Stored **verbatim** (nested objects act as categories, returned as sent); see [Update entity](/en/api-reference/entities/update) for details.
</ParamField>

<ParamField body="riskFactors" type="object">
  **Optional** - Custom risk factors and manual risk score overrides

  Properties:

  * `reasons` (array of strings) - Reasons for the risk assessment
  * `customLabel` (object) - Custom risk label configuration:
    * `name` (string) - Label name (e.g., "High Risk", "Suspicious")
    * `color` (string) - Color code for UI display
    * `status` (string) - Status indicator
    * `minScore` (number) - Minimum score for this label
    * `maxScore` (number | null) - Maximum score (null for infinite)
    * `severity` (enum) - Severity level: 'low', 'medium', 'high', 'critical'
  * `displayRange` (object) - Score range display configuration:
    * `max` (number | null) - Maximum value (null for infinite)
    * `min` (number) - Minimum value
    * `current` (number) - Current score value
    * `isInfinite` (boolean) - Whether the range is infinite
  * `originalScore` (number) - Original calculated score before manual override
  * `normalizedScore` (number) - Normalized score value

  **Use case**: Override automatic risk scoring with manual assessments for special cases.
</ParamField>

<ParamField body="entityData" type="object">
  **Optional** - Type-specific data structure. See examples below for each entity type.

  <Note>
    **When to use entityData?**

    * **Optional for basic entity creation** - You can create an entity with just `type`, `name`, `taxId`, and `countryCode`
    * **Required for enrichment and risk analysis** - If you want to run compliance checks, you'll need to provide relevant fields
    * **Can be populated later** - You can create a minimal entity first, then update it with full data before running risk analysis

    **Minimal Example (Person):**

    ```json theme={null}
    {
      "type": "person",
      "name": "John Doe",
      "taxId": "12345678",
      "countryCode": "US"
      // No entityData needed for basic creation
    }
    ```

    **Full Example (Person with KYC data):**

    ```json theme={null}
    {
      "type": "person",
      "name": "John Doe",
      "taxId": "12345678",
      "countryCode": "US",
      "entityData": {
        "person": {
          "firstName": "John",
          "lastName": "Doe",
          "dateOfBirth": "1980-01-15",
          "email": "john@example.com",
          "phone": "+1234567890"
        }
      }
    }
    ```
  </Note>
</ParamField>

<ParamField body="isClient" type="boolean" default="false">
  Mark this entity as a client/customer for tracking purposes
</ParamField>

<ParamField body="riskMatrixId" type="string | string[]">
  One or more risk matrix UUIDs (legacy: a single UUID string). If provided, after creation the system evaluates this entity **only** against active rules tied to those matrices (unless `skipRulesExecution` is true). Same semantics as `riskMatrixIds` when you send a single id as a string.
</ParamField>

<ParamField body="riskMatrixIds" type="string[]">
  Preferred way to pass **multiple** matrices: ordered list of UUIDs belonging to your organization. When present and non-empty, it takes precedence over `riskMatrixId`.
</ParamField>

<ParamField body="skipRulesExecution" type="boolean" default="false">
  Skip automatic rules execution after entity creation
</ParamField>

<ParamField body="shareholderDepth" type="number" default="0">
  For company entities: How many levels of shareholders to auto-create (0-5).

  * `0` = None (default)
  * `1` = Direct shareholders only
  * `2` = Shareholders + their shareholders
  * `3-5` = Deeper nested levels

  Useful for automatic KYB and UBO (Ultimate Beneficial Owner) discovery.
</ParamField>

<ParamField body="relationships" type="array">
  Declarative links to entities that **already exist** in the same organization (max 10). Independent of `shareholderDepth` / enrichment.

  Each item must include **exactly one** of: `relatedEntityId` (UUID), `relatedTaxId`, `relatedExternalId`.

  | Field                | Description                                                                                                                                                                                                                |
  | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `relationshipType`   | Graph enum (`shareholder`, `manages`, `owns`, `employed_by`, …)                                                                                                                                                            |
  | `role` / `roles`     | Role(s) stored in `metadata.roles` (e.g. `SOCIO`, `REPRESENTANTE`)                                                                                                                                                         |
  | `relatedCountryCode` | Optional ISO2 to normalize `relatedTaxId` (default: new entity `countryCode`)                                                                                                                                              |
  | `asSource`           | Default `true`: the created entity is **source** and the related entity is **target**. With `shareholder`, the created entity is a shareholder of the counterpart (e.g. person → company). `false` reverses the direction. |

  If the counterpart is missing → **404** `RELATED_ENTITY_NOT_FOUND` and the entity is **not** created.
</ParamField>

<ParamField body="status" type="string" default="under_review">
  Initial status for the entity. Options:

  * `active` - Entity is active
  * `inactive` - Entity is inactive
  * `blocked` - Entity is blocked
  * `under_review` - Entity is under review (default)
  * `suspended` - Entity is suspended
  * `expired` - Entity has expired
  * `deleted` - Soft deleted
  * `rejected` - Entity was rejected
</ParamField>

<ParamField body="monitoring" type="object">
  Optional. Requests **watchlist mode** (op 1: screening plus watchlist subscription for periodic runs) for a **monitoring-capable enrichment**, instead of a one-off check (op 0).

  **Scope today:** only **`global_gueno_sanctions_enrichment`**. Map keys must match codes in `autoExecuteIntegrations.enrichments`. Legacy `*_check` codes were **removed (2026-06-04)** and are no longer part of the contract.

  * **`main`**: flags for the **main entity** on this `POST /entities`.
  * **`relationships`**: **ignored** here; use [Create automatically](/en/api-reference/entities/create-automatic) with `depth` > 0.

  **Per-code value** (object recommended; legacy `boolean` still accepted):

  * `{ "watchlist": true }` — subscribe; monitoring rules use the entity’s global `riskMatrixId`.
  * `{ "watchlist": true, "riskMatrixId": "<uuid>" }` — subscribe; **only** that matrix on monitoring-triggered runs.
  * `{ "watchlist": false }` or `false` — no watchlist.
  * `true` — same as `{ "watchlist": true }`.

  **Requirements** (if any fail, enrichment still runs as op 0): (1) code in `enrichments` or active via execute-all; (2) org **monitoring** ON in Marketplace for Gu1 sanctions.

  Guide: [Gu1 sanctions monitoring](/es/guias/monitoreo-sanciones-gueno-cliente). Examples: [Monitoring on create](#example-gu1-sanctions-monitoring-on-create).
</ParamField>

<ParamField body="autoExecuteIntegrations" type="object">
  Configure automatic execution of enrichment integrations when creating the entity.

  Properties:

  * `executeAllActiveEnrichments` (boolean) - Execute all active enrichment integrations
  * `enrichments` (array) - Array of specific enrichment provider codes to execute (see [Provider Codes Reference](/en/api-reference/integrations/provider-codes))
  * `enrichmentGroupRefs` (array of strings, optional) - Marketplace **enrichment group** slugs. With `executeAllActiveEnrichments: false`, groups are resolved and merged with explicit `enrichments`. With `executeAllActiveEnrichments: true`, group refs are ignored (not resolved); explicit `enrichments` may still append after the active set.
  * `excludeEnrichments` (array, optional, default: `[]`) - Provider codes to omit from the final resolved enrichment set
</ParamField>

## Entity Data Structures

### Person Entity

```json theme={null}
{
  "person": {
    "firstName": "string",
    "lastName": "string",
    "dateOfBirth": "YYYY-MM-DD",
    "nationality": "string",
    "occupation": "string",
    "income": number,
    "incomeCurrency": "string",
    "address": "string | object (see Address Format note)",
    "city": "string",
    "state": "string",
    "country": "string",
    "postalCode": "string",
    "email": "string",
    "gender": "M | F | male | female | unknown | other",
    "phone": "string",
    "alternativePhone": "string",
    "idType": "national_id | passport | drivers_license | tax_id | other",
    "idNumber": "string",
    "isPep": boolean,
    "pepPosition": "string",
    "pepCountry": "string"
  }
}
```

<Note>
  **Gender (`entityData.person.gender`)** — closed enum. Only the values below are accepted; any other string (e.g. `X`, `non_binary`) returns a **validation error**.

  | Value           | Meaning                                                    |
  | --------------- | ---------------------------------------------------------- |
  | `M` or `male`   | Male                                                       |
  | `F` or `female` | Female                                                     |
  | `other`         | Other / non-binary — use this code for non-binary identity |
  | `unknown`       | Not provided or unknown                                    |

  **Argentina (AR):** automatic CUIL derivation from DNI + gender and RENAPER identity checks only recognize `M`/`F` (or `male`/`female`). With `other` or `unknown`, CUIL is not auto-derived and RENAPER cannot use gender from the entity.
</Note>

### Company Entity

```json theme={null}
{
  "company": {
    "legalName": "string",
    "tradeName": "string",
    "incorporationDate": "YYYY-MM-DD",
    "companySubtype": "merchant | investment_fund | holding | bank | payment_processor | other",
    "industry": "string",
    "websiteUrl": "string",
    "employeeCount": number,
    "revenue": number,
    "revenueCurrency": "string",
    "contactInfo": {
      "email": "string",
      "phone": "string",
      "alternativePhone": "string"
    },
    "address": "string | object (see Address Format note)",
    "city": "string",
    "state": "string",
    "country": "string",
    "postalCode": "string"
  }
}
```

<Note>
  **Address Format**: The `address` field supports both formats:

  * **String format** (simple): `"Av. Paulista, 1000, São Paulo, SP, Brazil"`
  * **Object format** (structured):
    ```json theme={null}
    {
      "street": "Av. Paulista",
      "number": "1000",
      "complement": "Suite 200",
      "neighborhood": "Bela Vista",
      "city": "São Paulo",
      "state": "SP",
      "country": "Brazil",
      "postalCode": "01310-100"
    }
    ```

  This applies to `person`, `company`, and `location` entities.
</Note>

### Device Entity

```json theme={null}
{
  "device": {
    "type": "string",
    "model": "string",
    "manufacturer": "string",
    "serialNumber": "string",
    "os": "string",
    "lastSeen": "ISO8601 timestamp",
    "imei": "string",
    "carrier": "string",
    "phoneNumber": "string"
  }
}
```

### Payment Method Entity

```json theme={null}
{
  "paymentMethod": {
    "type": "string",
    "issuer": "string",
    "lastFour": "string",
    "expiryDate": "YYYY-MM",
    "isDefault": boolean,
    "pixKey": "string",
    "pixKeyType": "string",
    "bankName": "string",
    "bankCode": "string"
  }
}
```

### Location Entity

```json theme={null}
{
  "location": {
    "type": "string",
    "address": "string | object (see Address Format note)",
    "city": "string",
    "state": "string",
    "postalCode": "string",
    "coordinates": {
      "lat": number,
      "lng": number
    }
  }
}
```

### Document Entity

```json theme={null}
{
  "document": {
    "type": "string",
    "issuer": "string",
    "issueDate": "YYYY-MM-DD",
    "expiryDate": "YYYY-MM-DD",
    "documentNumber": "string"
  }
}
```

### Alert Entity

```json theme={null}
{
  "alert": {
    "alertNumber": "string",
    "alertType": "RISK | COMPLIANCE | FRAUD | REGULATORY | SYSTEM",
    "severity": "INFO | WARNING | HIGH | CRITICAL",
    "status": "NEW | ACKNOWLEDGED | INVESTIGATING | RESOLVED | FALSE_POSITIVE",
    "sourceSystem": "string",
    "triggerRuleId": "string",
    "triggerCondition": "string",
    "affectedEntityId": "string",
    "relatedEntityIds": ["string"],
    "alertedAt": "ISO8601 timestamp",
    "acknowledgedAt": "ISO8601 timestamp",
    "acknowledgedBy": "string",
    "resolvedAt": "ISO8601 timestamp",
    "resolvedBy": "string",
    "resolutionNotes": "string",
    "falsePositiveReason": "string"
  }
}
```

## Query Parameters

<ParamField query="refresh" type="boolean" default="false">
  Force re-enrichment of the entity even if it already exists in the system.

  **Type**: `boolean` (query string: `"true"` or `"false"`)

  **Behavior**:

  * When `true`: Forces the system to fetch fresh data from enrichment providers (e.g., background checks, KYC data, company registries)
  * When `false` or omitted: Uses cached enrichment data if available
  * Overrides organization setting `enrichmentsConfig.reEnrichExistingEntities`

  **Use Cases**:

  * Re-validating entity data after a significant time period
  * Updating information when you know external data has changed
  * Manual refresh triggered by compliance team
  * Periodic data quality audits

  **Example**:

  ```bash theme={null}
  POST http://api.gu1.ai/entities?refresh=true
  ```

  **Note**: Re-enrichment may incur additional costs from third-party data providers.
</ParamField>

## Response

<ResponseField name="success" type="boolean">
  Indicates if the entity was created successfully
</ResponseField>

<ResponseField name="entity" type="object">
  The created entity object including:

  * `id` - gu1's internal ID
  * `externalId` - Your external ID
  * `organizationId` - Your organization ID
  * `type` - Entity type
  * `name` - Entity name
  * `riskScore` - Initial risk score (0-100)
  * `status` - Entity status
  * `entityData` - Type-specific data
  * `attributes` - Custom attributes
  * `createdAt` - Creation timestamp
  * `updatedAt` - Last update timestamp
</ResponseField>

<ResponseField name="rulesResult" type="object">
  Result of rules execution (only present when rules ran, e.g. when **skipRulesExecution** is `false` and a risk matrix is configured), including:

  * **success** (boolean) - Whether rules executed successfully
  * **rulesTriggered** (number) - Number of rules that were triggered
  * **alerts** (array) - Alerts generated by rules
  * **riskScore** (number) - Final calculated risk score
  * **decision** (string) - Final decision (APPROVE, REJECT, HOLD, REVIEW\_REQUIRED)
  * **rulesExecutionSummary** (object) - Present when rules ran. See below for structure.
</ResponseField>

<ResponseField name="rulesExecutionSummary" type="object">
  **At the root of the response** (same as transactions API). Only present when rules ran (e.g. skipRulesExecution is false and rules engine executed). Same value as `rulesResult.rulesExecutionSummary`. Summary of which rules matched (hit) vs did not match (no hit), executed actions, and total score. Omitted when rules did not run.

  * **rulesHit** (array) - Rules whose conditions were met. Each item: **name**, **description**, **score**, **priority**, **category**, **status** (e.g. `active`, `shadow`), **conditions** (array of `{ field, value, operator? }`), **actions** (alerts, suggestion, status, assignedUser).
  * **rulesNoHit** (array) - Rules that were evaluated but conditions were not met. Same structure as rulesHit (includes configured actions, not executed).
  * **actionsExecuted** (object) - Aggregated executed actions across all rules that hit: **alerts** (array of `{ name?, type?, severity?, description? }`), **suggestion** (`BLOCK` | `SUSPEND` | `FLAG`, highest weight), **status** (entity status applied, if any), **assignedUser** (`{ userId }`, if any), **customKeys** (array of strings, optional) — custom action keys from matched rules; for integrations/workflows.
  * **totalScore** (number) - Sum of **score** of all rules that hit and are **not** in `shadow` status.
</ResponseField>

## Example: Gu1 Sanctions Monitoring on Create

**`monitoring`** does not run integrations by itself — it only changes **how** an enrichment already listed in **`autoExecuteIntegrations`** runs. Today the documented case is **`global_gueno_sanctions_enrichment`** (org must allow monitoring in Marketplace).

| Condition                                                                             | Effect                                                 |
| ------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| Code in `enrichments` + `monitoring.main[code]` with watchlist on + org monitoring ON | **Op 1** — screening plus watchlist / daily screening. |
| No `monitoring` or `watchlist: false`                                                 | **Op 0** — one-off screening only.                     |
| `monitoring` set but org monitoring OFF                                               | **Op 0** — no mandatory error; screening still runs.   |
| `monitoring` without the code in `enrichments`                                        | No effect.                                             |

<Warning>
  Legacy `*_check` codes (e.g. `global_gueno_sanctions_check`) were **removed (2026-06-04)**. For watchlist on create, use **`global_gueno_sanctions_enrichment`** in both `enrichments` and `monitoring.main`.
</Warning>

### Watchlist Only (Person)

```json theme={null}
{
  "type": "person",
  "externalId": "cust_screening_001",
  "name": "María González",
  "countryCode": "AR",
  "taxId": "27-12345678-1",
  "entityData": {
    "person": {
      "firstName": "María",
      "lastName": "González",
      "dateOfBirth": "1985-03-15",
      "nationality": "AR"
    }
  },
  "monitoring": {
    "main": {
      "global_gueno_sanctions_enrichment": {
        "watchlist": true
      }
    }
  },
  "autoExecuteIntegrations": {
    "executeAllActiveEnrichments": false,
    "enrichments": ["global_gueno_sanctions_enrichment"]
  }
}
```

### Local Enrichments + Gu1 Monitoring (AR Person)

Combine registry/KYC enrichments with Gu1 watchlist in one `POST /entities`. **`monitoring` only affects** keys present in the map.

```json theme={null}
{
  "type": "person",
  "name": "María González",
  "taxId": "20-12345678-9",
  "countryCode": "AR",
  "riskMatrixId": "550e8400-e29b-41d4-a716-446655440000",
  "entityData": {
    "person": {
      "firstName": "María",
      "lastName": "González",
      "dateOfBirth": "1985-03-15"
    }
  },
  "autoExecuteIntegrations": {
    "executeAllActiveEnrichments": false,
    "enrichments": [
      "ar_renaper_data_enrichment",
      "ar_repet_person_enrichment",
      "global_gueno_sanctions_enrichment"
    ]
  },
  "monitoring": {
    "main": {
      "global_gueno_sanctions_enrichment": {
        "watchlist": true
      }
    }
  }
}
```

`ar_renaper_*` and `ar_repet_*` run as normal enrichments; only `global_gueno_sanctions_enrichment` can use op 1 when org monitoring is enabled.

### Dedicated Risk Matrix for Monitoring (Optional)

```json theme={null}
"monitoring": {
  "main": {
    "global_gueno_sanctions_enrichment": {
      "watchlist": true,
      "riskMatrixId": "660e8400-e29b-41d4-a716-446655440001"
    }
  }
}
```

`riskMatrixId: null` means **inherit** the entity global matrix for monitoring runs.

### Company (`type: "company"`)

Same `monitoring.main` shape; adjust `type`, `entityData.company`, and `enrichments` for your country.

```json theme={null}
{
  "type": "company",
  "externalId": "co_screening_001",
  "name": "Tech Solutions S.A.",
  "countryCode": "AR",
  "taxId": "30-71000001-2",
  "entityData": {
    "company": {
      "legalName": "Tech Solutions S.A.",
      "tradeName": "Tech Solutions",
      "industry": "Software"
    }
  },
  "monitoring": {
    "main": {
      "global_gueno_sanctions_enrichment": { "watchlist": true }
    }
  },
  "autoExecuteIntegrations": {
    "executeAllActiveEnrichments": false,
    "enrichments": ["global_gueno_sanctions_enrichment"]
  }
}
```

<Info>
  **`monitoring.relationships`** is not used on `POST /entities`. For shareholders or related entities in the same job, use [Create automatically](/en/api-reference/entities/create-automatic) with `depth` > 0, `monitoring.relationships`, and matching codes in `autoExecuteIntegrationsShareholders`.
</Info>

## Examples

### Create Person Entity (KYC)

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST http://api.gu1.ai/entities \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "type": "person",
      "externalId": "customer_12345",
      "name": "María González",
      "countryCode": "AR",
      "taxId": "20-12345678-9",
      "entityData": {
        "person": {
          "firstName": "María",
          "lastName": "González",
          "dateOfBirth": "1985-03-15",
          "nationality": "AR",
          "occupation": "Software Engineer",
          "income": 85000
        }
      },
      "attributes": {
        "email": "maria.gonzalez@example.com",
        "phone": "+54 11 1234-5678",
        "customerSince": "2024-01-15"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('http://api.gu1.ai/entities', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      type: 'person',
      externalId: 'customer_12345',
      name: 'María González',
      countryCode: 'AR',
      taxId: '20-12345678-9',
      entityData: {
        person: {
          firstName: 'María',
          lastName: 'González',
          dateOfBirth: '1985-03-15',
          nationality: 'AR',
          occupation: 'Software Engineer',
          income: 85000
        }
      },
      attributes: {
        email: 'maria.gonzalez@example.com',
        phone: '+54 11 1234-5678',
        customerSince: '2024-01-15'
      }
    })
  });

  const data = await response.json();
  console.log(data.entity);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'http://api.gu1.ai/entities',
      headers={
          'Authorization': 'Bearer YOUR_API_KEY',
          'Content-Type': 'application/json'
      },
      json={
          'type': 'person',
          'externalId': 'customer_12345',
          'name': 'María González',
          'countryCode': 'AR',
          'taxId': '20-12345678-9',
          'entityData': {
              'person': {
                  'firstName': 'María',
                  'lastName': 'González',
                  'dateOfBirth': '1985-03-15',
                  'nationality': 'AR',
                  'occupation': 'Software Engineer',
                  'income': 85000
              }
          },
          'attributes': {
              'email': 'maria.gonzalez@example.com',
              'phone': '+54 11 1234-5678',
              'customerSince': '2024-01-15'
          }
      }
  )

  entity = response.json()['entity']
  print(entity)
  ```
</CodeGroup>

### Create Company Entity (KYB)

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST http://api.gu1.ai/entities \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "type": "company",
      "externalId": "company_789",
      "name": "Tech Solutions S.A.",
      "countryCode": "BR",
      "taxId": "12.345.678/0001-90",
      "entityData": {
        "company": {
          "legalName": "Tech Solutions Sociedade Anônima",
          "tradeName": "Tech Solutions",
          "incorporationDate": "2020-06-15",
          "industry": "Software Development",
          "employeeCount": 50,
          "revenue": 5000000
        }
      },
      "attributes": {
        "website": "https://techsolutions.com.br",
        "registeredAddress": "Av. Paulista, 1000, São Paulo",
        "partnershipTier": "gold"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('http://api.gu1.ai/entities', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      type: 'company',
      externalId: 'company_789',
      name: 'Tech Solutions S.A.',
      countryCode: 'BR',
      taxId: '12.345.678/0001-90',
      entityData: {
        company: {
          legalName: 'Tech Solutions Sociedade Anônima',
          tradeName: 'Tech Solutions',
          incorporationDate: '2020-06-15',
          industry: 'Software Development',
          employeeCount: 50,
          revenue: 5000000
        }
      },
      attributes: {
        website: 'https://techsolutions.com.br',
        registeredAddress: 'Av. Paulista, 1000, São Paulo',
        partnershipTier: 'gold'
      }
    })
  });

  const data = await response.json();
  console.log(data.entity);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'http://api.gu1.ai/entities',
      headers={
          'Authorization': 'Bearer YOUR_API_KEY',
          'Content-Type': 'application/json'
      },
      json={
          'type': 'company',
          'externalId': 'company_789',
          'name': 'Tech Solutions S.A.',
          'countryCode': 'BR',
          'taxId': '12.345.678/0001-90',
          'entityData': {
              'company': {
                  'legalName': 'Tech Solutions Sociedade Anônima',
                  'tradeName': 'Tech Solutions',
                  'incorporationDate': '2020-06-15',
                  'industry': 'Software Development',
                  'employeeCount': 50,
                  'revenue': 5000000
              }
          },
          'attributes': {
              'website': 'https://techsolutions.com.br',
              'registeredAddress': 'Av. Paulista, 1000, São Paulo',
              'partnershipTier': 'gold'
          }
      }
  )

  entity = response.json()['entity']
  print(entity)
  ```
</CodeGroup>

## Response Example

```json theme={null}
{
  "success": true,
  "entity": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "externalId": "customer_12345",
    "organizationId": "8e2f89ab-c216-4eb4-90eb-ca5d44499aaa",
    "type": "person",
    "name": "María González",
    "taxId": "20-12345678-9",
    "countryCode": "AR",
    "riskScore": 25,
    "status": "active",
    "entityData": {
      "person": {
        "firstName": "María",
        "lastName": "González",
        "dateOfBirth": "1985-03-15",
        "nationality": "AR",
        "occupation": "Software Engineer",
        "income": 85000
      }
    },
    "attributes": {
      "email": "maria.gonzalez@example.com",
      "phone": "+54 11 1234-5678",
      "customerSince": "2024-01-15"
    },
    "createdAt": "2024-10-03T14:30:00.000Z",
    "updatedAt": "2024-10-03T14:30:00.000Z"
  }
}
```

## Error Responses

### 400 Bad Request — Invalid tax ID

```json theme={null}
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid CUIT format. Please check the format and try again.",
    "details": {
      "field": "taxId",
      "taxIdName": "CUIT",
      "providedValue": "20-12345678-9"
    }
  },
  "entity": null
}
```

### 400 Bad Request — Missing required fields

```json theme={null}
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Missing required fields for company creation",
    "details": {
      "missingFields": ["legalName", "industry"],
      "requiredFields": ["legalName", "tradeName", "industry", "incorporationDate"],
      "countryCode": "BR"
    }
  },
  "entity": null
}
```

### 409 Conflict — Duplicate entity

```json theme={null}
{
  "success": false,
  "error": {
    "code": "DUPLICATE_ENTITY",
    "message": "Entity with this external_id already exists",
    "details": {
      "field": "external_id",
      "value": "customer_12345",
      "constraint": "entities_organization_external_id_unique"
    }
  },
  "entity": null
}
```

Duplicate **tax ID** (same organization, any entity type) returns **`DUPLICATE_TAX_ID`** with `existingEntityId` / `existingEntityType` in `details` when available.

### 401 Unauthorized

```json theme={null}
{
  "error": "Invalid or missing API key",
  "code": "INVALID_KEY"
}
```

### 429 Too Many Requests

```json theme={null}
{
  "error": "Rate limit exceeded",
  "code": "RATE_LIMIT_EXCEEDED",
  "message": "You have exceeded your API rate limit. Please wait before making more requests.",
  "retryAfter": 3600,
  "limit": 100,
  "remaining": 0,
  "resetAt": "2025-01-15T10:00:00Z"
}
```

### 500 Internal Server Error

```json theme={null}
{
  "success": false,
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "An unexpected error occurred while creating the entity",
    "details": {
      "message": "Database connection timeout"
    }
  },
  "entity": null
}
```

## Next Steps

After creating an entity, you can:

1. [Request AI Analysis](/en/api-reference/entities/analyze) - Get automated risk assessment
2. [List Entities](/en/api-reference/entities/list) - Query your entities
3. [Get Entity Details](/en/api-reference/entities/get) - Retrieve complete entity information
4. [Apply Rules](/en/api-reference/rules/execute) - Run compliance and risk rules
