← Back to cookbook

Client Onboarding Packet

One form creates the OneDrive folder, writes the onboarding packet, upserts the company into Attio, and sends the welcome email.

integrationai

Source

/**
 * New client onboarding. Fill in one internal form and the system does
 * the rest: creates the client's folder in OneDrive, writes a tailored
 * onboarding packet with AI, saves it to the folder, upserts the company
 * into Attio, and sends the welcome email from your own mailbox.
 *
 * Setup:
 *   1. swirls add microsoft create_folder upload_file send_mail
 *   2. swirls add attio assert_record
 *   3. Deploy, then authorize both connections in Cloud -> Connections.
 */

connection client_microsoft {
  label: "Client Microsoft 365"
  provider: microsoft
}

connection team_attio {
  label: "Attio CRM"
  provider: attio
}

schema onboarding_payload {
  label: "New client"
  schema: @json {
    {
      "type": "object",
      "required": ["company", "domain", "contact_name", "contact_email", "services"],
      "properties": {
        "company": { "type": "string", "title": "Company name" },
        "domain": { "type": "string", "title": "Company domain" },
        "contact_name": { "type": "string", "title": "Primary contact" },
        "contact_email": { "type": "string", "format": "email", "title": "Contact email" },
        "services": { "type": "string", "title": "Services sold" }
      }
    }
  }
}

form new_client {
  label: "Onboard a New Client"
  schema: onboarding_payload
}

workflow onboard_client {
  label: "Onboard Client"
  description: "Create the OneDrive folder, write the onboarding packet, upsert the CRM record, and send the welcome email."

  root {
    type: code
    label: "Receive client"
    inputSchema: onboarding_payload
    code: @ts { return context.nodes.root.input }
    outputSchema: onboarding_payload
  }

  node create_client_folder {
    type: integration
    label: "Create OneDrive folder"
    connection: client_microsoft
    action: microsoft_create_folder
    params: @ts {
      return {
        parent_id: "root",
        name: "Clients - " + context.nodes.root.output.company,
        folder: {},
        "@microsoft.graph.conflictBehavior": "rename"
      }
    }
  }

  node write_packet {
    type: ai
    label: "Write onboarding packet"
    kind: text
    model: "google/gemini-2.5-flash"
    prompt: @ts {
      const c = context.nodes.root.output
      return "Write an onboarding packet in markdown for a new managed services client.\n\nClient: " + c.company + " (" + c.domain + ")\nPrimary contact: " + c.contact_name + "\nServices sold: " + c.services + "\n\nSections: welcome note, what happens in the first two weeks, how to reach support, and what we need from the client to get started. Keep it to one page and write in plain language."
    }
  }

  node save_packet {
    type: integration
    label: "Save packet to folder"
    connection: client_microsoft
    action: microsoft_upload_file
    params: @ts {
      return {
        parent_id: context.nodes.create_client_folder.output.id,
        filename: "onboarding-packet.md",
        content: context.nodes.write_packet.output,
        contentType: "text/markdown"
      }
    }
  }

  node upsert_company {
    type: integration
    label: "Upsert company in Attio"
    connection: team_attio
    action: attio_assert_record
    params: @ts {
      const c = context.nodes.root.output
      return {
        object: "companies",
        matching_attribute: "domains",
        data: {
          values: {
            domains: [c.domain],
            name: c.company
          }
        }
      }
    }
  }

  node send_welcome {
    type: integration
    label: "Send welcome email"
    connection: client_microsoft
    action: microsoft_send_mail
    params: @ts {
      const c = context.nodes.root.output
      const folderUrl = context.nodes.create_client_folder.output.webUrl || ""
      return {
        message: {
          subject: "Welcome aboard, " + c.company,
          body: {
            contentType: "text",
            content: "Hi " + c.contact_name + ",\n\nWelcome! Your onboarding packet is ready and your shared folder is set up:\n\n" + folderUrl + "\n\nIt covers what happens in the first two weeks and what we need from your side. Reply to this email with any questions.\n"
          },
          toRecipients: [
            { emailAddress: { address: c.contact_email, name: c.contact_name } }
          ]
        },
        saveToSentItems: true
      }
    }
  }

  flow {
    root -> create_client_folder
    create_client_folder -> write_packet
    write_packet -> save_packet
    save_packet -> upsert_company
    upsert_company -> send_welcome
  }
}

trigger on_new_client {
  form:new_client -> onboard_client
  enabled: true
}

Flow

Trigger to workflow

Workflow nodes