Tutorial

How to Build a Full CRM Automation with .0n SWITCH Files in 10 Minutes

MM
Mike Mento
Founder, RocketOpp LLC
How to Build a Full CRM Automation with .0n SWITCH Files in 10 Minutes

How to Build a Full CRM Automation with .0n SWITCH Files in 10 Minutes

Here's the scenario: a new contact hits your CRM. Within the next 90 seconds, you need to enrich their data, score them against your ICP, route them to the right pipeline stage, send a personalized welcome email, and notify your sales rep on Slack.

In a traditional CRM workflow builder, this is 20+ clicks, a dozen modal dialogs, a filter condition editor that makes you want to close the laptop, and 45 minutes of your afternoon.

In 0nMCP, it's a .0n SWITCH file and one command.

Let me show you exactly how.


What Is a .0n SWITCH File?

A SWITCH file is a structured JSON document that describes an automation as a series of steps. It follows the .0n Standard — a universal config format for AI-driven workflows. Think of it as the infrastructure-as-code equivalent for business automations.

Every SWITCH file has:

  • $0n — Document metadata (version, type, name)
  • trigger — What kicks off the automation
  • inputs — User-facing configuration variables
  • launch_codes — Sensitive credentials (API keys, tokens)
  • steps — The ordered list of actions to execute

Variable resolution follows a strict priority order:

{{system.}}  >  {{launch.}}  >  {{inputs.}}  >  {{step.output.}}

System variables are always trusted first. Launch codes (secrets) override input values. Step outputs are referenced by step ID.


The Automation We're Building

Here's what we want to happen when a new contact is created in the CRM:

  1. Enrich — Pull company data, LinkedIn, tech stack from People Data Labs
  2. Score — Check if they match our ICP (B2B, 10-500 employees, uses SaaS tools)
  3. Route — Move them to "High Priority" or "Nurture" pipeline based on score
  4. Email — Send a personalized welcome email using their first name and company
  5. Notify — Post to the #new-leads Slack channel with a summary card

The Complete SWITCH File

{

"$0n": { "version": "1.1.0", "type": "workflow", "name": "new-contact-icp-router", "description": "Enrich, score, route, email, and notify on every new CRM contact", "created": "2026-02-27" },

"trigger": { "type": "webhook", "event": "contact.created", "source": "crm" },

"inputs": { "pipeline_id_hot": "your-hot-pipeline-id", "pipeline_id_nurture": "your-nurture-pipeline-id", "icp_min_employees": 10, "icp_max_employees": 500, "sender_name": "Mike from 0nMCP", "sender_email": "mike@rocketopp.com", "slack_channel": "#new-leads" },

"launch_codes": { "pdl_api_key": "{{env.PDL_API_KEY}}", "crm_api_key": "{{env.CRM_API_KEY}}", "slack_token": "{{env.SLACK_BOT_TOKEN}}" },

"steps": [ { "id": "enrich", "name": "Enrich Contact Data", "service": "pdl", "action": "enrich_person", "params": { "email": "{{trigger.contact.email}}", "first_name": "{{trigger.contact.first_name}}", "last_name": "{{trigger.contact.last_name}}", "company": "{{trigger.contact.company_name}}" }, "on_error": "continue" },

{ "id": "score", "name": "Score Against ICP", "service": "internal", "action": "condition", "params": { "conditions": [ { "field": "{{step.enrich.output.employee_count}}", "operator": "between", "min": "{{inputs.icp_min_employees}}", "max": "{{inputs.icp_max_employees}}" }, { "field": "{{step.enrich.output.job_company_type}}", "operator": "equals", "value": "private" } ], "logic": "AND", "output_true": "hot", "output_false": "nurture" }, "depends_on": "enrich" },

{ "id": "route", "name": "Move to Correct Pipeline", "service": "crm", "action": "create_opportunity", "params": { "contact_id": "{{trigger.contact.id}}", "pipeline_id": "{{step.score.output == 'hot' ? inputs.pipeline_id_hot : inputs.pipeline_id_nurture}}", "name": "{{trigger.contact.first_name}} {{trigger.contact.last_name}} — New Lead", "status": "open" }, "depends_on": "score" },

{ "id": "welcome_email", "name": "Send Personalized Welcome Email", "service": "crm", "action": "send_email", "params": { "contact_id": "{{trigger.contact.id}}", "from_name": "{{inputs.sender_name}}", "from_email": "{{inputs.sender_email}}", "subject": "Hey {{trigger.contact.first_name}} — welcome to the ecosystem", "body_html": "<p>Hi {{trigger.contact.first_name}},</p><p>Saw you just joined — welcome. We work with a lot of teams at {{step.enrich.output.job_company_name || trigger.contact.company_name}} size doing exactly what you're describing.</p><p>I put you in the right place. You'll hear from us shortly.</p><p>— {{inputs.sender_name}}</p>" }, "depends_on": "route" },

{ "id": "slack_notify", "name": "Notify Sales Team on Slack", "service": "slack", "action": "post_message", "params": { "channel": "{{inputs.slack_channel}}", "text": "New {{step.score.output}} lead: {{trigger.contact.first_name}} {{trigger.contact.last_name}} at {{step.enrich.output.job_company_name || trigger.contact.company_name}}\n• Employees: {{step.enrich.output.employee_count || 'unknown'}}\n• Title: {{trigger.contact.title || 'unknown'}}\n• Email: {{trigger.contact.email}}\n• Pipeline: {{step.score.output == 'hot' ? 'HIGH PRIORITY' : 'Nurture'}}", "unfurl_links": false }, "depends_on": "route" } ] }


Breaking Down What's Happening

The Trigger Block

"trigger": {

"type": "webhook", "event": "contact.created", "source": "crm" }

This wires the automation to the CRM's webhook system. When a contact is created, the CRM fires a POST to your 0nMCP HTTP server endpoint. The trigger payload is available as {{trigger.}} throughout all steps.

Variable Resolution in Action

Notice how {{trigger.contact.email}} pulls from the webhook payload. {{inputs.sender_name}} pulls from your static config. {{step.enrich.output.employee_count}} pulls from the runtime output of the previous step.

The || operator handles graceful fallbacks: if enrichment didn't find a company name, fall back to what the CRM already has.

The on_error: continue Pattern

Step 1 (enrich) uses on_error: continue. PDL enrichment can fail if the email doesn't have a match. Instead of aborting the entire workflow, we continue — the downstream steps handle missing data gracefully via fallback expressions.

depends_on for Step Ordering

Steps 3 (route), 4 (welcome_email), and 5 (slack_notify) all depend on prior steps. depends_on guarantees execution order. Steps 4 and 5 both depend on step 3 but not each other — in Assembly Line mode, they run in parallel after routing completes.


Running the Automation

# Execute directly against a test payload

0nmcp run new-contact-icp-router.0n --input contact.email=test@example.com

Or start the HTTP server and let the CRM webhook trigger it

0nmcp serve --port 3001

For webhook-triggered automations in production:

0nmcp serve --port 3001 --host 0.0.0.0

Then point your CRM webhook to: https://your-server.com/webhook/contact.created


The 20-Click Alternative

For reference, here's what building this same automation in a traditional CRM workflow builder looks like:

  1. Open Automation Builder
  2. Create new workflow
  3. Name it
  4. Choose trigger type (contact created)
  5. Add filter conditions
  6. Add HTTP action (for PDL enrichment)
  7. Configure URL, headers, body (separate modal)
  8. Map response fields (JSON path picker)
  9. Add If/Else branch
  10. Configure branch conditions
  11. Add "Update Contact" action for hot branch
  12. Add "Update Contact" action for nurture branch
  13. Configure pipeline ID dropdown
  14. Add email action
  15. Open email template editor
  16. Write HTML email
  17. Map personalization tokens
  18. Set sender details
  19. Add Slack action
  20. Authenticate Slack app
  21. Configure channel + message format
  22. Publish and test

That's 22 steps, spread across 4-6 different modal dialogs, with no version control, no code review, no reusability, and no portability.

Your .0n SWITCH file is 80 lines of JSON. It's in your git repo. It's readable by humans and machines. It runs identically in dev, staging, and production.


Adding It to Your Master SWITCH

If you've run 0nmcp engine import to set up your master credentials, you can reference your services directly:

# Verify your credentials are loaded

0nmcp engine verify

Run the workflow against your real services

0nmcp run new-contact-icp-router.0n

The engine maps your imported credentials to {{launch.}} variables automatically. No copy-pasting API keys into config files.


What Comes Next

This is one automation. But the pattern scales. Every business process you're clicking through manually is a SWITCH file waiting to be written. Once it's a file, it's:

  • Versionable — git history for every change
  • Portable — runs anywhere 0nMCP is installed
  • Composable — combine SWITCH files into larger pipelines
  • AI-editable — hand it to Claude and say "add a step that scores by company size" — it knows the schema

That last point is the one that changes everything. When your automation infrastructure is data (JSON files), AI can read it, modify it, extend it, and reason about it. When it's a drag-and-drop UI state, AI can't touch it.

Write the file. Run the file. Ship the outcome.

Get 0nMCP | .0n Standard docs | More examples

#tutorial#CRM#automation#SWITCH files#.0n standard#workflow
← Previous
The 0nVault Container System: Secure AI Brain Transfer Explained
Next →
0nMCP v2.2.0: 819 Tools Across 48 Services — Full Breakdown
← All Posts
0nMCP Console
>

Describe it. 0nMCP executes it.

819 tools. 48 services. One command. Try the Console — your AI command center.

Open Console