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.
En esta página (5)
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
- Trae la cartera entera.
GET /contacts?per_page=100, avanzandopagehastameta.last_page. Guardaid,phone_e164yupdated_atde cada uno. - Cruza por teléfono en E.164 o por
external_idsi ya tienes uno común con Chatendo. Normaliza tus números antes:+34600111222, no600 111 222. - Da de alta o enlaza lo que falta con
PUT /contacts(§6.1): un único upsert porphoneoexternal_id, sin el paso previo de buscar y sin422 PHONE_TAKEN. Repetir la llamada con el mismo cuerpo no crea un segundo contacto. - Trae las conversaciones con
GET /conversations?per_page=100, avanzando pormeta.next_cursorhasta 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:
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_moreGET /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
- Al levantar, mira
GET /webhook-endpoints/{id}/deliveriespara saber qué se intentó mientras no estabas. - Lo que quedó en
failedno se puede reenviar hoy: reconcilia leyendo. RecorreGET /conversationsordenado por actividad y trae los mensajes de las que se movieron desde el corte. - 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
- 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.
- El teléfono en E.164, siempre, en los dos lados. Es la clave que los une.
- 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.