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

# Create & publish an agent

> Build a draft agent, test it, and publish it so campaigns can use it.

This walkthrough takes an agent from empty to published. Agents are editable while `draft` and locked once `published` — so you test freely, then publish when you're happy. For the model behind this, see the [Agents concept](/concepts/agents).

Agent management uses the `sessions:write` scope and works with an API key.

<Steps>
  <Step title="Create a draft">
    Create the agent with its prompt sections, variables, provider `config`, and tools. It starts as a `draft`.

    ```bash theme={null}
    curl -X POST "$LEHAR_BASE_URL/agent" \
      -H "X-API-KEY: $LEHAR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "id": "agent_sales_hi",
        "name": "Sales Agent",
        "objective": "You are a sales assistant for {{company}}.",
        "instruction": "Be polite, concise, and never invent prices.",
        "task": "Qualify the lead and book a callback.",
        "custom_variables": ["callee_name", "company"],
        "config": { "llm_provider": "gemini", "tts_provider": "sarvam", "speaker": "shubh" },
        "tools": []
      }'
    ```

    The response echoes the agent with read-only `status: "draft"`.
  </Step>

  <Step title="Edit until it's right">
    While `draft`, update any field with `PUT`:

    ```bash theme={null}
    curl -X PUT "$LEHAR_BASE_URL/agent/agent_sales_hi" \
      -H "X-API-KEY: $LEHAR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "instruction": "Be warm and concise. Confirm the callback time." }'
    ```
  </Step>

  <Step title="Test before publishing">
    You don't need to publish to try an agent — testing works on drafts. Fetch it, or start a [test session](/concepts/sessions) (bearer auth) and talk to it in the browser:

    ```bash theme={null}
    curl "$LEHAR_BASE_URL/agent/agent_sales_hi" -H "X-API-KEY: $LEHAR_API_KEY"
    ```

    For a WhatsApp agent, `POST /agent/{id}/whatsapp/test-reply` returns a sample reply without sending anything.
  </Step>

  <Step title="Publish">
    Publishing locks the config and makes the agent bindable by campaigns:

    ```bash theme={null}
    curl -X POST "$LEHAR_BASE_URL/agent/agent_sales_hi/publish" \
      -H "X-API-KEY: $LEHAR_API_KEY"
    ```

    The response now shows `status: "published"` and a `published_at` timestamp.

    <Warning>
      Publish is one-way. You get `422` if the agent has no `name`, and `409` if it's already published.
    </Warning>
  </Step>

  <Step title="Change it later — by cloning">
    A published agent can't be edited (`PUT` returns `409`). To change it, clone it into a fresh draft, edit, and publish the clone:

    ```bash theme={null}
    curl -X POST "$LEHAR_BASE_URL/agent/agent_sales_hi/clone" \
      -H "X-API-KEY: $LEHAR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "name": "Sales Agent v2" }'
    ```

    Then repoint your campaigns at the new agent. This guarantees a running campaign never changes underfoot.
  </Step>
</Steps>

<Note>
  Campaigns bind **only published** agents — creating or updating a campaign with a draft agent returns `400`. And a published agent can't be deleted while a campaign references it (`409`).
</Note>

<CardGroup cols={2}>
  <Card title="Run your first campaign" icon="users" href="/guides/first-campaign">Put the agent to work in bulk.</Card>
  <Card title="Make an outbound call" icon="phone-arrow-up-right" href="/guides/outbound-phone">Dial a single recipient.</Card>
</CardGroup>
