Swirls

SWIRLS_

  • How it works
  • Pricing

56 matches

OverviewDeliver client operations10Win and grow accounts8Resolve customer issues6Create and distribute content9Run people and operations5Review money and agreements3Monitor systems and data9Compose dependable work6

56 matches

OverviewDeliver client operations10Win and grow accounts8Resolve customer issues6Create and distribute content9Run people and operations5Review money and agreements3Monitor systems and data9Compose dependable work6
← Sales & MarketingWebhookView on GitHub

Lead Scoring

Scores incoming leads, persists results, and alerts sales on hot ones.

aiswitchemail

Source

/**
 * Scores incoming leads and persists results for reporting.
 * High-scoring leads trigger an alert to the sales team.
 */

webhook new_lead {
  label: "New Lead Webhook"
  schema: @json {
    {
      "type": "object",
      "required": ["email", "company", "source"],
      "properties": {
        "email": { "type": "string", "format": "email" },
        "company": { "type": "string" },
        "source": { "type": "string" },
        "job_title": { "type": "string" },
        "company_size": { "type": "string" }
      }
    }
  }
}

workflow score_lead {
  label: "Score Lead"

  root {
    type: code
    label: "Extract lead"
    code: @ts { return context.nodes.root.input }
    outputSchema: @json {
      {
        "type": "object",
        "properties": {
          "email": { "type": "string" },
          "company": { "type": "string" },
          "source": { "type": "string" },
          "job_title": { "type": "string" },
          "company_size": { "type": "string" }
        }
      }
    }
  }

  node score {
    type: ai
    label: "Score the lead"
    kind: object
    model: "google/gemini-2.5-flash"
    prompt: @ts {
      const lead = context.nodes.root.output
      return "Score this B2B lead from 0-100 based on likelihood to convert.\n\nEmail: " + lead.email + "\nCompany: " + lead.company + "\nSource: " + lead.source + "\nJob title: " + (lead.job_title || "unknown") + "\nCompany size: " + (lead.company_size || "unknown")
    }
    schema: @json {
      {
        "type": "object",
        "required": ["score", "reasoning", "tier"],
        "properties": {
          "score": { "type": "number", "minimum": 0, "maximum": 100 },
          "reasoning": { "type": "string" },
          "tier": { "type": "string", "enum": ["hot", "warm", "cold"] }
        }
      }
    }
  }

  node route {
    type: switch
    label: "Route by score"
    cases: ["hot", "other"]
    router: @ts {
      if (context.nodes.score.output.tier === "hot") return "hot"
      return "other"
    }
  }

  node alert_sales {
    type: email
    label: "Alert sales team"
    from: @ts { return "[email protected]" }
    to: @ts { return "[email protected]" }
    subject: @ts {
      return "Hot lead: " + context.nodes.root.output.company + " (Score: " + context.nodes.score.output.score + ")"
    }
    text: @ts {
      const lead = context.nodes.root.output
      const result = context.nodes.score.output
      return "New hot lead!\n\nCompany: " + lead.company + "\nEmail: " + lead.email + "\nScore: " + result.score + "\nReason: " + result.reasoning
    }
  }

  node log_result {
    type: code
    label: "Log score"
    code: @ts {
      return {
        email: context.nodes.root.output.email,
        company: context.nodes.root.output.company,
        score: context.nodes.score.output.score,
        tier: context.nodes.score.output.tier
      }
    }
  }

  flow {
    root -> score
    score -> route
    route -["hot"]-> alert_sales
    route -["other"]-> log_result
  }
}

stream scored_leads {
  label: "Scored leads"
  workflow: score_lead
  version: v1

  versions: {
    v1 {
      schema: @json {
        {
          "type": "object",
          "required": ["email", "company", "score", "tier"],
          "properties": {
            "email": { "type": "string" },
            "company": { "type": "string" },
            "score": { "type": "number" },
            "tier": { "type": "string" }
          }
        }
      }

      condition: @ts { return true }

      prepare: @ts {
        const logged = context.output.log_result
        if (logged) return logged
        return {
          email: context.nodes.root.output.email,
          company: context.nodes.root.output.company,
          score: context.nodes.score.output.score,
          tier: context.nodes.score.output.tier
        }
      }
    }
  }
}

trigger on_lead {
  webhook:new_lead -> score_lead
  enabled: true
}

Flow

Trigger to workflow

new_leadwebhook
score_lead
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

Workflow nodes

CODE
Code Node
Extract lead
AI
AI Node
Score the lead
SWITCH
Switch Node
Route by score
EMAIL
Email Node
Alert sales team
CODE
Code Node
Log score
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.