Docs
Creating a Workflow

Creating a Workflow

How POST /api/workflows works — from goal text to a saved plan sent to your inbox.

The API Call

POST /api/workflows
Authorization: Bearer <session>
 
{
  "goal": "Publish a weekly LinkedIn post about AI news every Monday morning",
  "schedule": "0 9 * * 1"   // optional cron string
}

The response returns the created workflow with its generated steps:

{
  "workflowId": "abc123",
  "title": "Weekly AI News LinkedIn Post",
  "steps": [...],
  "status": "draft",
  "message": "Plan created. Check your email to approve and activate."
}

How the Plan is Generated

The endpoint calls generateWorkflowPlan(goal, businessName, coreMemory) from lib/ai/workflows/planner.ts:

const { output } = await generateText({
  model: openai("gpt-4o"),
  output: Output.object({ schema: WorkflowPlanSchema }),
  system: `...planner instructions with available tools...`,
  prompt: `Goal: ${goal}`,
});

This is a single deterministic LLM call — not a ToolLoopAgent. It returns a strongly-typed WorkflowPlan:

WorkflowPlanSchema = z.object({
  title: z.string(),        // max 60 chars
  steps: z.array(z.object({
    stepIndex: z.number(),   // 0-based, no gaps
    description: z.string(), // shown in UI and emails
    toolName: z.enum(WORKFLOW_TOOL_NAMES),
  })).min(1).max(20),
})

Available Planner Tools

The planner can choose from these tools when generating steps:

ToolWhen to Use
web_searchFind current facts, news, trending topics
web_extractPull full content from a specific URL
generate_outlineStructure content before writing
generate_reportInternal research summaries and reports
format_postProduce the final formatted post
generate_imageCreate a visual asset
memoryRead or update team memory
llm_responseFree-form assistant message (summarize, transition, explain)

The planner system prompt enforces two rules:

  1. generate_outline must always come before format_post
  2. format_post and generate_image always get requiresApproval: true

After the Plan is Saved

  1. Workflow saved with status: "draft" and all steps in workflowSteps
  2. If a schedule was provided, it's stored in workflows.schedule (cron string)
  3. A 24-hour JWT is signed with WORKFLOW_TOKEN_SECRET
  4. sendPlanApprovalEmail() sends an HTML email with the step table and an "Approve & Activate" button

If the approval email fails to send, the workflow is still saved in draft state and can be approved programmatically via POST /api/workflows/[id]/approve.