# Custom API (/es/docs/integrations/custom-api)

Conecta tu portal de clientes, sistema de comentarios u otra herramienta a Sift.
Custom API importa conversaciones privadas e inicia el análisis de Sift.
Las conversaciones importadas usan los estados normales de las acciones.
Los moderadores pueden asignárselas, etiquetarlas y cambiar su estado.
Sift no puede enviar respuestas a estas conversaciones.

## De un vistazo [#de-un-vistazo]

| | |
| --- | --- |
| Importar contenido de clientes | ✅ Elementos individuales o lotes |
| Datos del autor, canales y etiquetas | ✅ |
| Campos registrados de elementos y autores | ✅ Asigna los campos antes de importar |
| IDs estables y reintentos exactos | ✅ |
| Análisis y seguimiento de recibos | ✅ |
| Acceso de la clave Import | Solo fuentes seleccionadas |
| Tamaño del lote | Hasta 100 elementos y 1 MiB |
| Respuestas salientes o archivos adjuntos | ❌ Solo contenido de texto |

## Qué estás viendo [#qué-estás-viendo]

Abre **Settings → Connections → Integrations → Custom API**. Cada fuente representa un sistema externo. Sus tres pestañas guían la configuración:

| Pestaña | Uso |
| --- | --- |
| Setup | Abre las claves API, configura la fuente, los canales y las etiquetas. Copia el endpoint y prueba un elemento. |
| Fields | Asigna nombres de campos del productor a campos registrados de elementos o autores. Los campos que escribe un agente por lotes no se ofrecen. |
| Activity | Consulta recibos, comprueba el análisis y abre conversaciones almacenadas. |

El flujo es: **Fuente → Clave Import → Validar → Importar → Recibo → Análisis de Sift**.

## Configurarlo [#configurarlo]

{/* screenshot */}
<figure>
  <img src="/assets/screenshots/custom-api/source-setup.png" alt="Formulario Connect a source con nombre de fuente y nombre opcional del canal predeterminado." width="600" />
  <figcaption>Asigna un nombre a la fuente. El nombre del canal predeterminado es opcional.</figcaption>
</figure>

1. Selecciona **Add source**. Introduce el nombre de la fuente. El nombre del canal predeterminado es opcional y usa el nombre de la fuente de forma predeterminada.
2. En **Setup**, añade canales o etiquetas de fuente si los necesitas. Conserva el canal con ID externo `default`.
3. En **Fields**, asigna los campos personalizados antes de enviarlos.
4. En **API keys**, crea una clave **Import**. El valor predeterminado selecciona esta fuente y una caducidad de 90 días.
5. Copia el secreto una vez. Guárdalo en el almacén de secretos de tu herramienta.
6. Copia el endpoint de **Setup**.

Los administradores de la organización gestionan fuentes y claves. Usa una fuente por sistema externo. Los IDs de elementos y autores se mantienen separados entre fuentes.

## Elegir la clave correcta [#elegir-la-clave-correcta]

{/* screenshot */}
<figure>
  <img src="/assets/screenshots/custom-api/key-permissions.png" alt="Menú Permission profile con Reporting, Import, Write y Read and write." width="600" />
  <figcaption>Elige Import para enviar contenido de fuentes seleccionadas. Developer access selecciona Reporting de forma predeterminada.</figcaption>
</figure>

| Perfil | Acceso |
| --- | --- |
| Import | Validar, importar, corregir elementos, reintentar importaciones fallidas y leer recibos de fuentes seleccionadas. Alcances: `ingest`, `ingest:read`. |
| Reporting | Leer datos de informes. Sin acceso a importaciones ni recibos. Alcance: `read`. |
| Write | Escrituras generales de API. Sin importación por Custom API. Alcance: `write`. |
| Read and write | Lecturas y escrituras generales. Sin importación por Custom API. Alcances: `read`, `write`. |

Usa claves separadas para importar y consultar informes. Las opciones de caducidad son 30 días, 90 días o sin caducidad. La revocación bloquea las solicitudes nuevas.

## Enviar un elemento [#enviar-un-elemento]

Guarda este ejemplo como `item.json`. Sustituye los valores por tu contenido.

```json
{
  "externalId": "feedback-184",
  "text": "Please add CSV export for feedback.",
  "occurredAt": "2026-10-12T09:00:00Z",
  "author": {
    "externalId": "customer-73",
    "name": "Maya Chen"
  }
}
```

Asigna `https://api.getsift.ai` a `SIFT_API_BASE`, el ID de tu fuente a `SIFT_SOURCE_ID` y tu clave Import a `SIFT_IMPORT_KEY`. Después envía:

```bash
curl --fail-with-body -X POST \
  "$SIFT_API_BASE/v0/sources/$SIFT_SOURCE_ID/items" \
  -H "X-API-Key: $SIFT_IMPORT_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @item.json
```

Para staging, usa `https://api.staging.getsift.ai`. Mantén separadas las fuentes y claves de staging y producción.

Los campos obligatorios son `externalId`, `text`, `occurredAt`, `author.externalId` y `author.name`. Usa un ID estable de tu sistema. No necesitas un ID de mensaje de plataforma. Usa la fecha original en formato ISO con `Z` o un desplazamiento de zona horaria.

**Try an item** en Setup valida el JSON antes de importar. La validación por API usa `POST /v0/sources/{sourceId}/items/validate` con un array `items`. Validar no almacena contenido ni inicia el análisis.

Una importación correcta devuelve HTTP `202` y un array `receipts`. Guarda el ID del recibo, el ID del elemento, la revisión y el estado. La aceptación no significa que el análisis esté completo.

## Canales, etiquetas y campos personalizados [#canales-etiquetas-y-campos-personalizados]

| Campo opcional | Uso |
| --- | --- |
| `channelExternalId` | ID de un canal configurado. Su valor predeterminado es `default`. |
| `title`, `sourceUrl` | Título opcional y enlace HTTPS al elemento original. |
| `author.username`, `author.email` | Nombre de usuario opcional y dirección de correo válida. |
| `author.avatarUrl`, `author.profileUrl` | URLs HTTPS opcionales. |
| `customFields`, `author.customFields` | Valores para campos de Sift registrados y asignados. |
| `metadata`, `author.metadata` | Contexto JSON. No crea campos de informes. |
| `tagIds` | Hasta 32 IDs de etiquetas existentes en tu organización. Usa IDs, no nombres. |

Una fuente admite hasta 50 canales. Las etiquetas de fuente y canal pueden filtrar las conversaciones importadas.

Asigna claves del productor a campos registrados en **Fields**. Por ejemplo, asigna `plan` a un campo de autor. Después envía `"customFields": {"plan": "Pro"}` dentro de `author`. Las claves sin asignación se rechazan. Las ediciones humanas y los campos verificados permanecen protegidos.

## Hilos y respuestas [#hilos-y-respuestas]

Para un elemento independiente, omite los IDs de hilo y padre. Para la raíz de un hilo, asigna su propio `externalId` a `threadExternalId`. Para una respuesta, envía el ID raíz como `threadExternalId` y el ID del padre inmediato como `parentExternalId`.

Importa las raíces primero. Una respuesta no puede ser su propio padre ni raíz. Una respuesta recibida antes de su raíz puede mostrar `waiting_for_root`.

## Consultar el procesamiento [#consultar-el-procesamiento]

Abre **Activity** o consulta recibos recientes con `GET /v0/sources/{sourceId}/receipts?limit=50`. El límite es de 1 a 100; el valor predeterminado es 50.

| Estado de importación | Significado |
| --- | --- |
| `accepted` | Se reserva un recibo duradero. |
| `processing` | La importación está en curso. |
| `waiting_for_root` | Importa la raíz del hilo correspondiente. |
| `stored` | El contenido está almacenado. Comprueba el análisis por separado. |
| `failed` | Corrige la causa y reintenta el recibo. |
| `superseded` | Una revisión nueva sustituye este trabajo pendiente. |

Los recibos almacenados muestran el análisis actual como completo, pendiente, omitido o no disponible. **Open conversation** abre la conversación importada. El análisis describe el registro actual, no una revisión concreta del recibo.

La respuesta de recibos recientes incluye `recordId`, `analysisStatus` y `url`. Consulta un recibo con `GET /v0/sources/{sourceId}/receipts/{receiptId}`. Esta respuesta individual no incluye el estado del análisis.

Sift usa su análisis existente para el contenido importado, incluidos títulos, resúmenes y sentimiento. El procesamiento tarda un tiempo. Si Search no muestra resultados, incluye la fecha original `occurredAt` en su intervalo.

## Lotes, reintentos y correcciones [#lotes-reintentos-y-correcciones]

Envía `{"items": [...]}` a `POST /v0/sources/{sourceId}/items/batch`. Usa IDs distintos. Cada elemento tiene un límite de 100 KiB. El texto admite hasta 64.000 caracteres. Los objetos de campos personalizados y metadatos permiten 64 claves y seis niveles anidados. Divide los lotes que superen 100 elementos o 1 MiB.

Si una importación agota el tiempo de espera, reenvía el mismo ID y contenido. Un reintento exacto devuelve el recibo original. El contenido distinto con el mismo ID causa un conflicto. Reintenta una importación fallida con `POST /v0/sources/{sourceId}/receipts/{receiptId}/retry`. No puedes reintentar trabajo pendiente o completado de esta forma.

Para corregir contenido, envía `PATCH /v0/sources/{sourceId}/items/{externalId}`:

```json
{
  "expectedRevision": 1,
  "requestId": "7192cdcb-c9d4-4cf4-8c37-d09d8a2ff715",
  "text": "Please add CSV export with dates."
}
```

Usa la revisión más reciente y un UUID nuevo para cada corrección. Para un reintento de red, reutiliza el UUID y el cuerpo. Puedes corregir texto, título, campos personalizados del elemento o metadatos. La identidad, fecha original, autor, canal e hilo no cambian. Los objetos de campos personalizados y metadatos sustituyen los objetos correspondientes. Incluye los valores que quieras conservar.

## Resolver problemas [#resolver-problemas]

| Problema | Acción |
| --- | --- |
| Clave no válida o caducada | Comprueba caducidad y revocación. Sustituye la clave si es necesario. |
| Falta un alcance | Usa una clave Import para importaciones y recibos. |
| Fuente no encontrada | Comprueba el ID y las fuentes permitidas de la clave. |
| Elemento no válido o canal desconocido | Comprueba campos, tipos JSON, canales y asignaciones. Valida de nuevo. |
| Conflicto | Mantén el contenido del reintento. Usa la revisión más reciente para corregir. |
| Fuente pausada o archivada | Reanuda una fuente pausada antes de importar. Las fuentes archivadas bloquean elementos nuevos. |
| Análisis pendiente o no disponible | Actualiza Activity. Si el estado persiste, contacta con tu administrador. |

Pausar bloquea importaciones y correcciones nuevas. Archivar conserva conversaciones y recibos almacenados.

## Consejos [#consejos]

- Mantén estables los IDs de elementos y autores. Codifica los IDs para usarlos en rutas URL.
- Guarda los cuerpos de las solicitudes y los IDs de recibo para reintentar con seguridad.
- No pongas claves en código del navegador, registros ni control de versiones.
- Usa la fecha original, no la fecha de envío de la solicitud.

## Relacionado [#relacionado]

<Cards>
  <Card href="/docs/developer/api-keys" title="Claves de API">Elige permisos y gestiona la caducidad.</Card>
  <Card href="/docs/developer/api" title="API">Explora la API REST de Sift.</Card>
  <Card href="/docs/integrations/custom-form" title="Custom Form">Recoge contenido de clientes con un formulario alojado.</Card>
</Cards>
