require("dotenv").config();
const { google } = require("googleapis");
const axios = require("axios");
const cron = require("node-cron");
const OPENPHONE_API_BASE_URL = "https://api.openphone.com/v1";
const openPhone = axios.create({
baseURL: OPENPHONE_API_BASE_URL,
headers: {
Authorization: process.env.OPENPHONE_API_KEY,
"Content-Type": "application/json",
},
});
const googleAuth = new google.auth.GoogleAuth({
keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS,
scopes: ["https://www.googleapis.com/auth/spreadsheets"],
});
async function createOpenPhoneContact(contactData) {
const response = await openPhone.post("/contacts", contactData);
return response.data.data;
}
async function updateOpenPhoneContact(contactId, contactData) {
const response = await openPhone.patch(`/contacts/${contactId}`, contactData);
return response.data.data;
}
function mapFields(sheetRow) {
if (!sheetRow.firstName) {
console.warn("Missing required firstName in row: ", sheetRow);
return;
}
return {
defaultFields: {
firstName: sheetRow.firstName,
lastName: sheetRow.lastName,
phoneNumbers: sheetRow.phone
? [{ name: "primary", value: sheetRow.phone }]
: undefined,
emails: sheetRow.email
? [{ name: "primary", value: sheetRow.email }]
: undefined,
},
};
}
async function getGoogleSheetsData() {
const sheets = google.sheets({ version: "v4", googleAuth });
const response = await sheets.spreadsheets.values.get({
spreadsheetId: process.env.GOOGLE_SHEET_ID,
range: "Sheet1!A1:Z",
});
const rows = response.data.values;
const headers = rows[0];
return rows.slice(1).map((row) => {
const contact = {};
headers.forEach((header, index) => {
contact[header] = row[index];
});
return contact;
});
}
async function updateSheetWithContactId(rowNumber, contactId) {
const sheets = google.sheets({ version: "v4", googleAuth });
await sheets.spreadsheets.values.update({
spreadsheetId: process.env.GOOGLE_SHEET_ID,
range: `Sheet1!A${rowNumber + 2}`,
valueInputOption: "RAW",
resource: { values: [[contactId]] },
});
}
async function syncContacts() {
const sheetContacts = await getGoogleSheetsData();
for (const [rowNumber, sheetRow] of sheetContacts.entries()) {
const mappedContact = mapFields(sheetRow);
if (sheetRow.contactId) {
await updateOpenPhoneContact(sheetRow.contactId, mappedContact);
} else {
const { id } = await createOpenPhoneContact(mappedContact);
await updateSheetWithContactId(rowNumber, id);
}
}
console.log("Sync completed successfully");
}
cron.schedule("0 * * * *", syncContacts);
console.log("Sync process started. Running every hour.");