Saltar al contenido

Apartado 7 de 12 · Sincronizar

La receta: una sincronización de ida y vuelta que funciona hoy

Lo que hay que montar hoy: tabla de correspondencia, carga inicial, pasada periódica, reconciliación tras una caída y tres reglas que evitan bucles.

Revisado el API 1.11.9 4 min de lectura

En esta página (5)
  1. 7.1 · Lo que tu lado tiene que guardar
  2. 7.2 · Carga inicial
  3. 7.3 · El día a día
  4. 7.4 · Cuando tu servidor se cae
  5. 7.5 · Las tres reglas que evitan el 90 % de los problemas

Esto es lo que hay que montar, en orden, con lo que la API da hoy.

7.1 · Lo que tu lado tiene que guardar

Contactos y conversaciones ya pueden guardar tu id en external_id (PUT /contacts §6.1, PATCH /conversations/{id} §6.6), pero el resto de colecciones todavía no lo tiene, así que te sigue haciendo falta una tabla de correspondencia:

Columna Qué es
id_tuyo El identificador en tu sistema
contacto_chatendo El id que devolvió Chatendo
telefono_e164 La clave natural que comparten los dos
visto_updated_at El updated_at que tenías la última vez
huella Hash de los campos que sincronizas, para no escribir si nada cambió

7.2 · Carga inicial

  1. Trae la cartera entera. GET /contacts?per_page=100, avanzando page hasta meta.last_page. Guarda id, phone_e164 y updated_at de cada uno.
  2. Cruza por teléfono en E.164 o por external_id si ya tienes uno común con Chatendo. Normaliza tus números antes: +34600111222, no 600 111 222.
  3. Da de alta o enlaza lo que falta con PUT /contacts (§6.1): un único upsert por phone o external_id, sin el paso previo de buscar y sin 422 PHONE_TAKEN. Repetir la llamada con el mismo cuerpo no crea un segundo contacto.
  4. Trae las conversaciones con GET /conversations?per_page=100, avanzando por meta.next_cursor hasta que venga vacío. No uses número de página aquí: esta colección va por cursor a propósito, y saltar páginas se come chats.

7.3 · El día a día

Lo que llega solo — monta el receptor de webhooks (§5) y suscríbete a los ocho eventos. Con eso te enteras al instante de conversaciones y mensajes entrantes.

Lo que hay que ir a buscar — los contactos y las conversaciones no avisan por webhook de todo lo que les pasa. Para eso pide el delta con updated_since en vez de recorrer la colección entera:

Texto
marca = visto_updated_at   # el mayor `updated_at` que procesaste la vez anterior
repite:
    página = GET /contacts?updated_since={marca}&cursor={cursor_guardado}
    para cada contacto de página.data:
        → tráetelo; su updated_at es mayor o igual que tu marca
        marca = máximo(marca, contacto.updated_at)
    cursor_guardado = página.meta.next_cursor
mientras página.meta.has_more

GET /contacts, /conversations, /conversations/{id}/messages, /tags, /conversation-tags, /contact-field-defs, /contacts/{id}/notes y /appointments aceptan los mismos tres parámetros (updated_since, order=updated_at|created_at, dir=asc|desc) y devuelven updated_at en cada fila, también las notas, los campos propios y las citas. updated_since es mayor o igual: la última fila que ya viste puede repetirse una vez, nunca se pierde. Los cambios aparecen con 5 a 6 s de retraso: el delta solo sirve filas con updated_at de hace más de 5 s (meta.settle_seconds; la columna guarda segundos enteros), igual que el diario de eventos. Así un cambio sellado antes pero confirmado después que otro nunca queda por detrás de la marca que reenvías. El techo vale en todo el modo delta, también con order=created_at o solo con dir: una fila que cambió hace menos de 5 s no sale en esa página, aunque sea antigua. Sin updated_since, order ni dir, cada colección responde offset/lista completa igual que antes — es aditivo.

Qué mueve el updated_at de un contacto (y por tanto lo saca en su delta): poner o quitar una etiqueta —uno a uno, en bloque o por la puerta upsert-v1, y también borrar o renombrar la etiqueta que lleva—, poner o borrar un valor de campo propio, y crear, editar o borrar una de sus notas. Mandar el mismo valor de un campo, o borrar uno que no estaba, no lo mueve.

Qué mueve el updated_at de una conversación: PATCH /conversations/{id} (§6.6) y poner o quitar una etiqueta de conversación, sola (POST/DELETE /conversations/{id}/tags/{tagId}) o en bloque (POST /conversations/bulk-action con action=tag), y borrar la etiqueta. Un cambio de estado de entrega o lectura mueve el mensaje, no la conversación: para seguirlos, relee el delta de mensajes de los chats que vigilas.

Lo que escribes tú — antes de mandar un PATCH, compara tu huella con la anterior. Si no cambió nada, no escribas: cada escritura innecesaria es un updated_at nuevo que hará que la pasada de vuelta crea que hubo un cambio. Es la forma más común de montarse un bucle entre dos sistemas.

7.4 · Cuando tu servidor se cae

  1. Al levantar, mira GET /webhook-endpoints/{id}/deliveries para saber qué se intentó mientras no estabas.
  2. Lo que quedó en failed no se puede reenviar hoy: reconcilia leyendo. Recorre GET /conversations ordenado por actividad y trae los mensajes de las que se movieron desde el corte.
  3. Apunta hasta dónde llegaste. El cursor de conversaciones es estable: guárdalo.

7.5 · Las tres reglas que evitan el 90 % de los problemas

  1. Un sentido manda en cada campo. Decide quién es el dueño del nombre del contacto: tu sistema o Chatendo. Si mandan los dos, se pisarán el uno al otro para siempre.
  2. El teléfono en E.164, siempre, en los dos lados. Es la clave que los une.
  3. Todo lo que escribas, regístralo con su respuesta. El día que algo salga duplicado, lo que te dirá qué pasó es tu propio registro, no el de Chatendo.
Escríbenos por WhatsApp Te contesta nuestro agente de IA al momento