Contactos, segmentos y verificación de direcciones
Un contacto es una persona a la que puedes escribir, guardada una vez por dirección. Empieza agregando uno. Esto pide una clave con operate.
import { Colding } from "colding";
const colding = new Colding("cd_your_key");
const contact = await colding.contacts.create({
email: "[email protected]",
});
console.log(contact.id, contact.email);Cambia la clave y la dirección por las tuyas. La dirección de aquí es solo un ejemplo.
6f1d2c3a-5b4e-4f70-9a8b-1c2d3e4f5a6b [email protected]
Si la dirección ya existe, con mayúsculas o minúsculas, la llamada responde 409 e indica el contacto en details.contactId. Para agregar o completar sin preocuparte por eso, usa upsert.
Agrega o actualiza varios por su dirección
contacts.upsert recibe hasta 500 contactos en una llamada. Una dirección nueva se crea. Una que ya existe se completa, o se deja como está si pasas mode: "skip".
const result = await colding.contacts.upsert({
contacts: [
{ email: "[email protected]", firstName: "Ana", company: "Example Ltd" },
{ email: "[email protected]", firstName: "Ben" },
],
});
console.log(result.created, result.updated, result.failed);created, updated y failed cuentan las filas. results trae una entrada por fila, en el orden en que las enviaste.
- Un valor en blanco nunca borra lo que ya está guardado. Para vaciar un campo, usa
contacts.update, donde el valor en blanco reemplaza al anterior. subscribed: falseregistra que la persona pidió no recibir correos. Nada de esto lo deshace, ni siquierasubscribed: true. Solo lo deshace quitar la dirección de la lista de supresión.- Una dirección incorrecta hace fallar solo su fila.
- Si los contactos nuevos superaran el límite de contactos de tu plan, no se guarda nada y la llamada responde 402.
Lee los contactos y su historial
contacts.get lee un contacto: sus campos, sus etiquetas y el último resultado de la verificación de la dirección. Un contacto de otro workspace responde 404. contacts.count acepta los mismos filtros que contacts.list (q, labelId, subscribed, check y segmentId) y responde cuántos contactos cumplen, así que úsalo antes de una acción masiva. Las dos piden read.
const subscribed = await colding.contacts.count({ subscribed: true });
console.log(subscribed.count);
const contactId = "66666666-6666-4666-8666-666666666666";
const contact = await colding.contacts.get({ contactId });
console.log(contact.email, contact.verification?.status);
const history = await colding.contacts.timeline({ contactId, limit: 20 });
for (const event of history.items) console.log(event.at, event.type);
const fields = await colding.contacts.listCustomFields();
console.log(fields.keys, fields.more);contacts.timeline responde qué pasó con un contacto, del más nuevo al más antiguo, una página a la vez. Pasa nextCursor como cursor para ir a la página siguiente. Todo evento tiene id, at y type, y los demás campos dependen del tipo. Un correo programado aparece a la hora en que saldrá, que puede estar en el futuro.
Los tipos de evento
added- Se creó el contacto.
sourcedice cómo, yimportnombra la importación mientras aún la guardamos. campaign_joined- El contacto pasó a ser lead de una campaña.
check- Terminó una de nuestras verificaciones de la dirección. Trae el
status, elreasony laaddressque se verificó. email- Un correo de campaña o directo al contacto: enviado, en espera o detenido. Uno que una persona canceló antes de que saliera no aparece.
reply- Correo que el contacto mandó a uno de tus buzones. Los correos de warmup, los informes de rebote y los de spam no son respuestas.
bounce- Un correo al contacto rebotó de forma permanente.
complaint- El contacto marcó un correo como spam.
suppressed- La dirección, o todo su dominio, entró en la lista de supresión.
unsuppressed- La dirección, o su dominio, salió de la lista de supresión.
campaign_left- Una persona o una clave sacó al lead de la campaña.
bydice quién. opened- El contacto abrió un correo por primera vez. Un evento por correo, y
openscuenta las aperturas. clicked- El contacto hizo clic en un enlace de un correo. Un evento por enlace, en su primer clic.
urles la página a la que lleva el enlace. outside_email- Correo que alguien de tu equipo escribió al contacto desde su propia aplicación de correo. Trae el asunto, el buzón y la conversación, nunca el cuerpo.
import_updated- Una importación modificó un contacto que ya estaba aquí.
importnombra la importación mientras aún la guardamos. Un contacto que la importación dejó como estaba no tiene evento.
Un correo que enviamos nosotros aparece una vez, como email. Las aperturas y los clics de un escáner de correo o de un proxy de correo nunca entran en el historial, ni tampoco el correo de warmup.
contacts.listCustomFields responde keys, los nombres de los campos personalizados que tienen tus contactos, de la A a la Z sin distinguir mayúsculas, hasta 200. more es true cuando hay más. El nombre es lo que lee un campo dinámico en una plantilla. Los campos estándar (first_name, last_name, company, phone y email) no aparecen.
Organiza los contactos con etiquetas
Una etiqueta es un nombre bajo el que guardas contactos y conversaciones de la bandeja de entrada. Los nombres son únicos, sin distinguir mayúsculas. contacts.label agrega y quita etiquetas de una selección en una sola llamada.
const label = await colding.labels.create({ name: "Met at the fair" });
const touched = await colding.contacts.label({
selection: {
ids: ["77777777-7777-4777-8777-777777777777", "88888888-8888-4888-8888-888888888888"],
},
add: [label.id],
});
console.log(touched.count);La llamada responde cuántos contactos tocó.
Una selección es una lista de hasta 1000 IDs de contactos, o todos los contactos que cumplen un filtro. En el segundo caso, pasa all: true, los filters y expectedCount, el número que comprobaste. Si ahora cumple una cantidad distinta de contactos, no cambia nada y la llamada responde 409.
Los filtros son q (palabras en la dirección, el nombre o la empresa), labelId, subscribed, check y segmentId. Eliminar, exportar y comprobar direcciones usan la misma selección.
labels.update cambia el nombre de una etiqueta y labels.remove elimina una. Las dos piden operate. Los contactos y las conversaciones se quedan con la etiqueta renombrada. Eliminar una etiqueta quita solo la etiqueta: los contactos y las conversaciones que la tenían se quedan.
const renamed = await colding.labels.update({
labelId: "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
name: "Met at the fair 2030",
});
console.log(renamed.name);
await colding.labels.remove({ labelId: "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb" });Elimina contactos
contacts.remove elimina un contacto. contacts.removeMany elimina una selección. Las dos piden operate y no se pueden deshacer.
await colding.contacts.remove({ contactId: "66666666-6666-4666-8666-666666666666" });
const filters = { check: "invalid" } as const;
const matching = await colding.contacts.count(filters);
const removed = await colding.contacts.removeMany({
selection: { all: true, filters, expectedCount: matching.count },
});
console.log(removed.count);La selección funciona como en las etiquetas: hasta 1000 IDs, o all: true con filters, exclude (IDs que se dejan fuera) y expectedCount. Ejecuta antes contacts.count y pasa su número, menos los IDs de exclude, como expectedCount. Si ahora cumple una cantidad distinta, no se elimina nada y la llamada responde 409. Una selección de más de 50.000 contactos se rechaza. La llamada responde cuántos contactos eliminó.
Un contacto eliminado sale de sus campañas, y sus verificaciones de la dirección se van con él. La lista de supresión no se toca: una dirección que pidió no recibir correos sigue en ella. Sus etiquetas siguen valiendo para los demás contactos. Un lote de verificaciones sin nada más que hacer termina.
Importa un archivo CSV o de Excel
En la consola, usa Importar en la página Contactos cuando una persona tiene el archivo. Tiene cuatro pasos: Archivo, Columnas, Revisión y Listo. Usa la API cuando un programa tiene los datos. Para hasta 500 contactos cada vez, contacts.upsert es más simple.
Para enviar un archivo entero, inicia una importación y confírmala. createImport todavía no cambia nada. Responde las columnas que encontró, los ajustes que sugiere y preview, una prueba de lo que haría la confirmación. Cambia un ajuste con contacts.updateImport, que sube la revision. commitImport indica la revisión que leíste.
const started = await colding.contacts.createImport({
fileName: "leads.csv",
csv: "email,first name\[email protected],Ana\[email protected],Ben\n",
});
console.log(started.preview?.blockers);
const done = await colding.contacts.commitImport({
importId: started.id,
revision: started.revision,
});
console.log(done.result);Una confirmación escribe todas las filas o ninguna. Repetir la misma revisión devuelve el mismo resultado, así que reintentar es seguro. Una celda que marca a alguien como No enviar correos pone su dirección en la lista de supresión. Una columna de etiquetas le da a cada contacto las etiquetas de su celda, una por línea, como las escribe la exportación. Si ya tienes una etiqueta con ese nombre, sin contar mayúsculas, el contacto la recibe; si no, se crea al confirmar. preview.newLabels muestra cuáles se crearían.
Un archivo puede tener hasta 50.000 filas y 10 MB. Las celdas de un CSV van separadas por comas, punto y coma o tabulaciones, y lo envías como texto en csv o como bytes en base64 en content. Un archivo de Excel (.xlsx, .xlsm o .xls) va solo en content. Leemos su primera hoja visible, como el texto que muestran las celdas: una fórmula da su último resultado guardado, y una fecha en el formato corto de Excel llega como año-mes-día. Un archivo protegido con contraseña, con más de 10 MB de texto en las celdas o en otro formato (Numbers, OpenDocument o Excel Binario) responde 400 y dice qué hacer: guarda la lista como .xlsx o CSV. Una importación que no confirmas se elimina, con su archivo, pasadas 24 horas. El resumen de una importación confirmada se guarda 7 días. Los contactos se quedan para siempre.
Las filas que fallan aparecen en preview, las primeras 1000. Para tenerlas todas, contacts.exportImportFailures({ importId, revision }) responde un enlace a un CSV con las filas que fallarían en esa revisión: la fila de encabezado del propio archivo, cada celda como se escribió y, en la última columna, el motivo. Corrige las filas e importa ese archivo. El enlace dura unos minutos y el archivo se escribe cuando lo abres. Cuando la importación termina, las celdas desaparecen, así que las filas que fallaron no vuelven: vuelve a subir el archivo.
Para volver a encontrar una importación, contacts.listImports lista las importaciones del workspace, de la más nueva a la más antigua, una página a la vez. Cada una trae su estado y sus conteos, nunca las celdas del archivo. Abre una con contacts.getImport.
Guarda un filtro como segmento
Un segmento es un filtro guardado con un nombre. No guarda una lista de personas: quien cumple sus condiciones en el momento en que lo usas está en él. Un contacto que agregues mañana puede entrar sin que hagas nada.
const tried = await colding.segments.count({
conditions: [{ field: "domain", op: "equals", value: "example.com" }],
});
console.log(tried.count);
const segment = await colding.segments.create({
name: "People at example.com",
conditions: [{ field: "domain", op: "equals", value: "example.com" }],
});
const page = await colding.contacts.list({ segmentId: segment.id });
console.log(page.items.map((contact) => contact.email));segments.count prueba condiciones sin guardarlas. segments.create las guarda. Un workspace guarda hasta 100 segmentos.
Pasa el ID del segmento en segmentId para listar, contar, etiquetar, eliminar, exportar o comprobar los contactos que lo cumplen. Si el segmento se eliminó después, la llamada responde 404.
Una condición tiene un field, un op (la prueba) y, en las pruebas que comparan, un value o values. Los campos incluyen search, email, domain, first_name, last_name, company, subscribed, suppressed, check, label, created_at y updated_at. Un campo custom se indica con key. match es all (todas las condiciones) o any (basta una). Un grupo, de un solo nivel, tiene condiciones propias, y cada una cuenta en el límite. Un segmento tiene hasta 20 condiciones. campaign_sent, campaign_replied, campaign_opened y campaign_clicked prueban qué pasó con un correo de campaña. campaign_opened y campaign_clicked cuentan la apertura o el clic de una persona, nunca el de un escáner o un proxy de correo. Necesitan el seguimiento de aperturas o de clics en un dominio de seguimiento verificado. Sin ninguno en uso, in y any no coinciden con nadie, y not_in y none coinciden con todo el mundo, también con quien la campaña nunca contactó. Para encontrar a quien recibió un correo y no hizo nada con él, agrega también campaign_sent.
Las pruebas que acepta cada campo están en el archivo OpenAPI. Una condición que no encaja con su campo se rechaza con 400 y la ruta de esa condición. Abrir el JSON de OpenAPI
segments.update recibe la revision que leíste. Si alguien cambió el segmento después, no se escribe nada y la llamada responde 409 con la revisión actual.
segments.list responde todos los segmentos, de la A a la Z, cada uno con sus condiciones. Es una sola página, porque un workspace guarda hasta 100. segments.remove elimina uno y pide operate. Sus contactos se quedan como están, y una llamada que aún nombra el segmento responde 404. Un segmento del que una campaña toma leads responde 409 segmentLinked, con las campañas en details: quita el vínculo con cada una antes, con campaigns.unlinkSegment.
const segments = await colding.segments.list();
const old = segments.find((segment) => segment.name === "People at example.com");
if (old) await colding.segments.remove({ segmentId: old.id });Comprueba las direcciones antes de enviar
Una verificación de la dirección dice si puede recibir correos. Comprobamos por etapas. Primero, revisamos la dirección y los servidores de correo del dominio. Después, nuestra verificación le pregunta al servidor de correo de la dirección si existe el buzón. No consulta Microsoft 365, Outlook.com, Yahoo, AOL ni iCloud, porque sus servidores no dan esa respuesta. Esas direcciones, y las que no podemos comprobar por nuestra cuenta, pasan a un servicio de verificación de pago. Iniciar una verificación pide el permiso validate, porque el servicio cobra por cada dirección que responde.
const check = await colding.emailChecks.check({
address: "[email protected]",
});
console.log(check.state, check.status, check.reason);check espera un poco la respuesta. Si el state sigue siendo queued, running o dispatched, léelo otra vez con emailChecks.get. Cuando el state es done, el status es el resultado y el reason dice el motivo.
Qué significa cada resultado
valid- La dirección puede recibir correos.
risky- No pudimos confirmarla, pero puede que funcione.
invalid- No puede recibir correos.
unknown- No pudimos concluir. Esto no es inválido.
Una verificación que no puede terminar espera, en lugar de adivinar. Si el servicio de verificación está caído o el mes se agotó, el state es on_hold y el holdReason dice el motivo. Una caída nunca se convierte en un resultado.
Qué consume una verificación
Cada respuesta cuenta una vez en las verificaciones del mes de tu plan, la haya dado nuestra verificación o el servicio de pago. Un plan sin límite mensual nunca se agota. Cuando no queda ninguna, la llamada responde 429 con details.resetAt y details.upgradeTo. Si el último pago falló, responde 402 y no pone nada en cola.
Un resultado vale 30 días, y una dirección con un resultado vigente no se vuelve a comprobar. recheck: true pide otra comprobación igualmente, pero no dentro de las 24 horas siguientes a la última respuesta del servicio de verificación: esa respuesta vuelve tal cual, sin una comprobación nueva.
Lee la configuración antes de un lote grande. month trae lo que usó el workspace y su límite, que es null cuando el plan no tiene.
const setup = await colding.emailChecks.setup();
console.log(setup.state, setup.month);Cuando tu clave tiene validate y las verificaciones están activas, un contacto que crea una escritura también se comprueba: contacts.create, una dirección nueva en contacts.upsert o una fila nueva en una importación. Un contacto que ya existe conserva su resultado y no recibe una comprobación nueva. Pasa checkAddresses: false para omitirlo. Un mes agotado nunca rechaza la escritura: el contacto se guarda y su verificación queda en espera.
Las verificaciones piden que el dueño acepte antes la política de uso aceptable. Hasta entonces, emailChecks.check y emailChecks.start responden 403 AUP_REQUIRED, y una escritura guarda el contacto pero no inicia ninguna verificación (notStartedBecause: aup_required). Un agente se lo pide al dueño con un handoff accept_aup.
Para comprobar muchas direcciones, inicia un lote con una selección, de hasta 50.000 contactos por lote. Pasa un intentKey para que un reintento devuelva el mismo lote. Síguelo con emailChecks.getRun, o espera el evento email_check.run_completed. El evento email_check.run_held avisa cuando el lote queda en espera.
const run = await colding.emailChecks.start({
selection: {
all: true,
filters: { segmentId: "99999999-9999-4999-8999-999999999999" },
},
intentKey: "check-example-com-2030-01-15",
});
const now = await colding.emailChecks.getRun({ runId: run.id });
console.log(now.state, now.counts);Encuentra, detén y repite lotes
emailChecks.list lista las verificaciones, de la más nueva a la más antigua, una página a la vez. Filtra por address (sin distinguir mayúsculas), contactId, runId (un lote), state o status, el resultado. emailChecks.listRuns lista los lotes igual, y cada uno trae counts: cuántas de sus verificaciones están en cada punto. Guardamos una verificación 30 días después de que termina, y un lote 30 días después de que termina. El contacto se queda con su último resultado. Las dos piden read.
const checks = await colding.emailChecks.list({ address: "[email protected]" });
for (const check of checks.items) console.log(check.state, check.status);
const runs = await colding.emailChecks.listRuns({ limit: 10 });
for (const run of runs.items) console.log(run.id, run.state, run.counts);emailChecks.cancelRun detiene un lote. Sus verificaciones que aún no han ido al servicio de verificación se detienen y no cuestan nada, salvo que otro lote también las quiera o que emailChecks.check las haya pedido. Una verificación que ya fue al servicio termina, porque puede que ya cuente. Un lote que ya está cancelado o terminado vuelve como está.
emailChecks.retryRun manda de nuevo al servicio las verificaciones de un lote que se quedaron sin respuesta: las uncertain y las que quedaron en espera tras agotar los reintentos (noAnswer en counts). Cada una puede volver a contar en el mes, así que valen las reglas de una verificación nueva: 429 cuando el mes se agotó, 402 tras un pago fallido y 403 AUP_REQUIRED hasta que el dueño acepte la política de uso aceptable. Un lote cancelado responde 409: inicia uno nuevo. Las dos llamadas piden validate.
const stopped = await colding.emailChecks.cancelRun({
runId: "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
});
console.log(stopped.state, stopped.counts.cancelled);
const again = await colding.emailChecks.retryRun({
runId: "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
});
console.log(again.state, again.counts.uncertain, again.counts.noAnswer);Un resultado nunca levanta una supresión
Una verificación es un indicio, no un permiso. Un resultado válido no devuelve una dirección a la lista de personas a las que puedes escribir. La lista de supresión se lee primero, y solo quitar la dirección de esa lista lo cambia. A una dirección que resultó inválida nunca se le envía. Un mensaje nuevo a una dirección riesgosa o sin conclusión pide recipientReviewed: true. Cada fila cubre un stream: cold (campañas y mensajes) o transactional (el correo de tu app). suppressions.list y suppressions.add aceptan stream. Un rebote bloquea los dos. La consola permite quitar ambas filas a la vez. Si alguna fila que vas a quitar registra que la persona pidió no recibir correos, pasa recipientAsked: true solo si pidió recibirlos de nuevo. Sin esa confirmación, no se quita nada.
Un mensaje nuevo necesita un resultado reciente antes de salir. La guía de envío muestra dónde encaja eso. Envía un correo y síguelo
Exporta contactos a un archivo
contacts.export recibe una selección y responde un enlace, no el archivo. Descarga el archivo con un GET simple, sin clave. El enlace es el permiso, así que compártelo solo con quien deba ver esos contactos.
const file = await colding.contacts.export({
selection: {
ids: ["77777777-7777-4777-8777-777777777777", "88888888-8888-4888-8888-888888888888"],
},
});
console.log(file.url, file.expiresAt);El enlace funciona 10 minutos y se abre como máximo 3 veces. Cada llamada crea un enlace nuevo, así que vuelve a llamar después de expiresAt. Un archivo tiene hasta 100.000 contactos.
El archivo trae los campos de cada contacto, los campos personalizados, las etiquetas (una por línea dentro de la celda), el No enviar correos y la última verificación de la dirección. Los nombres de las columnas vienen en el idioma que pasas en locale, el del workspace por defecto, con coma entre celdas en inglés y punto y coma en portugués y español, como espera Excel. Trae los contactos que cumplen en el momento de la descarga, así que count es el número del momento en que creaste el enlace.
Una celda que una hoja de cálculo podría ejecutar como fórmula empieza con '.