# Documentación API Go High Level (GHL) — Monte Providencia

> Versión de API: `2021-07-28`
> Base URL: `https://services.leadconnectorhq.com`
> Autenticación: `Bearer <API_TOKEN>` en header

---

## Índice

1. [Autenticación y Headers](#1-autenticación)
2. [Contactos](#2-contactos)
3. [Oportunidades](#3-oportunidades)
4. [Pipelines](#4-pipelines)
5. [Campos Personalizados](#5-campos-personalizados)
6. [Tags](#6-tags)
7. [Workflows](#7-workflows)
8. [Cuentas y Locations](#8-cuentas--locations)
9. [Búsquedas (Search)](#9-búsquedas-search)
10. [Errores Comunes](#10-errores-comunes)
11. [Apéndice: Códigos de Sucursales](#11-apéndice-códigos-de-sucursales)

---

## 1. Autenticación

### Headers requeridos en toda petición

```
Authorization: Bearer <API_TOKEN>
Version: 2021-07-28
Accept: application/json
```

### Cómo obtener el token

El token es el `API_token` asociado a cada Location ID. Se guarda en:
- `/data/workspace/agents/ghl/monte-providencia-accounts.csv`
- Formato: `Location_ID / API_TOKEN`

### Ejemplo con curl

```bash
curl -s -L "https://services.leadconnectorhq.com/contacts/" \
  -H "Authorization: Bearer TU_TOKEN_AQUI" \
  -H "Version: 2021-07-28"
```

---

## 2. Contactos

### 2.1 Obtener todos los contactos (GET /contacts/)

```
GET https://services.leadconnectorhq.com/contacts/?locationId={LOCATION_ID}&limit={1-100}
```

**Parámetros query:**
| Parámetro | Tipo | Descripción |
|---|---|---|
| `locationId` | string | **Requerido.** El Location ID de la cuenta |
| `limit` | int | 1-100 (máximo 100, API lo rechaza si es mayor) |
| `startAfter` | string | Cursor para paginar — valor de `nextPageUrl` |
| `startAfterId` | string | ID del último contacto para paginar |

**Nota sobre paginación:** La API devuelve `meta.nextPageUrl` con la URL completa de la siguiente página. No usa `skip`/offset. El campo `startAfter` se construye a partir del cursor en `nextPageUrl`.

```bash
# Primera página
curl -s "https://services.leadconnectorhq.com/contacts/?locationId=GBKkBpCmKu2QmloKFHy3&limit=100" \
  -H "Authorization: Bearer TOKEN" -H "Version: 2021-07-28"

# Segunda página (usar nextPageUrl completo)
curl -s "https://services.leadconnectorhq.com/contacts/?locationId=GBKkBpCmKu2QmloKFHy3&limit=100&startAfter={CURSOR}" \
  -H "Authorization: Bearer TOKEN" -H "Version: 2021-07-28"
```

**Respuesta:**
```json
{
  "contacts": [
    {
      "id": "CKFO2IvIw41sOGOtCeFi",
      "firstName": "Nicolas",
      "lastName": "Tielve",
      "email": "nicolas@ejemplo.com",
      "phone": "+525531320553",
      "locationId": "GbKkBpCmKu2QmloKFHy3",
      "tags": ["sucursal", "follow-up"],
      "customFields": [
        { "id": "N1apTH4TKBZ6PZqfs4L6", "value": "Ejército Nacional" }
      ],
      "type": "contact",
      "dateAdded": "2026-04-29T00:00:00Z",
      "updatedAt": "2026-04-29T00:00:00Z"
    }
  ],
  "meta": {
    "nextPageUrl": "https://services.leadconnectorhq.com/contacts/?locationId=...&startAfter=..."
  }
}
```

### 2.2 Obtener un contacto por ID (GET /contacts/{id})

```
GET https://services.leadconnectorhq.com/contacts/{CONTACT_ID}?locationId={LOCATION_ID}
```

```bash
curl -s "https://services.leadconnectorhq.com/contacts/CKFO2IvIw41sOGOtCeFi?locationId=GbKkBpCmKu2QmloKFHy3" \
  -H "Authorization: Bearer TOKEN" -H "Version: 2021-07-28"
```

### 2.3 Crear contacto (POST /contacts/)

```
POST https://services.leadconnectorhq.com/contacts/
```

**Body (JSON):**
```json
{
  "firstName": "Juan",
  "lastName": "Pérez",
  "email": "juan@ejemplo.com",
  "phone": "+525512345678",
  "locationId": "GbKkBpCmKu2QmloKFHy3",
  "tags": ["lead", "web"],
  "customFields": [
    { "id": "N1apTH4TKBZ6PZqfs4L6", "value": "Cancún" }
  ]
}
```

### 2.4 Actualizar contacto (PUT /contacts/{id})

```
PUT https://services.leadconnectorhq.com/contacts/{CONTACT_ID}
```

```json
{
  "firstName": "Juan Actualizado",
  "tags": ["lead", "web", "actualizado"],
  "customFields": [
    { "id": "N1apTH4TKBZ6PZqfs4L6", "value": "Cancún" }
  ]
}
```

### 2.5 Eliminar contacto (DELETE /contacts/{id})

```
DELETE https://services.leadconnectorhq.com/contacts/{CONTACT_ID}?locationId={LOCATION_ID}
```

### 2.6 Agregar tag a contacto (POST /contacts/{id}/tags)

```
POST https://services.leadconnectorhq.com/contacts/{CONTACT_ID}/tags
```

Body:
```json
{
  "tags": ["nuevo-tag"]
}
```

### 2.7 Eliminar tag de contacto (DELETE /contacts/{id}/tags/{tag})

```
DELETE https://services.leadconnectorhq.com/contacts/{CONTACT_ID}/tags/{TAG_NAME}
```

---

## 3. Oportunidades

### 3.1 Buscar oportunidades (POST /opportunities/search)

> ⚠️ **IMPORTANTE:** `GET /opportunities/` retorna vacío o 0 resultados. SIEMPRE usar `POST /opportunities/search`.

```
POST https://services.leadconnectorhq.com/opportunities/search
```

**Body:**
```json
{
  "locationId": "GbKkBpCmKu2QmloKFHy3",
  "limit": 100
}
```

**Respuesta:**
```json
{
  "total": 184,
  "opportunities": [
    {
      "id": "abc123",
      "name": "Venta BMW 2024",
      "status": "open",
      "pipelineId": "NipUIm51OGRx5xGDifGT",
      "pipelineStageId": "stage_xyz",
      "monetaryValue": 500000,
      "contactId": "CKFO2IvIw41sOGOtCeFi",
      "assignedTo": "user_123",
      "dateAdded": "2026-04-29T00:00:00Z"
    }
  ]
}
```

### 3.2 Obtener oportunidad por ID (GET /opportunities/{id})

```
GET https://services.leadconnectorhq.com/opportunities/{OPP_ID}?locationId={LOCATION_ID}
```

### 3.3 Crear oportunidad (POST /opportunities/)

```
POST https://services.leadconnectorhq.com/opportunities/
```

```json
{
  "name": "Nueva Oportunidad",
  "locationId": "GbKkBpCmKu2QmloKFHy3",
  "pipelineId": "NipUIm51OGRx5xGDifGT",
  "pipelineStageId": "stage_xyz",
  "contactId": "CKFO2IvIw41sOGOtCeFi",
  "monetaryValue": 100000,
  "assignedTo": "user_id",
  "status": "open"
}
```

### 3.4 Mover oportunidad a otro pipeline (PUT /opportunities/{id})

> Para cambiar una oportunidad de pipeline, se usa `PUT` con el nuevo `pipelineId` y `pipelineStageId`.

```
PUT https://services.leadconnectorhq.com/opportunities/{OPP_ID}
```

```json
{
  "pipelineId": "NipUIm51OGRx5xGDifGT",
  "pipelineStageId": "stage_destino"
}
```

**Nota:** Para obtener los pipelineStageId disponibles, primero hay que recuperar los pipelines (ver sección 4).

### 3.5 Eliminar oportunidad (DELETE /opportunities/{id})

```
DELETE https://services.leadconnectorhq.com/opportunities/{OPP_ID}?locationId={LOCATION_ID}
```

---

## 4. Pipelines

### 4.1 Obtener pipelines (GET /pipelines/)

> ⚠️ **NOTA:** Esta llamada frecuentemente retorna `[]` para muchas cuentas. Cuando esto ocurre, los `pipelineId` se pueden obtener desde las oportunidades existentes usando `POST /opportunities/search`.

```
GET https://services.leadconnectorhq.com/pipelines/?locationId={LOCATION_ID}
```

```json
{
  "pipelines": [
    {
      "id": "NipUIm51OGRx5xGDifGT",
      "name": "Pipeline Principal",
      "locationId": "GbKkBpCmKu2QmloKFHy3",
      "stages": [
        {
          "id": "stage_abc",
          "name": "Nuevo Lead",
          "order": 1
        },
        {
          "id": "stage_def",
          "name": "Contacto Hecho",
          "order": 2
        }
      ]
    }
  ]
}
```

### 4.2 Obtener pipeline específico (GET /pipelines/{pipelineId})

```
GET https://services.leadconnectorhq.com/pipelines/{PIPELINE_ID}?locationId={LOCATION_ID}
```

---

## 5. Campos Personalizados (Custom Fields)

### 5.1 Obtener todos los campos personalizados (GET /locations/{locationId}/customFields)

```
GET https://services.leadconnectorhq.com/locations/{LOCATION_ID}/customFields
```

```json
{
  "customFields": [
    {
      "id": "N1apTH4TKBZ6PZqfs4L6",
      "name": "Sucursal",
      "dataType": "SINGLE_OPTIONS",
      "options": ["Cancún", "Texcoco", "Ejército Nacional", ...]
    },
    {
      "id": "fRmSueH3BcHX8bCiybyC",
      "name": "Canal de Origen",
      "dataType": "SINGLE_OPTIONS"
    },
    {
      "id": "wtQb2PtY2GwJ4GI08BYG",
      "name": "Fuente de Prospecto",
      "dataType": "SINGLE_OPTIONS"
    }
  ]
}
```

### 5.2 Obtener las opciones de un campo SINGLE_OPTIONS

Las opciones vienen en el campo `options` del custom field.

### ⚠️ IDs de campos diferentes por cuenta

> **CRÍTICO:** Cada Location (sucursal) tiene sus propios IDs de campos personalizados. Un ID de campo en la cuenta Marca NO es el mismo en las sucursales.
>
> Ejemplo — Campo "Sucursal":
> - Monte Providencia Marca: `N1apTH4TKBZ6PZqfs4L6`
> - 85974 - MP - Ejército Nacional: `pmrGTW3tIa7oz7rQJMVx`
> - 85932 - MP - La Viga: `Wj1iYdPv98dYxvE8sDF8`
>
> Para auditar el campo Sucursal correctamente, primero hay que obtener los IDs de cada sucursal consultando `/locations/{id}/customFields`.

### 5.3 Crear campo personalizado (POST /locations/{locationId}/customFields)

```
POST https://services.leadconnectorhq.com/locations/{LOCATION_ID}/customFields
```

```json
{
  "name": "Mi Campo Nuevo",
  "dataType": "SINGLE_OPTIONS",
  "options": ["Opción 1", "Opción 2"],
  "placeholder": "Selecciona..."
}
```

### 5.4 Tipos de campo (dataType)

| dataType | Descripción |
|---|---|
| `SINGLE_OPTIONS` | Selector dropdown de una opción |
| `MULTIPLE_OPTIONS` | Checkboxes (múltiples opciones) |
| `TEXT` | Campo de texto libre |
| `LARGE_TEXT` | Textarea (texto largo) |
| `PHONE_NUMBER` | Número telefónico |
| `EMAIL_ADDRESS` | Correo electrónico |
| `MONETORY` | Monto en dinero |
| `DATE` | Fecha |
| `CHECKBOX` | Boolean (sí/no) |

---

## 6. Tags

### 6.1 Obtener todos los tags (GET /locations/{locationId}/tags)

```
GET https://services.leadconnectorhq.com/locations/{LOCATION_ID}/tags
```

```json
{
  "tags": [
    { "id": "tag_123", "name": "sucursal", "contactCount": 45 },
    { "id": "tag_456", "name": "lead", "contactCount": 120 }
  ]
}
```

### 6.2 Crear tag (POST /locations/{locationId}/tags)

```
POST https://services.leadconnectorhq.com/locations/{LOCATION_ID}/tags
```

Body:
```json
{ "name": "nuevo-tag" }
```

### 6.3 Eliminar tag (DELETE /locations/{locationId}/tags/{tagName})

```
DELETE https://services.leadconnectorhq.com/locations/{LOCATION_ID}/tags/{TAG_NAME}
```

### 6.4 Eliminar tag de contacto específico (DELETE /contacts/{id}/tags/{tagName})

```
DELETE https://services.leadconnectorhq.com/contacts/{CONTACT_ID}/tags/{TAG_NAME}?locationId={LOCATION_ID}
```

### 6.5 Agregar tag a contacto (POST /contacts/{id}/tags)

```
POST https://services.leadconnectorhq.com/contacts/{CONTACT_ID}/tags
```

Body:
```json
{ "tags": ["nuevo-tag"] }
```

---

## 7. Workflows

### 7.1 Obtener workflows (GET /workflows/)

```
GET https://services.leadconnectorhq.com/workflows/
```

**Parámetros query:**
| Parámetro | Descripción |
|---|---|
| `locationId` | **Requerido.** Location ID |
| `limit` | 1-100 |
| `status` | `active`, `inactive`, `draft` |

```json
{
  "workflows": [
    {
      "id": "wf_abc123",
      "name": "Sincronizar Contacto Creado",
      "status": "active",
      "trigger": "contact.created",
      "createdAt": "2026-01-01T00:00:00Z"
    }
  ]
}
```

### 7.2 Obtener un workflow específico (GET /locations/{locationId}/workflows/{workflowId})

```
GET https://services.leadconnectorhq.com/locations/{LOCATION_ID}/workflows/{WORKFLOW_ID}
```

### 7.3 Activar/Desactivar workflow (PUT /locations/{locationId}/workflows/{workflowId})

```
PUT https://services.leadconnectorhq.com/locations/{LOCATION_ID}/workflows/{WORKFLOW_ID}
```

```json
{
  "status": "active"
}
```

### 7.4 Estados de workflow

| Status | Significado |
|---|---|
| `active` | Publicada y corriendo |
| `inactive` | Pausada |
| `draft` | Borrador — no está publicada |

### 7.5 Triggers comunes

Los triggers disponibles varían según la configuración de GHL. Comunes:
- `contact.created` — Se ejecuta al crear contacto
- `contact.updated` — Se ejecuta al actualizar contacto
- `tag.added` — Se ejecuta al agregar tag
- `form.submission` — Se ejecuta al recibir formulario

---

## 8. Cuentas y Locations

### 8.1 Location ID de Monte Providencia (Marca)

| Campo | Valor |
|---|---|
| Location ID | `GbKkBpCmKu2QmloKFHy3` |
| Token | `pit-4e4266f8-97ac-4150-a971-cc9158809640` |

### 8.2 Obtener información de location (GET /locations/{locationId})

```
GET https://services.leadconnectorhq.com/locations/{LOCATION_ID}
```

### 8.3 Listar usuarios (GET /locations/{locationId}/users)

```
GET https://services.leadconnectorhq.com/locations/{LOCATION_ID}/users
```

---

## 9. Búsquedas (Search)

### 9.1 Búsqueda de contactos con filtros (POST /contacts/search)

> ⚠️ **NOTA:** Esta endpoint devuelve 404 o errores para muchas cuentas. Usar `GET /contacts/` con paginación en su lugar.

```
POST https://services.leadconnectorhq.com/contacts/search
```

```json
{
  "locationId": "GbKkBpCmKu2QmloKFHy3",
  "limit": 100,
  "query": "Nicolas"
}
```

### 9.2 Búsqueda de oportunidades (POST /opportunities/search)

> Esta es la forma correcta y principal de obtener oportunidades. **No usar GET.**

```
POST https://services.leadconnectorhq.com/opportunities/search
```

```json
{
  "locationId": "GbKkBpCmKu2QmloKFHy3",
  "limit": 100,
  "pipelineId": "NipUIm51OGRx5xGDifGT"
}
```

---

## 10. Errores Comunes

| Código | Causa | Solución |
|---|---|---|
| `400` | Body malformado | Verificar JSON, comas, comillas |
| `401` | Token inválido o expirado | Verificar el `Bearer <token>` |
| `404` | Recurso no encontrado | Verificar el ID del recurso |
| `422` | Datos inválidos | Revisar el formato del body |
| `429` | Rate limit | Esperar 5-10 segundos entre requests |
| `500` | Error interno del servidor | Reintentar más tarde |
| `limit > 100` | Límite de página excedido | Usar `limit=100` máximo |
| `[]` vacío en GET /pipelines/ | Endpoint no soportado | Usar POST /opportunities/search para obtener pipelineIds |
| `[]` vacío en GET /contacts/ | Rate limit o account empty | Verificar token y Location ID |

### Rate Limits

- No hay un rate limit documentado oficial, pero se recomienda:
  - **0.5-1 segundo** entre requests normales
  - **5-10 segundos** después de errores 429
  - Paginación: continuar solo cuando `nextPageUrl` exista

---

## 11. Apéndice: Códigos de Sucursales

### Monte Providencia — CSV de cuentas

Archivo: `/data/workspace/agents/ghl/monte-providencia-accounts.csv`

### Sucursales con IDs de campo Sucursal (Custom Field)

> Cada sucursal tiene su propio ID para el campo "Sucursal". Usar la tabla del CSV de cuentas para obtener el ID correcto.

| Sucursal | Location ID | Token (primeros 10 chars) |
|---|---|---|
| Monte Providencia (Marca) | GbKkBpCmKu2QmloKFHy3 | `pit-4e4266f8` |
| 0001 - MP -Qro DEMO | Z64WQKORPVwXb5mn68Ef | `pit-8215e76f` |
| Monte Providencia DEMO | Vf7qQl3L9vakJ8hDtQ8e | `pit-f162f285` |
| 85930 - MP - TULYEHUALCO | rQYjjwsGnjEGagskOxix | `pit-8001d42c` |
| 85931 - MP - Marina Nacional | HvDw9Eg3rjrwkbQJXqfi | `pit-155a2c8f` |
| 85932 - MP - La Viga | fKn9SaXZoKcjjLryg10v | `pit-350d963b` |
| 85957 - MP - PINOTEPA | 7H91g95hhLKwIUqSk0Rg | `pit-f68877be` |
| 85958 - MP - POCHUTLA | HvyNhH2IOe9ByeZrRo0N | `pit-0fb64a32` |
| 85974 - MP - Ejército Nacional | nF1uEaYB3mCK5em9bPn2 | `pit-dbdaabeb` |
| 85976 - MP - Cancún | uJEn2iuUficuml9zxAnt | `pit-7a23a1d8` |
| 85954 - MP - Izcalli | r0fiuXv6zQnFyXJW2SWU | `pit-8e8596a8` |

> Para la lista completa, consultar el archivo CSV.

---

## 12. Scripts de Auditoría Existentes

### Ubicación: `/data/workspace/agents/ghl/scripts/`

| Script | Descripción |
|---|---|
| `move_opportunities_pipeline.py` | Mueve oportunidades de un pipeline a otro |
| `check_multi_pipeline.py` | Detecta cuentas con múltiples pipelines |
| `find_contacts_without_sucursal.py` | Encuentra contactos sin campo Sucursal |
| `monitor_no_email.py` | Detecta contactos sin email en todas las cuentas (cron) |

### Monitoreo activo (cron jobs):

| Cron | Frecuencia | Qué hace |
|---|---|---|
| `GHL Monitor No Email` | Cada 30 min | Reporta nuevos contactos sin email |
| `Health Check Workflows` | Cada 30 min | Detecta workflows faltantes/inactivos |

Reportes: `/data/workspace/agents/ghl/reports/`

---

*Documentación generada en mayo 2026. Algunas endpoints pueden variar según el plan y configuración de GHL.*