Use caseSaaS & Services

Customer Onboarding

From sign up to fully provisioned customer in minutes, across CRM, billing and email. With proper rollback if any step fails.
Systems involved:CRMBillingIdentityEmail

The problem

When a new customer signs up, several systems need to be set up at once: an account in the identity system, a customer record in billing, a contact in the CRM, and a welcome email sequence in the marketing tool.

If just one of these steps fails halfway through, you end up with a broken customer: a user who can log in but has no billing account, or a contact in the CRM that nobody can charge. Cleaning that up by hand is slow, error prone and embarrassing when the customer notices.

How dataflows solves it

dataflows runs the whole onboarding as one durable workflow. Every step is recorded. If a step fails, it retries. If it cannot succeed, the workflow rolls back the previous steps so you never end up with a half-created customer.

The workflow can also wait for slow events without using server resources: an email confirmation, a manual review by sales, or the first payment. When the event arrives, the workflow picks up exactly where it stopped.

What it looks like in code

// Customer onboarding workflow
export const onboarding = defineWorkflow({
  id: 'customer-onboarding',
  trigger: { type: 'webhook', path: '/signup' },

  async run({ event, step }) {
    const { email, name } = event.body

    const account = await step.run('create-account', () =>
      identity.createUser({ email })
    )

    const customer = await step.run('create-billing', () =>
      billing.createCustomer({ email, accountId: account.id })
    )

    await step.run('create-crm-contact', () =>
      crm.contacts.create({ name, email, customerId: customer.id })
    )

    await step.run('send-welcome', () =>
      email.send({
        to: email,
        template: 'welcome',
        data: { name }
      })
    )

    return { accountId: account.id, customerId: customer.id }
  },

  onFailure: ({ step, context }) => step.run('rollback', () =>
    cleanup.undo(context)
  )
})

What the business gets

All systems in sync
One signup creates the right record in every system, in the right order.
Safe rollback
If something fails, previous steps are undone automatically. No zombie accounts.
Pause for humans
Workflow can wait for sales review or first payment, then continue on its own.

Ready for automation that just works?

Tell us about your process. We will tell you if and how dataflows can help.