# Assert / Upsert

> Creación o actualización idempotente de contactos, empresas y oportunidades

Source: https://docs.graph8.com/es/developers/assert/

Los endpoints de tipo assert ofrecen semántica idempotente de creación o actualización (upsert). Si existe un registro coincidente, se actualiza; de lo contrario, se crea uno nuevo. Esto permite invocarlos repetidamente sin generar duplicados.

---

## Assert Contact

`PUT /contacts/assert`

Crea o actualiza un contacto individual. La coincidencia se busca primero por `work_email` y, si no se encuentra, por `linkedin_url`.

Requiere `list_id` y al menos una clave de coincidencia (`work_email` o `linkedin_url`).

### Cuerpo de la solicitud

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `list_id` | integer | Sí | ID de la lista de destino |
| `work_email` | string | No* | Correo corporativo (clave de coincidencia principal) |
| `linkedin_url` | string | No* | URL de LinkedIn (clave de coincidencia alternativa) |
| `first_name` | string | No | Nombre |
| `last_name` | string | No | Apellido |
| `job_title` | string | No | Cargo |
| `company_domain` | string | No | Dominio de la empresa |
| ... | | | Cualquier otro campo de contacto |

*Se requiere al menos uno de `work_email` o `linkedin_url`.

### Ejemplo

**cURL**

```bash
curl -X PUT "https://api.graph8.com/api/v1/contacts/assert" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "list_id": 5,
    "work_email": "jane@acme.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "job_title": "VP of Sales"
  }'
```

**Python**

```python
response = requests.put(
    f"{BASE_URL}/contacts/assert",
    headers=HEADERS,
    json={
        "list_id": 5,
        "work_email": "jane@acme.com",
        "first_name": "Jane",
        "last_name": "Doe",
        "job_title": "VP of Sales"
    }
)
```

### Respuesta

```json
{
  "data": {
    "action": "created",
    "count": 1
  }
}
```

El campo `action` indica el resultado: `"created"` para un registro nuevo y `"updated"` para una coincidencia existente.

---

## Batch Assert Contacts

`PUT /contacts/assert/batch`

Crea o actualiza hasta 100 contactos a la vez. Cada contacto debe incluir `work_email` o `linkedin_url` como clave de coincidencia.

### Cuerpo de la solicitud

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `list_id` | integer | Sí | ID de la lista de destino |
| `contacts` | object[] | Sí | Hasta 100 objetos de contacto |

### Ejemplo

**cURL**

```bash
curl -X PUT "https://api.graph8.com/api/v1/contacts/assert/batch" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "list_id": 5,
    "contacts": [
      {"work_email": "jane@acme.com", "first_name": "Jane"},
      {"work_email": "bob@acme.com", "first_name": "Bob"}
    ]
  }'
```

**Python**

```python
response = requests.put(
    f"{BASE_URL}/contacts/assert/batch",
    headers=HEADERS,
    json={
        "list_id": 5,
        "contacts": [
            {"work_email": "jane@acme.com", "first_name": "Jane"},
            {"work_email": "bob@acme.com", "first_name": "Bob"}
        ]
    }
)
```

### Respuesta

```json
{
  "data": {
    "total": 2,
    "created": 2,
    "updated": 0,
    "errors": []
  }
}
```

---

## Assert Company

`PUT /companies/assert`

Crea o actualiza una empresa. La coincidencia se busca primero por `domain` y, si no se encuentra, por `linkedin_url`.

### Cuerpo de la solicitud

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `list_id` | integer | Sí | ID de la lista de destino |
| `domain` | string | No* | Dominio de la empresa (clave de coincidencia principal) |
| `linkedin_url` | string | No* | URL de LinkedIn (clave de coincidencia alternativa) |
| `name` | string | No | Nombre de la empresa |
| `industry` | string | No | Industria |
| `employee_count` | integer | No | Número de empleados |
| ... | | | Cualquier otro campo de empresa |

*Se requiere al menos uno de `domain` o `linkedin_url`.

### Ejemplo

**cURL**

```bash
curl -X PUT "https://api.graph8.com/api/v1/companies/assert" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "list_id": 5,
    "domain": "acme.com",
    "name": "Acme Inc",
    "industry": "Technology"
  }'
```

**Python**

```python
response = requests.put(
    f"{BASE_URL}/companies/assert",
    headers=HEADERS,
    json={
        "list_id": 5,
        "domain": "acme.com",
        "name": "Acme Inc",
        "industry": "Technology"
    }
)
```

### Respuesta

```json
{
  "data": {
    "action": "created",
    "count": 1
  }
}
```

---

## Batch Assert Companies

`PUT /companies/assert/batch`

Crea o actualiza hasta 100 empresas a la vez.

### Cuerpo de la solicitud

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `list_id` | integer | Sí | ID de la lista de destino |
| `companies` | object[] | Sí | Hasta 100 objetos de empresa |

---

## Assert Deal

`PUT /deals/assert`

Crea o actualiza una oportunidad. La coincidencia se realiza por `name` + `company_id`.

### Cuerpo de la solicitud

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `name` | string | Sí | Nombre de la oportunidad (clave de coincidencia) |
| `company_id` | string | No | ID de la empresa (clave de coincidencia, combinada con el nombre) |
| `amount` | number | No | Valor monetario |
| `currency` | string | No | Código de moneda |
| `stage_id` | string | No | ID de la etapa del pipeline |
| `pipeline_id` | string | No | ID del pipeline |
| `description` | string | No | Descripción de la oportunidad |
| `close_date` | string | No | Fecha estimada de cierre (ISO 8601) |

### Ejemplo

**cURL**

```bash
curl -X PUT "https://api.graph8.com/api/v1/deals/assert" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Enterprise Deal",
    "amount": 50000,
    "company_id": "comp-123"
  }'
```

**Python**

```python
response = requests.put(
    f"{BASE_URL}/deals/assert",
    headers=HEADERS,
    json={
        "name": "Enterprise Deal",
        "amount": 50000,
        "company_id": "comp-123"
    }
)
```

### Respuesta

```json
{
  "data": {
    "action": "created",
    "deal_id": "deal-new-abc"
  }
}
```

---

## Assert Deal-Contact Association

`PUT /contacts/{contact_id}/deals/assert`

Vincula un contacto con una oportunidad. Es idempotente: si la asociación ya existe, devuelve `"exists"` sin error.

### Cuerpo de la solicitud

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `deal_id` | string | Sí | ID de la oportunidad por asociar |

### Ejemplo

**cURL**

```bash
curl -X PUT "https://api.graph8.com/api/v1/contacts/12345/deals/assert" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"deal_id": "deal-abc"}'
```

### Respuesta

```json
{
  "data": {
    "action": "created",
    "deal_id": "deal-abc",
    "contact_id": 12345
  }
}
```

El campo `action` devuelve `"created"` para un vínculo nuevo, o `"exists"` si la asociación ya existía.
