Sync contacts from your CRM
هذا المحتوى غير متوفر بلغتك بعد.
Two directions, and most integrations need both.
Pulling changes into your system
Section titled “Pulling changes into your system”updated_since returns only what changed. This is what makes an incremental
sync possible.
async function syncFromKMessage(lastRunAt) { let cursor = null let newHighWater = lastRunAt
do { const url = new URL('https://k-message.kerneltics.com/v1/contacts') url.searchParams.set('updated_since', lastRunAt) url.searchParams.set('limit', '200') if (cursor) url.searchParams.set('cursor', cursor)
const res = await fetch(url, { headers: { Authorization: `Bearer ${KEY}` } }) const page = await res.json()
for (const contact of page.data) { await upsertInCrm(contact) if (contact.updated_at > newHighWater) newHighWater = contact.updated_at }
cursor = page.has_more ? page.next_cursor : null } while (cursor)
return newHighWater}Two details worth copying:
Track the high-water mark from the data, not the clock. Using
new Date().toISOString() as the next updated_since will skip any contact
modified while the sync was running.
Overlap slightly. Start the next run a minute before the last high-water mark. Re-processing a handful of contacts costs nothing; missing one because two writes landed in the same second is a silent bug you find months later.
Pushing changes into K-Message
Section titled “Pushing changes into K-Message”There is no bulk import endpoint, so write contacts one at a time and let the duplicate response tell you when one already exists:
async function pushToKMessage(customer) { const res = await fetch('https://k-message.kerneltics.com/v1/contacts', { method: 'POST', headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ phone_number: customer.phone, name: customer.name, tags: customer.segments, // Your own key, so later syncs are a lookup rather than a guess. metadata: { crm_id: customer.id }, }), })
if (res.status === 409) { // Already there. Find it and update instead. const existing = await findByPhone(customer.phone) return updateContact(existing.id, customer) }
return res.json()}A 409 is not an error to log and move past: it is the API telling you this
customer already exists, with the id in the message. Nothing is merged
automatically, because a sync creating the same customer twice has a bug worth
seeing rather than hiding.
Staying in step
Section titled “Staying in step”Poll only for the initial import. Afterwards, subscribe to contact.created
and contact.updated and let changes arrive.
case 'contact.created':case 'contact.updated': await upsertInCrm({ phone: data.contact_phone, name: data.contact_name, tags: data.tags, }) breakSubscribe to both. A sync that heard only about creations drifts out of date on the first edit, and nothing about that failure is visible until someone notices a stale name.
Metadata
Section titled “Metadata”metadata is free-form JSON. Put your own primary key there:
{ "metadata": { "crm_id": "C-4471", "source": "shopify", "lifetime_value": 4200 } }Matching on a phone number works until someone stores it differently, at which point a whole segment quietly stops matching. Matching on your own id does not have that failure mode.