Exportación incremental de la API de Zendesk: Una guía completa para desarrolladores

Stevia Putri
Written by

Stevia Putri

Reviewed by

Stanley Nicholas

Last edited 2 marzo 2026

Expert Verified

Imagen del banner para la exportación incremental de la API de Zendesk: Una guía completa para desarrolladores

Mantener sus sistemas externos sincronizados con los datos de Zendesk puede parecer una tarea interminable. Ya sea que esté construyendo un almacén de datos, ejecutando análisis o sincronizando información de tickets con su CRM, necesita una forma confiable de obtener solo lo que ha cambiado desde su última actualización. La exportación incremental de la API de Zendesk está diseñada exactamente para este propósito.

A diferencia de los puntos finales (endpoints) de la API estándar diseñados para consultas en tiempo real, las exportaciones incrementales están diseñadas específicamente para la sincronización masiva de datos. Le permiten obtener registros que se crearon o actualizaron desde un punto específico en el tiempo, lo que los hace ideales para canalizaciones (pipelines) ETL y sincronizaciones de datos regulares.

En esta guía, aprenderá a utilizar la API de exportación incremental de Zendesk de forma eficaz. Cubriremos los dos enfoques de paginación (basado en cursor y basado en tiempo), repasaremos una implementación completa en Python y compartiremos las mejores prácticas para las canalizaciones de datos de producción. Si está buscando una manera de obtener análisis de Zendesk sin construir una infraestructura personalizada, eesel AI ofrece integraciones de Zendesk nativas que manejan la sincronización de datos automáticamente.

¿Qué es la API de exportación incremental de Zendesk?

La API de exportación incremental es un conjunto de puntos finales diseñados para la exportación masiva de datos en lugar de la búsqueda de registros individuales. Si bien la API estándar de Tickets es excelente para obtener un ticket específico o buscar con filtros, no está optimizada para sincronizar grandes conjuntos de datos de manera eficiente.

Así es como funcionan las exportaciones incrementales: usted proporciona una hora de inicio (como una marca de tiempo de la época de Unix), y la API devuelve todos los registros creados o actualizados desde ese momento. En su próxima sincronización, utiliza la hora de finalización o el cursor de la respuesta anterior como su nuevo punto de inicio. Esto crea un bucle de sincronización eficiente donde solo obtiene los datos modificados.

La API admite dos métodos de paginación:

  • La paginación basada en cursor utiliza un puntero de cursor opaco para rastrear la posición. Es más consistente, elimina duplicados y es el enfoque recomendado cuando está disponible.
  • La paginación basada en tiempo utiliza marcas de tiempo de inicio y fin. Es compatible con todos los puntos finales incrementales, pero puede devolver registros duplicados cuando varios elementos comparten la misma marca de tiempo.

Puede exportar incrementalmente tickets, usuarios, organizaciones, eventos de tickets, datos de llamadas de Talk, conversaciones de Chat, artículos del Centro de ayuda y registros de objetos personalizados. Para los equipos que construyen análisis integrales, nuestra guía sobre la API de tickets de Zendesk cubre puntos finales adicionales que complementan las exportaciones incrementales.

Cuándo utilizar exportaciones incrementales frente a la API de búsqueda

Una pregunta común es si utilizar exportaciones incrementales o la API de búsqueda para obtener datos de tickets. La diferencia clave es el propósito: las exportaciones incrementales están diseñadas para la sincronización de datos, mientras que la búsqueda está diseñada para la consulta.

Utilice exportaciones incrementales cuando:

  • Esté sincronizando datos con un almacén de datos o un sistema externo
  • Necesite procesar cada cambio de ticket de forma fiable
  • Esté construyendo canalizaciones de análisis o informes
  • Desee minimizar las llamadas a la API obteniendo solo los cambios

Utilice la API de búsqueda cuando:

  • Necesite encontrar tickets específicos que coincidan con criterios complejos
  • Esté construyendo una interfaz de búsqueda para agentes
  • Necesite resultados en tiempo real con filtrado avanzado

Paginación basada en cursor frente a basada en tiempo: ¿Cuál debe utilizar?

Zendesk ofrece ambos métodos de paginación, pero el basado en cursor es el claro ganador cuando está disponible. Así es como difieren.

Paginación basada en cursor (recomendada)

Las exportaciones basadas en cursor utilizan un puntero opaco (el cursor) para rastrear su posición en el conjunto de datos. Después de su solicitud inicial con un start_time, las solicitudes posteriores utilizan el parámetro cursor.

Flujo de trabajo de paginación basado en cursor para exportaciones de datos de Zendesk
Flujo de trabajo de paginación basado en cursor para exportaciones de datos de Zendesk

Beneficios clave:

  • Sin registros duplicados, incluso cuando los elementos comparten marcas de tiempo
  • Tiempos de respuesta y tamaños de carga útil más consistentes
  • Mejor rendimiento para grandes conjuntos de datos
  • Límites de velocidad más altos (10 solicitudes por minuto para tickets, 20 para usuarios o 60 con el complemento High Volume API)

Recursos admitidos:

  • Tickets
  • Usuarios
  • Registros de objetos personalizados

Cómo funciona:

  1. Realice la solicitud inicial con el parámetro start_time
  2. Extraiga after_cursor de la respuesta
  3. Utilice el parámetro cursor para la siguiente solicitud
  4. Repita hasta que end_of_stream sea verdadero

Paginación basada en tiempo

Las exportaciones basadas en tiempo utilizan marcas de tiempo de la época de Unix para definir su ventana de consulta. Cada respuesta incluye un end_time que utiliza como start_time para su próxima solicitud.

Limitaciones:

  • Puede devolver registros duplicados cuando varios elementos comparten la misma marca de tiempo
  • Rendimiento menos consistente
  • Límites de velocidad más bajos (10 solicitudes por minuto)

Cuándo utilizarlo:

  • Cuando el basado en cursor no está disponible (eventos de tickets, organizaciones, datos de Talk)
  • Para scripts simples donde el manejo de duplicados no es crítico

Matriz de decisión

FactorBasado en cursorBasado en tiempo
Manejo de duplicadosNinguno (único garantizado)Debe eliminar duplicados manualmente
RendimientoConsistenteVariable
Límite de velocidad10-20/min (60 con complemento)10/min
Disponible paraTickets, usuarios, objetos personalizadosTodos los recursos

Utilice el basado en cursor siempre que sea posible. La única vez que debe utilizar el basado en tiempo es cuando el basado en cursor no está disponible para su tipo de recurso.

Primeros pasos: Autenticación y requisitos previos

Antes de empezar a codificar, necesitará algunas cosas configuradas.

Requerido:

  • Una cuenta de Zendesk con privilegios de administrador
  • Un token de API (genere uno en Centro de administración > Aplicaciones e integraciones > API > API de Zendesk)
  • Python 3.7+ instalado

Paquetes de Python:

pip install requests python-dotenv

Configuración del entorno: Cree un archivo .env para almacenar sus credenciales de forma segura:

ZENDESK_SUBDOMAIN=su-subdominio
ZENDESK_EMAIL=su-correo-electronico@empresa.com
ZENDESK_API_TOKEN=su-token-de-api

La API de exportación incremental utiliza la autenticación básica. Pasará su dirección de correo electrónico combinada con /token como nombre de usuario, y su token de API como contraseña.

Paso a paso: Exportación de tickets con paginación basada en cursor

Repasemos una implementación completa para exportar tickets utilizando la paginación basada en cursor. Este patrón maneja la paginación, la limitación de velocidad y la recuperación de errores.

El código

import os
import time
import requests
from requests.auth import HTTPBasicAuth
from dotenv import load_dotenv

load_dotenv()

class ZendeskIncrementalExport:
    def __init__(self):
        self.subdomain = os.getenv('ZENDESK_SUBDOMAIN')
        self.email = os.getenv('ZENDESK_EMAIL')
        self.api_token = os.getenv('ZENDESK_API_TOKEN')
        self.base_url = f"https://{self.subdomain}.zendesk.com/api/v2"
        self.auth = HTTPBasicAuth(f"{self.email}/token", self.api_token)

    def export_tickets(self, start_time=None, cursor=None):
        """
        Export tickets using cursor-based pagination.

        Args:
            start_time: Unix timestamp for initial export (required for first call)
            cursor: Cursor from previous response (for subsequent calls)
        """
        url = f"{self.base_url}/incremental/tickets/cursor.json"
        params = {}

        if cursor:
            params['cursor'] = cursor
        elif start_time:
            params['start_time'] = start_time
        else:
            raise ValueError("Either start_time or cursor must be provided")

        try:
            response = requests.get(url, auth=self.auth, params=params, timeout=30)

            if response.status_code == 429:
                # Rate limited - implement exponential backoff
                retry_after = int(response.headers.get('Retry-After', 60))
                print(f"Rate limited. Waiting {retry_after} seconds...")
                time.sleep(retry_after)
                return self.export_tickets(start_time, cursor)

            response.raise_for_status()
            return response.json()

        except requests.exceptions.RequestException as e:
            print(f"Request failed: {e}")
            raise

    def full_export(self, start_time):
        """
        Perform a complete export, handling pagination automatically.
        """
        all_tickets = []
        cursor = None
        page_count = 0

        while True:
            data = self.export_tickets(
                start_time=start_time if cursor is None else None,
                cursor=cursor
            )

            tickets = data.get('tickets', [])
            all_tickets.extend(tickets)
            page_count += 1

            print(f"Fetched page {page_count}: {len(tickets)} tickets")

            # Check if we've reached the end
            if data.get('end_of_stream'):
                print(f"Export complete. Total tickets: {len(all_tickets)}")
                return {
                    'tickets': all_tickets,
                    'final_cursor': data.get('after_cursor'),
                    'pages': page_count
                }

            cursor = data.get('after_cursor')

            # Respect rate limits - sleep between requests
            time.sleep(3)  # 20 requests/min = 1 request per 3 seconds

if __name__ == "__main__":
    exporter = ZendeskIncrementalExport()

    # Start from 24 hours ago
    import datetime
    start_time = int((datetime.datetime.now() - datetime.timedelta(days=1)).timestamp())

    result = exporter.full_export(start_time)

    # Save the final cursor for next sync
    print(f"Save this cursor for next run: {result['final_cursor']}")

Detalles clave de la implementación

La ventana de exclusión de 1 minuto: La API excluye los datos del minuto más reciente para evitar condiciones de carrera. Su end_time nunca será más reciente que hace un minuto. Planifique su programa de sincronización en consecuencia.

Manejo del límite de velocidad: El código implementa una retirada exponencial cuando se recibe una respuesta 429. El encabezado Retry-After le indica exactamente cuánto tiempo debe esperar.

Persistencia del cursor: Guarde siempre el cursor final de forma atómica con sus escrituras de datos. Si su script falla después de escribir datos pero antes de guardar el cursor, procesará registros duplicados en la siguiente ejecución.

Exclusión de tickets eliminados: Agregue exclude_deleted=true a los parámetros de su solicitud si no desea tickets eliminados en su exportación. Los tickets eliminados se conservan durante 90 días después de la eliminación permanente, por lo que aparecerán en las exportaciones a menos que se excluyan.

Trabajar con otros puntos finales de exportación incremental

Los mismos patrones se aplican a otros recursos de Zendesk, aunque las URL de los puntos finales y los métodos de paginación disponibles varían.

Usuarios y organizaciones

Estos siguen el mismo patrón que los tickets:

url = f"{base_url}/incremental/users/cursor.json"

url = f"{base_url}/incremental/organizations.json"

Eventos de tickets

Los eventos de tickets son solo basados en tiempo e incluyen un registro de cada cambio realizado en los tickets:

url = f"{base_url}/incremental/ticket_events.json"

params = {'start_time': start_time, 'include': 'comment_events'}

La carga lateral comment_events es particularmente útil si necesita el texto real del comentario, no solo los metadatos sobre los cambios.

Datos de llamadas de Talk

Exporte registros de llamadas y tramos de llamadas para análisis de voz:

url = f"{base_url}/channels/voice/stats/incremental/calls.json"

url = f"{base_url}/channels/voice/stats/incremental/legs.json"

Límite de velocidad: 10 solicitudes por minuto para los puntos finales de Talk.

Datos de chat

Las exportaciones de chat utilizan microsegundos en lugar de segundos para las marcas de tiempo:

url = f"{base_url}/chat/incremental/chats.json"

start_time_micro = start_time * 1000000
url = f"{base_url}/chat/incremental/agent_timeline.json?start_time={start_time_micro}"

Nota: La API de chat requiere que la hora de inicio sea al menos 5 minutos en el pasado.

Artículos del Centro de ayuda

Exporte los cambios de metadatos de los artículos:

url = f"{base_url}/help_center/incremental/articles.json"

Devuelve hasta 1000 artículos por página. La URL next_page contiene una nueva hora de inicio basada en la marca de tiempo de la última actualización del artículo.

Manejo de límites de velocidad y errores

Las canalizaciones de datos de producción necesitan un manejo de errores robusto. Esto es lo que debe vigilar.

Encabezados de límite de velocidad

Los puntos finales basados en cursor devuelven información detallada sobre el límite de velocidad:

Zendesk-RateLimit-incremental-exports-cursor: total=20; remaining=15; resets=45

Analice estos encabezados para limitar proactivamente sus solicitudes en lugar de esperar respuestas 429.

Estrategia de retirada exponencial

Cuando alcance un límite de velocidad, utilice una retirada exponencial con fluctuación:

import random

def backoff_with_jitter(attempt, base_delay=3):
    """Calculate delay with exponential backoff and jitter."""
    delay = min(base_delay * (2 ** attempt), 60)  # Cap at 60 seconds
    jitter = random.uniform(0, delay * 0.1)  # Add 0-10% jitter
    return delay + jitter

for attempt in range(5):
    try:
        response = requests.get(url, auth=auth)
        if response.status_code == 429:
            delay = backoff_with_jitter(attempt)
            time.sleep(delay)
            continue
        response.raise_for_status()
        break
    except requests.exceptions.RequestException:
        if attempt == 4:  # Last attempt
            raise
        delay = backoff_with_jitter(attempt)
        time.sleep(delay)

Errores comunes y soluciones

ErrorCausaSolución
401 No autorizadoCredenciales no válidasCompruebe el formato del correo electrónico (debe incluir /token) y el token de API
403 ProhibidoPermisos insuficientesAsegúrese de que la cuenta tenga acceso de administrador
422 No procesablestart_time no válidoVerifique que la marca de tiempo tenga al menos 60 segundos en el pasado
429 Demasiadas solicitudesLímite de velocidad excedidoImplemente la retirada y respete el encabezado Retry-After
500/502/503Error del servidor de ZendeskVuelva a intentar con una retirada exponencial

Pruebas con exportaciones de muestra

Zendesk proporciona un punto final de exportación de muestra con límites más estrictos (10 solicitudes por cada 20 minutos) pero respuestas más pequeñas. Utilice esto para el desarrollo y las pruebas:

url = f"{base_url}/incremental/tickets/sample.json?start_time={start_time}"

Construcción de una canalización de datos de producción

Para el uso en producción, querrá una arquitectura más robusta que un simple script.

Arquitectura recomendada

Arquitectura de canalización de datos de producción desde Zendesk hasta el almacén de datos
Arquitectura de canalización de datos de producción desde Zendesk hasta el almacén de datos

Trabajo programado (Airflow/Lambda/Cron)
    ↓
API de exportación incremental
    ↓
Validación y transformación de datos
    ↓
Almacén de datos (Snowflake/BigQuery/Redshift)
    ↓
Panel de análisis

Almacenamiento del estado del cursor

Nunca confíe en archivos locales para el almacenamiento del cursor en producción. Utilice un almacenamiento persistente:

import psycopg2

def save_cursor(cursor, last_sync_time):
    conn = psycopg2.connect(database_url)
    cur = conn.cursor()
    cur.execute("""
        INSERT INTO zendesk_sync_state (cursor, last_sync_time, updated_at)
        VALUES (%s, %s, NOW())
        ON CONFLICT (id) DO UPDATE SET
            cursor = EXCLUDED.cursor,
            last_sync_time = EXCLUDED.last_sync_time,
            updated_at = EXCLUDED.updated_at
    """, (cursor, last_sync_time))
    conn.commit()

Eliminación de duplicados para exportaciones basadas en tiempo

Si está utilizando la paginación basada en tiempo, implemente la eliminación de duplicados:

def deduplicate_records(records, key_fields):
    """
    Remove duplicates based on composite key.
    For tickets: (id, updated_at)
    For ticket events: (id, created_at)
    """
    seen = set()
    unique = []

    for record in records:
        key = tuple(record.get(f) for f in key_fields)
        if key not in seen:
            seen.add(key)
            unique.append(record)

    return unique

tickets = deduplicate_records(tickets, ['id', 'updated_at'])

Monitoreo y alertas

Realice un seguimiento de estas métricas en su canalización:

  • Duración de la sincronización y recuentos de registros
  • Impactos en el límite de velocidad y recuentos de reintentos
  • Solicitudes fallidas y tasas de error
  • Actualidad de los datos (tiempo desde la última sincronización exitosa)

Configure alertas para:

  • Fallas de sincronización o reintentos excesivos
  • Recuentos de registros inusualmente bajos (posibles problemas de la API)
  • Actualidad de los datos que exceda su SLA

Alternativa: Soluciones gestionadas

Construir y mantener una canalización de datos requiere recursos de ingeniería. Si su equipo necesita análisis de Zendesk sin la sobrecarga de la infraestructura, el Agente de IA de eesel AI proporciona análisis, informes e información automatizados de tickets directamente desde sus datos de Zendesk, sin necesidad de una canalización personalizada.

Panel de control de eesel AI para configurar el agente de IA
Panel de control de eesel AI para configurar el agente de IA

Limitaciones y mejores prácticas clave

Antes de implementar en producción, tenga en cuenta estos puntos.

Mejores prácticas

  • Utilice siempre la paginación basada en cursor cuando esté disponible. Los beneficios de rendimiento y consistencia valen la pena.
  • Almacene los cursores de forma atómica con las escrituras de datos. Utilice una transacción para asegurarse de que el cursor y los datos estén siempre sincronizados.
  • Maneje la ventana de exclusión de 1 minuto. No espere datos más recientes que hace un minuto.
  • Implemente escrituras idempotentes. Diseñe su sistema de destino para manejar los registros duplicados con elegancia.
  • Supervise los encabezados de límite de velocidad. La limitación proactiva supera a la retirada reactiva.

Limitaciones que debe conocer

  • Retención de tickets eliminados: Los tickets eliminados permanecen en las exportaciones durante aproximadamente 120 días en total (30 días hasta la eliminación permanente, luego 90 días después de la limpieza).
  • Tickets archivados: Los tickets archivados por Zendesk no se incluyen en las exportaciones incrementales.
  • Datos limpiados: Después de 30 días, los tickets eliminados tienen su contenido limpiado (reemplazado con "SCRUBBED" o "X").
  • Sin garantías en tiempo real: La API está diseñada para sincronizaciones por lotes, no para transmisión en tiempo real.

Empiece a sincronizar sus datos de Zendesk de forma eficiente

La exportación incremental de la API de Zendesk le brinda una forma confiable de mantener los sistemas externos sincronizados con sus datos de soporte. Al utilizar la paginación basada en cursor, manejar los límites de velocidad con elegancia y almacenar el estado correctamente, puede construir canalizaciones de datos robustas que se escalen con su volumen de tickets.

Puntos clave:

  • Utilice la paginación basada en cursor para tickets y usuarios cuando sea posible
  • Implemente la retirada exponencial para el manejo del límite de velocidad
  • Almacene los cursores de forma atómica con sus escrituras de datos
  • Tenga en cuenta la ventana de exclusión de datos de 1 minuto en su programa de sincronización

Construir una canalización personalizada tiene sentido cuando tiene necesidades específicas de transformación de datos o se está integrando con sistemas propietarios. Pero si está buscando principalmente análisis, informes e información impulsada por IA de sus datos de Zendesk, considere si una solución gestionada como eesel AI podría ahorrarle a su equipo meses de esfuerzo de ingeniería. Nuestra integración de Zendesk maneja la sincronización de datos automáticamente, brindándole acceso inmediato a los análisis de tickets sin escribir una sola línea de código de API.

Panel de control de informes de eesel AI que muestra el análisis de la brecha de conocimiento
Panel de control de informes de eesel AI que muestra el análisis de la brecha de conocimiento

Preguntas frecuentes

Utilice la paginación basada en cursor siempre que esté disponible (tickets, usuarios, objetos personalizados). Elimina duplicados y ofrece un mejor rendimiento. Utilice únicamente la paginación basada en tiempo para los recursos que no admiten la basada en cursor, como los eventos de tickets o las organizaciones.
Los puntos finales basados en cursor permiten 10 solicitudes por minuto para los tickets y 20 para los usuarios (60 con el complemento High Volume API). Los puntos finales basados en tiempo están limitados a 10 solicitudes por minuto. Compruebe siempre el encabezado Zendesk-RateLimit-incremental-exports-cursor para conocer su cuota actual.
Los tickets eliminados permanecen en las exportaciones durante aproximadamente 120 días en total (30 días hasta la eliminación permanente, luego 90 días después). Puede excluirlos utilizando el parámetro exclude_deleted=true, o filtrarlos comprobando el estado: eliminado en su lógica de procesamiento.
La API excluye los datos del minuto más reciente para evitar condiciones de carrera. Su end_time nunca será más reciente que hace un minuto. Si necesita datos en tiempo real, considere la posibilidad de utilizar webhooks en lugar de exportaciones incrementales.
Los eventos de tickets incluyen metadatos de comentarios de forma predeterminada. Para obtener el texto completo de los comentarios, utilice el parámetro include=comment_events en el punto final de los eventos de tickets. Para una exportación completa de comentarios, es posible que deba utilizar la API de comentarios de tickets por separado.
Almacene el cursor de forma atómica con sus escrituras de datos utilizando una transacción de base de datos. Esto garantiza que si su sincronización se interrumpe, no perderá registros ni procesará duplicados en la siguiente ejecución. Nunca almacene cursores en archivos locales para sistemas de producción.

Compartir esta entrada

Stevia undefined

Article by

Stevia Putri

Stevia Putri is a marketing generalist at eesel AI, where she helps turn powerful AI tools into stories that resonate. She’s driven by curiosity, clarity, and the human side of technology.