> ## Documentation Index
> Fetch the complete documentation index at: https://docs.callkaro.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Build A Workflow With Claude

> Describe the follow-up in plain language, get an importable JSON file

Placing a dozen steps and wiring every branch by hand is slow. If you already
have the plan written down — a sales cadence, a follow-up script, a spreadsheet
of steps, another tool's automation — you can hand it to Claude with the file
below and get a finished workflow you import in one step.

***

## 1. Download The Skill

<Card title="callkaro-workflow-skill.txt" icon="file-arrow-down" href="/media/callkaro-workflow-skill.txt">
  The complete workflow specification, written for Claude. \~27 KB.
</Card>

It is Markdown — every step type, every field, the value sources, what import
rejects, and the exact shape of an importable workflow file. **Save it as
`SKILL.md`** (or any `.md` name) once you have it.

Want to see the result first? This is the complete example from the skill — a
call, a branch on whether it connected and whether the lead is interested, a
WhatsApp template and a second call the next day. Copy it, save it as
`lead-follow-up.json` and import it as it is to see how a file maps onto the
canvas.

<Accordion title="lead-follow-up.json" icon="file-code">
  ```json lead-follow-up.json theme={null}
  {
    "type": "callkaro_workflow",
    "version": 1,
    "data": {
      "workFlowName": "New lead follow-up",
      "type": "normal",
      "graph": {
        "nodes": [
          {
            "id": "start-1",
            "type": "start",
            "name": "Start",
            "x": 320,
            "y": 180
          },
          {
            "id": "send-call-1",
            "type": "send-call",
            "name": "First call",
            "x": 660,
            "y": 180,
            "agentId": "REPLACE_ME_AGENT",
            "retries": 1,
            "retryGaps": [
              30
            ],
            "retryGapMinutes": 30,
            "metadata": [
              {
                "key": "customer_name",
                "source": "contact",
                "value": "first_name"
              }
            ]
          },
          {
            "id": "conditions-1",
            "type": "conditions",
            "name": "Picked up?",
            "x": 1000,
            "y": 180,
            "exits": [
              {
                "id": "exit-picked",
                "label": "Picked up",
                "condition": {
                  "source": "connected_call",
                  "field": "",
                  "op": "eq",
                  "value": "true"
                }
              },
              {
                "id": "exit-missed",
                "label": "otherwise"
              }
            ]
          },
          {
            "id": "conditions-2",
            "type": "conditions",
            "name": "Interested?",
            "x": 1340,
            "y": 180,
            "exits": [
              {
                "id": "exit-interested",
                "label": "Interested",
                "condition": {
                  "source": "post_call_variables",
                  "field": "interested",
                  "op": "eq",
                  "value": "yes"
                }
              },
              {
                "id": "exit-not",
                "label": "otherwise"
              }
            ]
          },
          {
            "id": "update-lead-1",
            "type": "update-lead",
            "name": "Mark interested",
            "x": 1680,
            "y": 180,
            "updates": [
              {
                "attribute": "lead_status",
                "source": "static_value",
                "value": "Interested"
              }
            ]
          },
          {
            "id": "api-basic-1",
            "type": "api-basic",
            "name": "Tell our CRM",
            "x": 2020,
            "y": 180,
            "method": "POST",
            "url": "https://REPLACE_ME.example.com/leads",
            "parameters": [],
            "headers": [
              {
                "key": "Authorization",
                "source": "secret",
                "value": "CRM_API_TOKEN"
              }
            ],
            "body": "{\"phone\": \"{{phone}}\", \"status\": \"interested\"}",
            "bodyParameters": [
              {
                "key": "{{phone}}",
                "source": "phone_number",
                "value": ""
              }
            ]
          },
          {
            "id": "end-1",
            "type": "end",
            "name": "Interested",
            "x": 2360,
            "y": 180
          },
          {
            "id": "end-2",
            "type": "end",
            "name": "Not interested",
            "x": 1680,
            "y": 400
          },
          {
            "id": "wa-template-1",
            "type": "wa-template",
            "name": "Missed-call template",
            "x": 1340,
            "y": 620,
            "provider": "whatsapp",
            "templateId": "REPLACE_ME_TEMPLATE",
            "templateName": "",
            "languageCode": "",
            "templateBody": "",
            "phoneNumberId": "",
            "displayPhoneNumber": "",
            "parameters": []
          },
          {
            "id": "wait-1",
            "type": "wait",
            "name": "Wait a day",
            "x": 1680,
            "y": 620,
            "minutes": 1440
          },
          {
            "id": "send-call-2",
            "type": "send-call",
            "name": "Second call",
            "x": 2020,
            "y": 620,
            "agentId": "REPLACE_ME_AGENT",
            "retries": 0,
            "retryGaps": [],
            "retryGapMinutes": 30
          },
          {
            "id": "end-3",
            "type": "end",
            "name": "Done",
            "x": 2360,
            "y": 620
          }
        ],
        "edges": [
          {
            "id": "edge-1",
            "from": "start-1",
            "fromHandle": "out",
            "to": "send-call-1"
          },
          {
            "id": "edge-2",
            "from": "send-call-1",
            "fromHandle": "out",
            "to": "conditions-1"
          },
          {
            "id": "edge-3",
            "from": "conditions-1",
            "fromHandle": "exit-picked",
            "to": "conditions-2"
          },
          {
            "id": "edge-4",
            "from": "conditions-1",
            "fromHandle": "exit-missed",
            "to": "wa-template-1"
          },
          {
            "id": "edge-5",
            "from": "conditions-2",
            "fromHandle": "exit-interested",
            "to": "update-lead-1"
          },
          {
            "id": "edge-6",
            "from": "conditions-2",
            "fromHandle": "exit-not",
            "to": "end-2"
          },
          {
            "id": "edge-7",
            "from": "update-lead-1",
            "fromHandle": "out",
            "to": "api-basic-1"
          },
          {
            "id": "edge-8",
            "from": "api-basic-1",
            "fromHandle": "out",
            "to": "end-1"
          },
          {
            "id": "edge-9",
            "from": "wa-template-1",
            "fromHandle": "out",
            "to": "wait-1"
          },
          {
            "id": "edge-10",
            "from": "wait-1",
            "fromHandle": "out",
            "to": "send-call-2"
          },
          {
            "id": "edge-11",
            "from": "send-call-2",
            "fromHandle": "out",
            "to": "end-3"
          }
        ]
      }
    }
  }
  ```
</Accordion>

***

## 2. Give It To Claude

<Tabs>
  <Tab title="Claude Code">
    Save it as a skill and it loads itself whenever the task calls for it:

    ```
    ~/.claude/skills/callkaro-workflow/SKILL.md
    ```
  </Tab>

  <Tab title="Claude apps">
    Attach the file to the conversation, then describe what you want. Add it as
    a Project file if you will be building more than one workflow.
  </Tab>
</Tabs>

***

## 3. Describe The Workflow

With the skill attached, either paste the plan:

> Here is our lead follow-up cadence *(attach the file)*. Build a CallKaro
> workflow from it. Use agent `68f1c0a2b3d4e5f6a7b8c9d0` for every call.

…or just describe it:

> New leads get a call straight away, with one retry after 30 minutes. If they
> pick up and are interested, set `lead_status` to Interested and post them to
> our CRM. If they don't pick up, send our missed-call WhatsApp template, wait a
> day and call once more.

Claude returns a single JSON file.

<Tip>
  Give Claude the IDs it cannot guess: your **voice agent IDs** (the last part of
  the agent's URL) and the **CRM attribute names** a step should read or write
  (**CRM → Attributes**). Anything you leave out comes back as a placeholder for
  you to fill in.
</Tip>

***

## 4. Import It

Save what Claude gives you as `something.json`, then:

**Workflows → Import** → choose the file

The workflow is created with every step already placed and connected. Open it
from the list to see it on the canvas.

<Warning>
  Import **creates** the workflow; it does not enroll anyone. Fix the steps listed
  below first, then add contacts from the CRM or through
  [Assign to Workflow](/api-reference/workflow-assign).
</Warning>

You can also go the other way: **Export** an existing workflow (the row's menu
in the Workflows list), hand that file to Claude to extend, and import the
result back as a new workflow.

***

## What To Check Before Enrolling Anyone

Some values only exist in your account, so Claude leaves placeholders for
anything you did not give it. Import accepts them — they fail on the first run
instead — so open these steps and fix them on the canvas:

* **Send Call** — the **Voice Agent**, if it shows `REPLACE_ME_AGENT`
* **Send WhatsApp Template** — pick the **template** and the **sending number**,
  then map the template's variables
* **Send WhatsApp Message** — pick the **sending number**
* **API Call — Basic** — the **URL**, and any **secret** a header refers to,
  which must exist under that exact name
* **API Call — Advanced** — the code is a sketch against *your* systems, not a
  working integration
* **Update Contact** and any **Contact** value — the attribute names must exist
  in **CRM → Attributes**
* **Conditions** on **Post Call** values — your agent must actually extract that
  post-call variable

The skill tells Claude to list these back to you explicitly. If it did not, ask:
*"which values in this workflow did you invent?"*

***

## What It Will Refuse To Build

The skill documents the platform's limits so Claude tells you instead of faking
them: parallel branches (a run follows one path), waiting until a time of day,
waiting for a WhatsApp reply, built-in SMS or email steps, and free-text WhatsApp
messages to contacts who have not written to you in the last 24 hours (use a
template).

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Build a workflow" icon="pen-ruler" href="/workflows/build-a-workflow">
    What each step does on the canvas
  </Card>

  <Card title="Enroll and monitor" icon="chart-line" href="/workflows/enroll-and-monitor">
    Add contacts and follow every run
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.