Bahrul
BahrulPersonal Docs
KYZN

N8N - Sleekflow to PostgreSQL

Integrate N8N workflows with PostgreSQL for real-time inbound data processing

Last updated: Jan 3, 2026

Inbound Realtime N8N to PostgreSQL

N8N to PostgreSQL Integration

API Configuration

MethodValue
HTTP MethodGET
Contact APIhttps://api.sleekflow.io/api/contact?limit=100&offset=0
Conversations (Closed)https://api.sleekflow.io/api/conversation/all?limit=100&offset=0&status=closed
Conversations (Open)https://api.sleekflow.io/api/conversation/all?limit=100&offset=0&status=open
Send HeadersON
HeaderX-Sleekflow-Api-Key

Data Transformation

Chat Data Processing (chat.js)

Transform contact and conversation data from SleekFlow API into a standardized format.

// Function to format the timestamp to 'YYYY-MM-DD HH:MM:SS'
function formatTimestamp(timestamp) {
  if (!timestamp) return null; // Return null if missing
  const date = new Date(timestamp);
  if (isNaN(date.getTime())) return null; // Return null for invalid date

  // Extract the year, month, day, hours, minutes, and seconds
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0'); // Month is 0-based
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');

  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

// Function to map lastChannelIdentityId to specific labels
function mapChannelIdentity(lastChannelIdentityId) {
  if (!lastChannelIdentityId) return null;

  if (lastChannelIdentityId.includes("409534172246677")) {
    return "fb_kyzn_id";
  } else if (lastChannelIdentityId.includes("17841468769957389")) {
    return "ig_kyzn_id";
  } else if (lastChannelIdentityId.includes("19190")) {
    return "fb_kuningan";
  } else if (lastChannelIdentityId.includes("17841453892878958")) {
    return "ig_kuningan";
  } else if (lastChannelIdentityId.includes("19191")) {
    return "fb_bsd";
  } else if (lastChannelIdentityId.includes("17841450110322840")) {
    return "ig_bsd";
  } else if (lastChannelIdentityId.includes("113207553436200")) {
    return "ig_kyzn_life";
  } else if (lastChannelIdentityId.includes("110429021829147")) {
    return "ig_kyzn_preschool";
  } else if (lastChannelIdentityId.includes("6285174420088")) {
    return "whatsapp";
  } else {
    return "whatsapp";
  }
}

// Function to map mremarks based on the value of sremarks
function mapMremarks(sremarks) {
  if (["fb_kyzn_id", "ig_kyzn_id", "fb_kuningan", "ig_kuningan", "fb_bsd", "ig_bsd"].includes(sremarks)) {
    return "dm";
  } else {
    return "wa"; // Default or fallback value
  }
}

// Function to map branch based on mremarks value
function mapBranch(sremarks) {
  const branchMapping = {
    fb_bsd: "KYZN BSD",
    ig_bsd: "KYZN BSD",
    fb_kuningan: "KYZN Kuningan",
    ig_kuningan: "KYZN Kuningan"
  };
  return branchMapping[sremarks] || "KYZN"; // Default branch value
}

// Function to convert text to Capitalized Case
function capitalizeText(text) {
  if (!text) return null; // Handle missing text
  return text
    .toLowerCase()
    .split(" ")
    .map(word => word.charAt(0).toUpperCase() + word.slice(1))
    .join(" ");
}

// List of names to check for exclusion in contact_owner
const excludedOwners = new Set([
  "KYZN", "Diadre Marketing", "Sales BSD", "Sales KNG",
  "Lutfi CA", "FO BSD", "FO Kuningan", "Siska Permata", "Admin KYZN"
]);

// Get the input from the previous node
const data = items;

// Transform the data to the desired format with safe checks for undefined fields
const result = data.map(item => {
  const sremarks = mapChannelIdentity(item.json.lastChannelIdentityId);
  const mremarks = mapMremarks(sremarks);
  const rawContactOwner = item.json.assignee?.userInfo?.displayName || item.json.assignedTeam?.teamName || null;
  const contactOwner = excludedOwners.has(rawContactOwner) ? null : rawContactOwner;

  return {
    id: item.json.userProfile?.id || null,
    conversationId: item.json.conversationId || null,
    name: capitalizeText(item.json.userProfile?.firstName || null), // Convert to Capitalized Case
    phone: item.json.userProfile?.whatsAppAccount?.phone_number || null,
    created_at: formatTimestamp(item.json.userProfile?.createdAt),
    updated_at: formatTimestamp(item.json.userProfile?.updatedAt),
    last_contact_from_customer: formatTimestamp(item.json.userProfile?.lastContactFromCustomers),
    contact_owner: contactOwner, // Apply exclusion rule
    contact_owner_email: item.json.assignee?.userInfo?.email || null,
    last_channel: item.json.lastMessageChannel || 'whatsapp',
    sremarks_id: item.json.lastChannelIdentityId || null,
    sremarks: sremarks || 'whatsapp',
    mremarks: mremarks || 'wa',
    branch: mapBranch(sremarks) // Map branch based on sremarks
  };
});

// Return the result to the next node
return result;

Conversion Data Processing (convert.js)

Process and standardize lead conversion data for PostgreSQL storage.

// Function to format the timestamp to 'YYYY-MM-DD HH:MM:SS'
function formatTimestamp(timestamp) {
  const date = timestamp ? new Date(timestamp) : new Date(); // Use current date-time if missing

  // Extract the year, month, day, hours, minutes, and seconds
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0'); // Month is 0-based
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');

  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

// List of names to check for exclusion
const excludedOwners = new Set([
  'KYZN', 'Diadre Marketing', 'Sales BSD', 'Sales KNG',
  'Lutfi CA', 'FO BSD', 'FO Kuningan', 'Siska Permata', 'Admin KYZN'
]);

// Function to map sremarks_id to specific labels
function mapSremarksId(sremarks_id) {
  if (!sremarks_id) return "whatsapp"; // Default jika tidak ada id

  const identityMap = {
    "409534172246677": "fb_kyzn_id",
    "17841468769957389": "ig_kyzn_id",
    "19190": "fb_kuningan",
    "17841453892878958": "ig_kuningan",
    "19191": "fb_bsd",
    "17841450110322840": "ig_bsd",
    "113207553436200": "ig_kyzn_life",
    "110429021829147": "ig_kyzn_preschool",
    "6285174420088": "whatsapp"
  };

  return identityMap[sremarks_id] || "whatsapp";
}

// Function to determine branch based on sremarks
function mapBranch(sremarks) {
  const branchMapping = {
    fb_bsd: "KYZN BSD",
    ig_bsd: "KYZN BSD",
    fb_kuningan: "KYZN Kuningan",
    ig_kuningan: "KYZN Kuningan"
  };
  return branchMapping[sremarks] || "KYZN"; // Default branch value
}

// Function to determine mremarks based on sremarks
function mapMremarks(sremarks) {
  const dmSources = ["fb_kyzn_id", "ig_kyzn_id", "fb_kuningan", "ig_kuningan", "fb_bsd", "ig_bsd"];
  return dmSources.includes(sremarks) ? "dm" : "wa"; // Default fallback
}

// Function to convert text to Capitalized Case
function capitalizeText(text) {
  if (!text) return null; // Handle missing text
  return text
    .toLowerCase()
    .split(" ")
    .map(word => word.charAt(0).toUpperCase() + word.slice(1))
    .join(" ");
}

// Get the input from the previous node
const data = items;

// Transform the data, converting all relevant timestamp fields
const result = data.map(item => {
  const contactOwnerName = item.json.ContactOwnerName || null;
  const adSourceId = item.json.AdSourceID || null;
  const leadSource = item.json.LeadSource || null;
  const phoneNumber = item.json.PhoneNumber || null;
  const sremarks_id = item.json.sremarks_id || null;

  let source = leadSource;
  let sremarks = item.json.sremarks || null;
  let medium = 'sleekflow'; // Default to 'sleekflow'
  let mremarks = item.json.mremarks || null;

  // Apply conditions
  if (adSourceId) {
    // Jika ad_source_id tidak null
    source = 'meta_ads';
    sremarks = adSourceId;
    mremarks = 'wa';
  } else {
    // Jika ad_source_id null, cek sremarks_id
    sremarks = mapSremarksId(sremarks_id);
    source = 'social_media';
    mremarks = mapMremarks(sremarks);
  }

  return {
    id: item.json.id || null,
    phone: phoneNumber,
    language: item.json.Language || null,
    interest: item.json.Interest || null,
    interest_remarks: item.json['interest remarks'] || null, // Corrected for property with space
    last_contact: formatTimestamp(item.json.LastContact),
    last_contact_from_customer: formatTimestamp(item.json.LastContactFromCustomers),
    last_contact_from_company: formatTimestamp(item.json.LastContactedFromCompany),
    last_contact_from_user: formatTimestamp(item.json.LastContactedFromUser),
    created_at: formatTimestamp(item.json.CreatedAt),
    updated_at: formatTimestamp(item.json.UpdatedAt),
    last_channel: item.json.LastChannel || null,
    contact_owner: excludedOwners.has(contactOwnerName) ? null : contactOwnerName,
    contact_owner_email: item.json.ContactOwnerEmail || null,
    source: source,
    sremarks: sremarks,
    medium: medium,
    mremarks: mremarks,
    click_id: item.json.AdClickID || null,
    ad_source_url: item.json.AdSourceURL || null,
    ad_source_id: adSourceId,
    name: capitalizeText(item.json.FirstName || 'unknown'),
    branch: mapBranch(sremarks),
    conversationId: item.json.conversationId || null,
    sremarks_id: sremarks_id,
  };
});

// Return the result to the next node
return result;

Database Storage

After transformation, store the processed data in PostgreSQL tables using N8N's PostgreSQL node for persistence and real-time querying.

On this page