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

# API de Eva para tu CRM

> Conecta tu sistema con los contactos y las oportunidades de Eva mediante una llave revocable.

## Requisitos

Necesitas ser propietario o administrador de la cuenta y tener un sistema capaz de hacer solicitudes HTTPS. La API está disponible para las cuentas de Eva; cada llave pertenece a una sola cuenta.

## Qué se sincroniza

| Dirección | Datos |
| - | - |
| Tu sistema → Eva | Crear o actualizar contactos y oportunidades, incluidos los campos personalizados registrados. |
| Eva → tu sistema | Leer contactos, oportunidades, dueños, campos y pipelines. Para avisos de cambios, configura **Webhook personalizado** por separado. |

También puedes buscar registros y leer o añadir notas en oportunidades.

La API no elimina registros, no crea campos ni ofrece un `external_id` propio. Guarda el `id` de Eva en tu sistema. Las llamadas a la API no consumen créditos.

## Conectar

1. Abre **Ajustes → Integraciones → API de Eva** y selecciona **Crear llave**.
2. Escribe un nombre que identifique tu sistema y elige **Solo lectura** (`crm:read`) o **Lectura y escritura** (`crm:write`). Una llave de escritura también puede leer.
3. Copia la llave `eva_sk_…` en ese momento. Eva solo muestra el valor completo una vez. Guárdalo como secreto en el servidor de tu sistema; no lo pongas en una página web pública.

El encabezado `Authorization` usa el formato `Bearer <llave>`. Envía un `User-Agent` real para que Cloudflare acepte la solicitud:

```bash theme={null}
curl 'https://api.goeva.ai/api/v1/public/crm/contacts?limit=50' \
  -H 'Authorization: Bearer eva_sk_TU_LLAVE' \
  -H 'User-Agent: MiCRM/1.0 contacto@miempresa.com'
```

Para crear o actualizar un contacto por correo o teléfono:

```bash theme={null}
curl -X POST 'https://api.goeva.ai/api/v1/public/crm/contacts' \
  -H 'Authorization: Bearer eva_sk_TU_LLAVE' \
  -H 'User-Agent: MiCRM/1.0 contacto@miempresa.com' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Ana","email":"ana@example.com","source":"Meta · Campaña octubre","fields":{"region":"Oeste"}}'
```

La respuesta incluye `created: true` para un contacto nuevo o `false` para uno ya encontrado. Usa `GET /fields?entity=contact` para conocer las claves válidas. Para campos de oportunidades, agrega `entity=opportunity&pipeline_id=<id>`.

`source` es **Origen del contacto** y va al nivel principal del JSON, no dentro de `fields`. Eva elimina espacios al principio y al final; acepta hasta 128 caracteres y rechaza una cadena vacía con `422`. En `POST`, el origen llena un contacto encontrado solo si su origen estaba vacío; enviar `null` no lo cambia. `PATCH /contacts/{id}` con `{"source":"Feria"}` reemplaza el origen y con `{"source":null}` lo borra. Las respuestas de contacto incluyen `source`. Acepta cualquier otro texto, incluidas las opciones de origen del panel como `website`, `referral` o `meta_ads`. Solo estos valores de sistema, sin distinguir mayúsculas, devuelven `422 invalid_source`: `capture`, `personal_whatsapp_import`, `tokko_import`, `shopify` y cualquiera que empiece con `connected:`. Si el origen guardado es uno de esos valores de sistema, `PATCH` con `source` devuelve `422 invalid_source` y `POST` no lo cambia. Un mensaje entrante de WhatsApp conserva un origen ya registrado.

## Endpoints y prueba

Todos empiezan por `/api/v1/public/crm`. Usa `GET /contacts`, `GET /contacts/{id}`, `POST /contacts`, `PATCH /contacts/{id}`, sus equivalentes `/opportunities`, y `GET /fields`, `GET /owners`, `GET /pipelines`. Las listas aceptan `updated_since` en ISO 8601, `limit` de 1 a 100 y un `cursor` opaco de la respuesta anterior. Las oportunidades también aceptan `pipeline_id` y `stage_id`. Para `POST /opportunities`, envía `Idempotency-Key: <identificador-unico>` y reutiliza el mismo valor en cada reintento; Eva respeta un reintento de la misma solicitud durante 30 días. `POST /contacts` necesita correo o teléfono: si alguno ya pertenece a un contacto, Eva actualiza ese contacto en lugar de crear otro.

Busca por nombre, correo, teléfono o campos de contacto marcados para búsqueda; en oportunidades, por título o contacto vinculado. `q` se recorta y debe tener entre 2 y 100 caracteres; `type` es `contact` u `opportunity`; `limit` va de 1 a 25. La respuesta contiene `type` y `data` con los mismos campos que las lecturas de contactos u oportunidades:

```bash theme={null}
curl 'https://api.goeva.ai/api/v1/public/crm/search?q=Ana&type=contact&limit=10' \
  -H 'Authorization: Bearer eva_sk_TU_LLAVE' \
  -H 'User-Agent: MiCRM/1.0 contacto@miempresa.com'

curl 'https://api.goeva.ai/api/v1/public/crm/search?q=Venta&type=opportunity&limit=10' \
  -H 'Authorization: Bearer eva_sk_TU_LLAVE' \
  -H 'User-Agent: MiCRM/1.0 contacto@miempresa.com'
```

Para leer notas de una oportunidad, usa `GET /opportunities/{id}/notes?limit=50` y pasa `next_cursor` como `cursor` para la página siguiente. Llegan de la más reciente a la más antigua. `author.kind` identifica `api_key`, `member` o `system`; `author.name` muestra el nombre de la llave o del miembro.

```bash theme={null}
curl 'https://api.goeva.ai/api/v1/public/crm/opportunities/22222222-2222-4222-8222-222222222222/notes?limit=50' \
  -H 'Authorization: Bearer eva_sk_TU_LLAVE' \
  -H 'User-Agent: MiCRM/1.0 contacto@miempresa.com'

curl -X POST 'https://api.goeva.ai/api/v1/public/crm/opportunities/22222222-2222-4222-8222-222222222222/notes' \
  -H 'Authorization: Bearer eva_sk_TU_LLAVE' \
  -H 'User-Agent: MiCRM/1.0 contacto@miempresa.com' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: nota-crm-123' \
  -d '{"text":"Llamar el martes"}'
```

La nota requiere texto no vacío (hasta 10,000 caracteres) y no admite adjuntos. Reutiliza la misma clave de idempotencia al reintentar: durante 30 días Eva devuelve la misma nota con `replayed: true`; una solicitud distinta con esa clave devuelve `409`.

Prueba primero `GET /owners`: `200` confirma que la llave funciona y muestra los miembros activos; `401` indica una llave ausente, inválida o revocada; `403` indica que faltan permisos para la operación.

## Avisos de cambios

Configura **Webhook personalizado** en Integraciones con la URL HTTPS de tu sistema y un secreto de firma. Sus envíos incluyen `X-Eva-Event-Id` y, cuando hay secreto de firma, `X-Eva-Timestamp` y `X-Eva-Signature-256`. Verifica la firma antes de procesar el cuerpo y deduplica por ID de evento. Los eventos de cada registro llevan un `revision` creciente y pueden llegar en otro orden: conserva el de `revision` más alto por registro. Los cambios hechos por la API llegan con `source: "api"`. El webhook es una conexión separada de la llave API; revocar la llave no desconecta el webhook.

## Citas de Eva en tu CRM

`GET /appointments` devuelve las citas vinculadas a un contacto u oportunidad y `GET /appointments/{id}` devuelve una cita. Cada registro incluye su ID de Eva, `eva_contact_id` y `eva_opportunity_id` (cualquiera puede ser `null`, pero al menos uno es válido), inicio y fin en UTC, zona horaria, ubicación, responsable, `status` (`active` o `cancelled`) y `updated_at`; no incluye título ni notas. Por ejemplo, una cita vinculada solo a un contacto lleva `"eva_contact_id": "44444444-4444-4444-8444-444444444444", "eva_opportunity_id": null`. Una cancelación sigue disponible aunque Eva haya borrado la cita. La lista usa `limit` de 1 a 100, `updated_since` con zona horaria y el `cursor` de la página anterior. Recorre todas las páginas y solapa unos minutos entre lecturas incrementales. Estas rutas son de solo lectura: tu sistema no puede cambiar las citas de Eva.

Para recibir avisos, activa **Citas → salida** en **Webhook personalizado**. Empieza desactivado y requiere un secreto de firma. `appointment.upserted` lleva el mismo objeto que `GET /appointments/{id}`. `status: "cancelled"` indica que debes marcar la cita como cancelada en tu CRM. Verifica la firma HMAC-SHA256 sobre los bytes exactos de `<X-Eva-Timestamp>.<cuerpo>`, deduplica por `X-Eva-Event-Id` y aplica solo la revisión más alta de cada cita. Si pierdes un aviso, recupera con la lista paginada; al activar el webhook no se reenvían citas históricas.

## Revocar y errores

En **API de Eva**, selecciona **Revocar** junto a la llave. La siguiente llamada con ella devuelve `401`. Los registros creados permanecen. Para cambiar permisos, crea otra llave y revoca la anterior cuando tu sistema ya use la nueva.

| Código HTTP | Qué hacer |
| - | - |
| 401 | Revisa la llave y su estado. |
| 403 | Usa una llave con el permiso necesario. |
| 404 | Confirma el ID; puede pertenecer a otra cuenta. |
| 409 | Revisa la clave de idempotencia y el cuerpo del reintento. |
| 422 | Corrige el campo, dueño o etapa indicado. |
| 429 | Espera los segundos de `Retry-After`. |
| 503 | Intenta más tarde; la verificación de límite no está disponible. |

## Privacidad y límites

Cada llave solo accede a su cuenta. El secreto se guarda como hash; Eva conserva el nombre, los permisos y la fecha del último uso. El límite es 120 solicitudes por minuto por llave. Usa paginación y `updated_since` para leer cambios sin recorrer toda la cuenta en cada ciclo.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.