crm.leads.getById & crm.leads.update #

Read full lead records and update writable properties, including dynamic custom metadata fields (meta).


TypeScript Signatures #

typescript
// Fetch lead by numerical ID
crm.leads.getById(id: number): Promise<Lead>;

// Mutate writable lead fields
crm.leads.update(
  id: number,
  data: {
    name?: string;
    email?: string | null;
    phone?: string | null;
    countryCode?: string | null;
    meta?: Record<string, unknown>;
  }
): Promise<Lead>;

Parameters Reference #

getById(id) #

ParameterTypeRequiredDescription
idnumberYesThe positive integer ID of the lead to retrieve.

Returns: Promise<Lead> representing the latest database state.


update(id, data) #

ParameterTypeRequiredDescription
idnumberYesThe ID of the lead to update.
data.namestringOptionalLead display name or contact title.
data.emailstring | nullOptionalPrimary email address.
data.phonestring | nullOptionalTelephone number string.
data.countryCodestring | nullOptionalE.164 dial code (e.g. "+1", "+44", "+91").
data.metaRecord<string, unknown>OptionalCustom fields configured in the Module Builder.
⚠️ Warning

Field Whitelist Enforcement: Only name, email, phone, countryCode, and meta can be updated through crm.leads.update. Attempting to modify system-controlled attributes such as tenantId, moduleId, stageId, or pipelineId will be ignored. To change stages, use crm.leads.changeStage.


Minimal Quickstart Example #

typescript
async function run(context: Context, dolfin: DolfinApi): Promise<void> {
  const { lead } = context;
  const crm = await dolfin.crm.module(lead.moduleId);

  // Update custom metadata field
  await crm.leads.update(lead.id, {
    meta: {
      account_status: "verified",
      onboarding_score: 85
    }
  });
}

Production Recipe: Dynamic Lead Enrichment & Qualification Scoring #

This production recipe fetches fresh lead data, calculates a composite qualification score based on company domain and deal estimate, updates custom metadata, and appends an internal audit note.

typescript
async function run(context: Context, dolfin: DolfinApi): Promise<void> {
  const { lead } = context;
  const crm = await dolfin.crm.module(lead.moduleId);

  console.log(`Starting automated enrichment for Lead ID: ${lead.id} (${lead.name})`);

  try {
    // 1. Fetch fresh record from database
    const currentLead = await crm.leads.getById(lead.id);

    // 2. Compute dynamic qualification score
    let score = 0;
    const email = currentLead.email || "";

    // Domain check: Target enterprise accounts
    if (email.endsWith("@fortune500.com") || email.endsWith("@enterprise.org")) {
      score += 50;
    } else if (email && !email.includes("gmail.com") && !email.includes("yahoo.com")) {
      score += 25;
    }

    // Revenue check: High-value opportunities
    const annualRevenue = Number(currentLead.meta?.annual_revenue || 0);
    if (annualRevenue >= 1_000_000) {
      score += 35;
    } else if (annualRevenue >= 250_000) {
      score += 15;
    }

    const tier = score >= 70 ? "Tier 1 — High Value" : score >= 40 ? "Tier 2 — Standard" : "Tier 3 — Nurture";

    // 3. Persist score & tier back into custom meta
    const updated = await crm.leads.update(lead.id, {
      meta: {
        ...currentLead.meta,
        lead_score: score,
        qualification_tier: tier,
        last_scored_at: new Date().toISOString()
      }
    });

    // 4. Log audit note to timeline
    await crm.leads.notes.add(
      lead.id,
      `🎯 Lead automatically scored: ${score}/100 (${tier}).`
    );

    console.log(`Enrichment complete. Lead #${lead.id} assigned score ${score}.`);
  } catch (error: any) {
    console.error(`Failed to enrich lead #${lead.id}: ${error.message}`);
    throw error;
  }
}

Common Errors & Troubleshooting #

Error MessageCauseResolution
Invalid lead IDPassed non-integer or <= 0 ID.Ensure lead.id is a valid positive integer.
Lead not found in this moduleThe lead exists in the tenant but belongs to another module.Ensure you call dolfin.crm.module(lead.moduleId) using the correct module ID.
No updatable fields provideddata object was empty or contained only disallowed keys.Provide at least one writable field (name, email, phone, countryCode, or meta).