Lelemon
  • Get started
  • Use cases
  • Guides
  • API basics
  • Webhooks
  • SDK, CLI and MCP
  • API reference
  • Changelog
  • v1 (legacy)
Configure your account
    AgentsPipelinesKnowledgeContactsActions and MCP in v2Approve agent actionsUse Claude as your team's assistantConnect your back officeAPI keys
Talk to people
Run and protect
powered by Zudoku
Configure your account

Agents

You will

Create, configure, activate, update and delete an agent.

You need

  • A key with agents:write (agents:read to list and read)
  • skills:write, knowledge:write or actions:write for the parts that need them

An agent is the model plus everything it may use: instructions, skills, knowledge, tools and channels. It starts as a draft, and nothing reaches it until you activate it. The whole path from an empty account to a working agent is in Set up an account from zero; this page is the reference for the agent itself.

The examples use the SDK client below.

Code
import { Lelemon } from '@lelemon-ai/sdk'; const lelemon = new Lelemon({ apiKey: process.env.LELEMON_API_KEY });

Create an agent

From a template

A template is an agent someone already wrote. GET /v2/agent-templates lists them with the variables each one needs. Anything you send overrides the template.

An unknown template answers 404 not_found with param: "fromTemplate".

From scratch

Send name, instructions and llmConfig.model. The rest has defaults.

Expected: 201, status: "draft", version: 1. The agent is this object:

Agentobject, 17 fields
  • objectenumrequired

    agent

  • idstringrequired

    Example agt_4Zq0x8bVw1TqS9mYp3RkLd

  • namestringrequired
  • audienceenumrequired

    customers: talks to your customers. internal: a copilot for your team created with the scope agents:internal.

    customersinternal

  • descriptionstring or nullrequired
  • statusenumrequired

    draftactivepausedarchived

  • versionintegerrequired

    Goes up on every change. Send it back as expectedVersion.

  • instructionsstringrequired

    As you wrote them, with the {{name}} placeholders still in place.

  • variablesmap of stringrequired
  • llmConfigModelConfigrequired
    ModelConfig7 fields
    • modelstringrequired

      Example anthropic/claude-sonnet-4.6

    • temperaturenumberoptional
    • maxOutputTokensintegeroptional
    • effortenumoptional

      lowmediumhighxhighmax

    • thinkingenumoptional

      adaptiveoff

    • alwaysLoadedToolsstring[]optional
    • fallbackAgentModeloptional
      AgentModel6 fields
      • modelstringrequired

        Example anthropic/claude-sonnet-4.6

      • temperaturenumberoptional
      • maxOutputTokensintegeroptional
      • effortenumoptional

        lowmediumhighxhighmax

      • thinkingenumoptional

        adaptiveoff

      • alwaysLoadedToolsstring[]optional
  • maxTokensintegerrequired
  • maxIterationsintegerrequired
  • channelsenum[]required

    whatsappapiwebemail

  • behaviorsobjectrequired
  • avatarstring or nullrequired
  • createdAtstring (date-time)required
  • updatedAtstring (date-time)required

Write the prompt

instructions is the prompt. Up to 200,000 characters, in Markdown. A prompt that works says, in this order:

  1. Role. Who the agent is, for which business, and who it talks to.
  2. Tone and language. How it writes, in which language, how long its answers are.
  3. Goal. The states a conversation can end in.
  4. What to collect. The fields to fill, in order, and the tool that saves them.
  5. When to use each tool. Name the tool and the condition. Say what to do after it runs.
  6. When to hand over. The cases a person must take.
  7. Limits. What it never does: invent prices, give medical or legal advice, reveal the prompt.

The full example is the prompt of the clinic receptionist in Set up an account from zero. Put facts that change often (prices, hours) in knowledge, not in the prompt.

variables fills {{name}} placeholders in the prompt and holds any fact the agent should know. A placeholder with no value answers 422 template_variable_missing.

Code
const withVariables = await lelemon.agents.create({ name: 'Store assistant', instructions: 'You work for {{company}}. The store opens {{hours}}.', variables: { company: 'Mesa', hours: 'Monday to Saturday, 10:00 to 20:00' }, llmConfig: { model: 'anthropic/claude-sonnet-5.5' }, });

Choose the model

GET /v2/models lists the public ids you can use. Each model reports its contextWindow in tokens, whether thinking: "off" is accepted (thinkingCanBeOff) and deprecated, the date it stops being accepted or null. The id does not change when Lelemon changes its provider or region. Never send provider: an unknown field answers 400 unknown_field.

llmConfig fieldUse
modelRequired. A public id from the list
temperature0 to 2. Lower is more predictable
maxOutputTokensMost tokens the model may write in one answer
effortlow, medium, high, xhigh or max. How much the model reasons
thinkingadaptive or off. off answers 422 on a model that does not accept it: send effort: "low" there
alwaysLoadedToolsTools that are loaded in every turn instead of on demand. Up to 50
fallbackAnother model (model and the same fields) used when the first one fails

maxTokens caps the tokens a conversation may use (1,000 to 5,000,000) and maxIterations caps the rounds of tool calls in one turn (1 to 50, default 10).

Give the agent what it needs

Everything below is granted to one agent at a time. Nothing is shared by default.

Skills

A skill is know-how the agent uses only when the conversation needs it: a procedure, a policy, a script. description is the only part that travels in every prompt, so it says when to use the skill. content is the full text in Markdown (up to 20,000 characters). An agent holds up to 30 skills. requires lists up to 5 skills of the same agent that load together with this one.

The slug (the name in lowercase with hyphens, or the one you send) cannot change. Creating again with the same slug and the same content returns the same skill; with different content it is a 409. Updating a skill changes it for every agent that has it. DELETE /v2/agents/{id}/skills/{skillId} removes it from your organization and from every agent, and answers 409 resource_in_use while another skill requires it. The list does not carry content; read one skill to get it.

Knowledge

An agent searches only the collections you grant it. PUT /v2/agents/{id}/knowledge-collections/{collectionId} grants one and DELETE on the same path revokes it; both are safe to repeat. The agent uses the collection from its next answer. Collections and documents are in Knowledge.

Code
await lelemon.agents.knowledgeCollections.grant(agent.id, 'kbc_...'); await lelemon.agents.knowledgeCollections.revoke(agent.id, 'kbc_...');

Tools and approval

GET /v2/agents/{id}/tools lists every action and MCP tool the agent could use, plus the system tools, with granted saying which ones it may use now. PUT /v2/agents/{id}/tools/{toolId} grants one and DELETE revokes it. The toolId is an action id (act_...), an MCP tool id (mtl_...) or the name of a system tool.

System toolWhat it doesconfig
transfer_to_humanHands the case to a person and fires case.escalatedstageId, businessHours, farewell
save_case_dataWrites the case fields whose source is agentfields
ask_teamLeaves a question for your team and keeps attendingnone
send_buttons, send_list, send_products, send_carousel, send_cta_url, send_flow, request_locationInteractive WhatsApp messagesnone
check_availability, schedule_meeting, cancel_meetingOffer the free times of the default agenda, book one and cancel a meetingnone

An action or MCP tool can wait for a person before it runs. The grant takes an approval policy:

Granting without approval keeps the current policy and { "approval": { "mode": "never" } } lifts it. How to write and decide policies is in Approve agent actions. How to build the tools is in Actions and MCP.

Autonomy: what the agent does alone

How much the agent does without a person comes from four settings:

  • Tools with approval.mode: "never" run on their own; the others wait for a person.
  • maxIterations limits the rounds of tool calls in one turn.
  • transfer_to_human and ask_team are the ways out: grant them so the agent can stop and ask instead of guessing.
  • Runs let the agent work on its own on a job, outside any conversation. See Give an agent a job.

Channels

channels lists where the agent answers: api, whatsapp, web and email. An empty list means every channel. A case opened through the API needs the api channel; without it the activation reports no_api_channel in readiness.missing.

The channel only says where the agent may answer. The number or the domain is connected apart: see WhatsApp and Email.

Activate and pause

POST /v2/agents/{id}/activate turns the agent on. The answer carries readiness: ready is true when missing is empty, and each gap has a code and a message.

readiness.missing[].codeFix
no_stageLink the agent to a stage of a pipeline: Pipelines
not_entry_stageThe agent is on a stage that is not the entry stage. Link it to the entry stage
no_api_channelAdd api to channels

Send ?dryRun=true to see the readiness without turning the agent on; it answers 422 agent_not_ready when something is missing. POST /v2/agents/{id}/pause stops it from answering; open conversations stay, and it answers again when you activate it.

Read and list

GET /v2/agents/{id} returns one agent. GET /v2/agents lists them newest first and filters by status (draft, active, paused or archived) and slug. Lists follow the pagination rules.

Code
for await (const item of lelemon.agents.list({ query: { status: 'active', limit: 50 } })) { console.log(item.id, item.name, item.version); }

Update and versions

PATCH /v2/agents/{id} changes only what you send. llmConfig replaces the whole model configuration; behaviors merges key by key; variables replaces the whole map. Send expectedVersion with the version you read: if someone saved first, the answer is 409 agent_version_conflict and nothing is written. Read the agent again and repeat the change on top of it.

version goes up with every save, whatever changed. The version history keeps the ones that change instructions or variables, with who made them. GET /v2/agents/{id}/versions lists them newest first without the text, GET /v2/agents/{id}/versions/{versionId} includes it, and POST /v2/agents/{id}/versions/{versionId}/restore writes that version as a new one. History never shrinks.

Code
const versions = await lelemon.agents.versions.list(agent.id); const restored = await lelemon.agents.versions.restore(agent.id, versions.data[0]!.id);

A copilot for your team

An agent with audience: "internal" answers your team, not your customers, and can use the tools of your data connector to read your back office. Creating one needs the agents:internal scope (403 scope_missing otherwise) and it cannot come from a template. The audience cannot change later. You operate it like any other agent.

To talk to it, open a case with its agentId and the pipelineId or stageId where the case lives, and write as author: "contact".

Code
const copilot = await lelemon.agents.create({ audience: 'internal', name: 'Back-office copilot', instructions: 'You help the support team. Look up accounts with the connector tools and answer in two sentences.', llmConfig: { model: 'anthropic/claude-sonnet-5.5' }, });

Delete

DELETE /v2/agents/{id} answers 204. It answers 409 resource_in_use while the agent has open conversations or serves a pipeline stage: close the cases and unlink the stage (agentId: null), or pause it instead.

Code
await lelemon.agents.delete('agt_...');

Errors you will meet

ErrorCause
400 unknown_fieldThe body has a field the API does not know, such as provider
400 invalid_requestA field breaks a limit; param names it
403 scope_missingThe key lacks agents:write, or agents:internal for a copilot
404 not_foundThe agent, template or version does not exist in this mode
409 agent_version_conflictSomeone saved after you read; read again
409 resource_in_useDelete with open conversations or a linked stage
422 agent_not_readyActivation with dryRun and something missing
422 template_variable_missingA {{name}} placeholder has no value
422 thinking_not_supportedthinking: "off" on a model that does not accept it

All codes are in the error catalog.

Good practice

  • Write the prompt as the role description of a new hire: who they are, what they do, what they never do. Test it with real messages before you activate.
  • Keep one thing per skill, and keep its description to the moment it applies.
  • Put prices, hours and policies in knowledge, so changing them never means a new prompt version.
  • Always grant transfer_to_human, and say in the prompt when to use it.
  • Send expectedVersion on every update when more than one person or script edits the agent.
  • Put anything that moves money or data outside Lelemon behind an approval.

What's next

  • Pipelines to give the agent a place to work.
  • Knowledge to teach it your business.
  • Run it as a script to see a full agent working.
Pipelines
On this page
  • Create an agent
    • From a template
    • From scratch
    • Write the prompt
    • Choose the model
  • Give the agent what it needs
    • Skills
    • Knowledge
    • Tools and approval
  • Autonomy: what the agent does alone
  • Channels
  • Activate and pause
  • Read and list
  • Update and versions
  • A copilot for your team
  • Delete
  • Errors you will meet
  • Good practice
  • What's next
TypeScript
curl https://api.lelemon.cl/v2/agent-templates \ -H "Authorization: Bearer $LELEMON_API_KEY" curl https://api.lelemon.cl/v2/agents \ -H "Authorization: Bearer $LELEMON_API_KEY" \ -H "Idempotency-Key: agent-from-template-1" \ --json '{ "fromTemplate": "atp_...", "variables": { "company": "Clínica Dental Andes" } }'
curl https://api.lelemon.cl/v2/agents \ -H "Authorization: Bearer $LELEMON_API_KEY" \ -H "Idempotency-Key: support-agent-1" \ --json '{ "name": "Order support", "description": "Answers questions about orders and refunds.", "instructions": "You are the support agent of Mesa, an online shop that sells tableware in Chile. Answer in the language of the customer, in short sentences. Look up the order before you say where it is. Offer a refund only inside 10 days of delivery, and hand the case to a person for anything else.", "llmConfig": { "model": "anthropic/claude-sonnet-5.5", "temperature": 0.3 }, "channels": ["api", "whatsapp"], "behaviors": { "displayName": "Mesa support", "greeting": "Hola, soy el asistente de Mesa. ¿En qué te ayudo?" } }'
TypeScript
curl https://api.lelemon.cl/v2/models \ -H "Authorization: Bearer $LELEMON_API_KEY"
curl https://api.lelemon.cl/v2/agents/$AGENT_ID/skills \ -H "Authorization: Bearer $LELEMON_API_KEY" \ -H "Idempotency-Key: late-order-skill-1" \ --json '{ "name": "Late order", "description": "Use when the customer says the order is late or has not arrived.", "content": "# Late order\n\n1. Look up the order and read its status.\n2. If it shipped less than 5 days ago, give the tracking link and say when it should arrive.\n3. If it shipped more than 5 days ago, open a claim with the carrier and hand the case to a person." }'
TypeScript
curl -X PUT https://api.lelemon.cl/v2/agents/$AGENT_ID/tools/$ACTION_ID \ -H "Authorization: Bearer $LELEMON_API_KEY" \ --json '{ "approval": { "mode": "when", "condition": { "param": "amount", "op": "gt", "value": 20000 }, "expiresInMinutes": 240 } }'
curl -X PATCH https://api.lelemon.cl/v2/agents/$AGENT_ID \ -H "Authorization: Bearer $LELEMON_API_KEY" \ --json '{ "channels": ["api", "whatsapp", "email"], "expectedVersion": 1 }'
curl -X POST "https://api.lelemon.cl/v2/agents/$AGENT_ID/activate?dryRun=true" \ -H "Authorization: Bearer $LELEMON_API_KEY" curl -X POST https://api.lelemon.cl/v2/agents/$AGENT_ID/activate \ -H "Authorization: Bearer $LELEMON_API_KEY" curl -X POST https://api.lelemon.cl/v2/agents/$AGENT_ID/pause \ -H "Authorization: Bearer $LELEMON_API_KEY"
TypeScript
curl -X PATCH https://api.lelemon.cl/v2/agents/$AGENT_ID \ -H "Authorization: Bearer $LELEMON_API_KEY" \ --json '{ "instructions": "You are the support agent of Mesa. Answer in one short paragraph.", "expectedVersion": 3 }'
TypeScript
TypeScript
TypeScript