> ## 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.

# Update a company by external ID

> Update a company entity in gu1 using your own external identifier instead of the internal UUID, useful when migrating from legacy CRM or core systems.

## Overview

This endpoint allows you to update an entity using your own external identifier instead of our internal UUID. This is useful when you don't store our UUIDs in your system and only track your own external IDs.

The functionality is identical to `PATCH /entities/:id`, but uses `externalId` as the identifier.

## Path Parameters

<ParamField path="externalId" type="string" required>
  Your unique external identifier for the entity
</ParamField>

## Request Body

<ParamField body="name" type="string">
  Entity name (person full name or company name)
</ParamField>

<ParamField body="taxId" type="string">
  Tax identification number (SSN, EIN, VAT, RFC, etc.)
</ParamField>

<ParamField body="nationality" type="string | null">
  Root-level nationality (ISO 3166-1 alpha-2 when persisted). Omit to leave unchanged; send `null` to clear. Updating `nationality` inside `entityData` in the same request may recalculate the root field.
</ParamField>

<ParamField body="status" type="string">
  Entity status. Possible values:

  * `active`: Entity is active and operational
  * `inactive`: Entity is inactive
  * `blocked`: Entity is blocked (requires `reason`)
  * `suspended`: Entity is suspended (requires `reason`)
  * `rejected`: Entity was rejected during onboarding (requires `reason`)

  **Note**: Changing to `blocked`, `suspended`, or `rejected` requires providing a `reason` for audit purposes.
</ParamField>

<ParamField body="reason" type="string">
  Required when changing status to `blocked`, `suspended`, or `rejected`. Provides audit trail for the status change.
</ParamField>

<ParamField body="riskMatrixId" type="string (uuid)">
  Risk matrix ID to assign to this entity. The risk matrix determines which rules will be executed for risk evaluation.
</ParamField>

<ParamField body="entityData" type="object">
  Entity-specific data structure. For person entities, use `entityData.person`. For company entities, use `entityData.company`.

  **Person fields**:

  * `firstName`: First name
  * `lastName`: Last name
  * `middleName`: Middle name
  * `dateOfBirth`: Date of birth (YYYY-MM-DD)
  * `nationality`: Nationality (ISO 3166-1 alpha-2)
  * `email`: Email address
  * `phone`: Phone number
  * `address`: Address object (street, city, state, country, postalCode)

  **Company fields**:

  * `legalName`: Legal company name
  * `tradingNames`: Array of trading names
  * `registrationNumber`: Company registration number
  * `incorporationDate`: Date of incorporation (YYYY-MM-DD)
  * `industry`: Industry/sector
  * `employees`: Number of employees
  * `website`: Company website
  * `address`: Address object
</ParamField>

<ParamField body="attributes" type="object">
  Custom key-value attributes for flexible entity data storage
</ParamField>

<ParamField body="metadata" type="object">
  System metadata (usually set by the system, but can be updated)
</ParamField>

## Immutable Fields

The following fields **cannot** be changed after entity creation:

* `type`: Entity type (person or company)
* `countryCode`: Entity country code (ISO 3166-1 alpha-2)

## Response

Returns the updated entity object.

<ResponseField name="entity" type="object">
  The updated entity object with all current values
</ResponseField>

<ResponseField name="evaluation" type="object | null">
  Evaluation object (currently null - re-evaluation feature temporarily disabled)
</ResponseField>

<ResponseField name="previousEntity" type="object">
  The entity state before the update (for audit purposes)
</ResponseField>

## Example Request

```bash theme={null}
curl -X PATCH https://api.gueno.ai/entities/by-external-id/customer-12345 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Michael Doe",
    "status": "active",
    "entityData": {
      "person": {
        "firstName": "John",
        "middleName": "Michael",
        "lastName": "Doe",
        "email": "john.doe@example.com",
        "phone": "+1-555-0123"
      }
    },
    "riskMatrixId": "matrix-uuid-here"
  }'
```

## Example Response

```json theme={null}
{
  "entity": {
    "id": "entity-uuid",
    "organizationId": "org-uuid",
    "externalId": "customer-12345",
    "type": "person",
    "name": "John Michael Doe",
    "taxId": "123-45-6789",
    "countryCode": "US",
    "nationality": "US",
    "status": "active",
    "riskScore": "35.00",
    "riskMatrixId": "matrix-uuid-here",
    "entityData": {
      "person": {
        "firstName": "John",
        "middleName": "Michael",
        "lastName": "Doe",
        "email": "john.doe@example.com",
        "phone": "+1-555-0123"
      }
    },
    "createdAt": "2025-12-20T10:00:00Z",
    "updatedAt": "2025-12-24T15:30:00Z"
  },
  "evaluation": null,
  "previousEntity": {
    "id": "entity-uuid",
    "name": "John Doe",
    "status": "pending",
    ...
  }
}
```

## Status Change with Reason

When changing status to `blocked`, `suspended`, or `rejected`, you **must** provide a reason:

```bash theme={null}
curl -X PATCH https://api.gueno.ai/entities/by-external-id/customer-12345 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "blocked",
    "reason": "Failed sanctions screening - OFAC match detected"
  }'
```

## Use Cases

### 1. Update Customer Information

Update customer data from your CRM or user management system:

```json theme={null}
{
  "name": "Jane Smith-Johnson",
  "entityData": {
    "person": {
      "lastName": "Smith-Johnson",
      "email": "jane.smithjohnson@example.com",
      "address": {
        "street": "456 New St",
        "city": "Seattle",
        "state": "WA",
        "country": "US",
        "postalCode": "98101"
      }
    }
  }
}
```

### 2. Assign Risk Matrix

Assign or change the risk matrix for an entity:

```json theme={null}
{
  "riskMatrixId": "high-risk-matrix-uuid"
}
```

After updating the risk matrix, you should trigger a re-analysis using `POST /entities/:entityId/analyze` to re-evaluate the entity with the new rules.

### 3. Block Entity After Investigation

Block an entity after compliance investigation:

```json theme={null}
{
  "status": "blocked",
  "reason": "Investigation revealed connections to sanctioned entities"
}
```

### 4. Sync Company Data

Update company information from business registry:

```json theme={null}
{
  "entityData": {
    "company": {
      "employees": 250,
      "revenue": 50000000,
      "website": "https://company-new-domain.com"
    }
  }
}
```

## Events and Webhooks

### Real-time Events

After a successful update, the following real-time event is emitted via WebSocket:

```json theme={null}
{
  "event": "entity.updated",
  "entityId": "entity-uuid",
  "externalId": "customer-12345",
  "updatedFields": ["name", "entityData"],
  "previousValues": {...},
  "newValues": {...}
}
```

### Webhook Triggers

If you change **only** the `status` field (without other field changes), a webhook is triggered:

**Event**: `entity.status_changed`

```json theme={null}
{
  "event": "entity.status_changed",
  "entityId": "entity-uuid",
  "externalId": "customer-12345",
  "oldStatus": "active",
  "newStatus": "blocked",
  "reason": "Failed sanctions screening",
  "changedBy": "user-uuid",
  "timestamp": "2025-12-24T15:30:00Z"
}
```

**Note**: If you update status **along with other fields**, the webhook is NOT triggered (assumes bulk entity edit rather than standalone status change).

## Audit Trail

Every entity update creates an `ATTRIBUTE_CHANGED` event in the entity events log with:

* Before state (all changed fields)
* After state (all changed fields)
* User who made the change
* Timestamp
* Source (API, dashboard, etc.)

Query audit trail:

```bash theme={null}
GET /entity-events?entityId=:entityId&eventType=ATTRIBUTE_CHANGED
```

## Error Responses

<ResponseField name="404 Not Found" type="error">
  Entity with the specified `externalId` not found in your organization

  ```json theme={null}
  {
    "error": "Entity not found"
  }
  ```
</ResponseField>

<ResponseField name="400 Bad Request" type="error">
  Invalid request data or validation error

  ```json theme={null}
  {
    "error": "Changing status to 'blocked' requires a reason for audit purposes."
  }
  ```
</ResponseField>

<ResponseField name="400 Bad Request" type="error">
  Attempting to change immutable fields

  ```json theme={null}
  {
    "error": "Field 'type' cannot be changed after entity creation"
  }
  ```
</ResponseField>

## Best Practices

1. **Always Set External ID on Creation**: Set `externalId` when creating entities via `POST /entities` to enable updates by external ID.

2. **Use for System Integration**: This endpoint is ideal for integrations where you sync data from external systems (CRM, ERP, etc.) using your own IDs.

3. **Provide Reasons for Status Changes**: Always include meaningful reasons when blocking, suspending, or rejecting entities for compliance audit trail.

4. **Re-analyze After Risk Matrix Change**: After assigning a new risk matrix, trigger `POST /entities/:entityId/analyze` to re-evaluate with new rules.

5. **Handle 404 Gracefully**: If entity not found by external ID, you may need to create it first using `POST /entities`.

6. **Batch Updates**: For updating multiple entities, call this endpoint concurrently with different external IDs for better performance.

## Related Endpoints

* [Create Entity](/en/api-reference/entities/create) - Create new entity
* [Update Entity by UUID](/en/api-reference/entities/update) - Update using internal UUID
* [Get Entity](/en/api-reference/entities/get) - Retrieve entity details
* [Analyze Entity](/en/api-reference/entities/analyze) - Trigger risk analysis
