Lelemon
  • Get started
  • Use cases
  • Guides
  • API basics
  • Webhooks
  • SDK, CLI and MCP
  • API reference
  • Changelog
  • v1 (legacy)
Configure your account
Talk to people
Run and protect
    Give an agent a jobSchedule a jobTrack usage and cap spendingRun Lelemon for your customersKeep tool data out of storageErase a contact or a messageBest practicesMoving from v1
powered by Zudoku
Run and protect

Run Lelemon for your customers

This guide is for platforms such as a POS, a CRM or a booking app. Your organization is the platform. Each of your customers is a subaccount: a full organization with its own agents, pipelines, cases, numbers and keys, isolated from your other subaccounts. Your platform pays for all of them.

You will

Create a subaccount per customer, act on it with your own key, connect its WhatsApp number and receive its events.

You need

  • A key with subaccounts:write
  • Your own customer id to use as externalRef
Your platformone keyLelemonSubaccountsub_...POST /v2/subaccountsexternalRef: restaurant-10421sub_...2GET /v2/agentsLelemon-Subaccount: sub_...3Isolated organizationits own agents, pipelines, numbers4sharedWithSubaccounts: trueone action, every customer5Shared action callLelemon-Subaccount-Id: sub_...6Events with customerIdwebhook endpoint scope: customers7
One key, many customers. The Lelemon-Subaccount header picks the organization a call acts on, and a shared tool tells your backend which customer is asking.
  1. When your customer signs up, create the subaccount with your own id as externalRef and an Idempotency-Key.
  2. Lelemon answers with the sub_ id. A second subaccount with the same externalRef is a 409 external_ref_conflict.
  3. Any /v2 route acts on the subaccount when you add the header. The key does not change, only the organization.
  4. A subaccount is a full organization, isolated from your other subaccounts. One that is not yours answers 404.
  5. You create a tool once in your organization and share it. Each subaccount grants it to its own agents.
  6. When an agent of a subaccount uses the shared tool, your backend receives a call signed with your secret and Lelemon-Subaccount-Id, so it knows which customer is asking.
  7. One webhook endpoint with scope customers receives the events of all subaccounts. Each carries customerId, the sub_ id it belongs to.

1. Create the subaccount when your customer signs up

Send your own id as externalRef so you never need a lookup table. fromTemplates copies draft agents and pipelines: agent ids come from GET /v2/agent-templates (Lelemon's templates and the ones you saved from the dashboard; leave agents out when it comes back empty) and pipeline ids from GET /v2/pipelines.

A subaccount is this object:

Subaccountobject, 7 fields
  • objectenumrequired

    subaccount

  • idstringrequired

    Example sub_4Zq0x8bVw1TqS9mYp3RkLd

  • externalRefstringrequired

    Example local-1042

  • namestringrequired

    Example Cafe Central

  • createdAtstring (date-time)required
  • updatedAtstring (date-time)required
  • createdSubaccountCreatedResourcesoptional

    Only on create: what fromTemplates made.

    SubaccountCreatedResources2 fields
    • agentsstring[]required
    • pipelinesstring[]required

Store the sub_... id next to your customer. If you lose it, GET /v2/subaccounts?externalRef=restaurant-1042 finds it.

externalRef is unique among your subaccounts: a second subaccount with the same value answers 409 external_ref_conflict. Use your customer's stable id, never an email, which can change.

The key you use needs subaccounts:write.

2. Act on it with your own key

Add the Lelemon-Subaccount header to any /v2 route. The key does not change, only the organization it acts on.

A subaccount that is not yours, or was deleted, answers 404, the same as one that never existed. /v2/subaccounts itself rejects the header with 400.

3. Connect their WhatsApp number

Create a connection link and show setupUrl as a button in your product. Your customer confirms the number in Meta and never opens Lelemon.

Use coexistence when your customer keeps using the WhatsApp Business app on that number, and dedicated for a number only the agent uses. When the link completes you receive phone_number.connected. A number belongs to the subaccount that connected it, and the agent that answers on it is routed to the entry stage of one of its pipelines.

A subaccount can have several pending links at once, one per phone, so you can connect every branch in parallel. Asking again for a phone that already has a pending link answers 409 resource_in_use. When a number is linked, Lelemon matches it to the pending link by the phone you asked for. A number that matches none of them is detached and ignored. Name each number with PATCH /v2/whatsapp/phone-numbers/{id} and { "label": "Branch Centro" }. Business hours and time zone belong to the organization, not to a number: the route does not set them.

4. One webhook endpoint for every subaccount

Create an endpoint with "scope": "customers" to receive the events of all your subaccounts. Each event carries customerId, the sub_... id it belongs to.

An endpoint with "scope": "self" receives the events of the platform organization only.

Tools inside each subaccount

Each customer can have its own agent with tools that only reach that customer's systems.

  • Your key creates them. POST /v2/actions and POST /v2/mcp-servers with Lelemon-Subaccount create the tool inside the subaccount. The site of the tool must be one of the allowedActionOrigins of your key.
  • Its key creates them. A subaccount key can hold actions:write. Give it sites with allowedActionOrigins when you create it. They must be sites of your own key. If you leave them out, the key gets the same sites as yours.
  • Isolation. An action or an MCP server belongs to one subaccount. Another subaccount, and you without the header, do not see it, change it or delete it.

Share a tool with all your subaccounts

Create the tool once in your organization with "sharedWithSubaccounts": true, or turn it on later with PATCH /v2/actions/{id}. Then:

  • GET /v2/agents/{id}/tools for an agent of a subaccount lists it with sharedByPlatform: true, and PUT /v2/agents/{id}/tools/{toolId} grants it.
  • The call to your system is signed with your signing secret and carries Lelemon-Subaccount-Id, so your backend knows which customer is asking. Verify it with verifyRequest of the SDK.
  • A subaccount cannot read, change or delete it, and cannot create a tool with the same name. You cannot share a tool whose name a subaccount already uses.
  • Turning sharing off, or deleting the action, removes it from the agents of your subaccounts.
  • Only a platform can share. A subaccount that sends sharedWithSubaccounts answers 422.

Share an MCP server with all your subaccounts

An MCP server works the same way. Connect it in your organization with "sharedWithSubaccounts": true in POST /v2/mcp-servers, or turn it on later with PATCH /v2/mcp-servers/{id}. Then:

  • GET /v2/mcp-servers in a subaccount lists it with sharedByPlatform: true, and GET /v2/agents/{id}/tools lists its tools with kind: "mcp_tool" and sharedByPlatform: true. PUT /v2/agents/{id}/tools/{toolId} grants them.
  • The calls go out to your server with your credentials. When you turned on the run identity of the server, each call carries the signed context of the subaccount that made it, so your server knows which customer is asking.
  • A subaccount can read it and grant its tools, but cannot change it, discover its tools again or delete it. It cannot connect a server whose name starts like a shared one, and you cannot share a server whose name starts like one a subaccount already has.
  • Turning sharing off, or deleting the server, removes its tools from the agents of your subaccounts.
  • Only a platform can share. A subaccount that sends sharedWithSubaccounts answers 422.

Keys inside a subaccount

POST /v2/subaccounts/{id}/api-keys issues a key that sees only that subaccount. Its scopes cannot exceed those of the key that created it and cannot include subaccounts:*. A subaccount key cannot use Lelemon-Subaccount or manage subaccounts. The response holds the secret, so it is never replayed from the idempotency cache.

With actions:write, the key also takes allowedActionOrigins, a subset of the sites of your own key. A site you do not have answers 403 with param: allowedActionOrigins, and sites without actions:write answer 400.

When a customer leaves

DELETE /v2/subaccounts/{id} closes the subaccount.

Track usage and cap spendingKeep tool data out of storage
On this page
  • 1. Create the subaccount when your customer signs up
  • 2. Act on it with your own key
  • 3. Connect their WhatsApp number
  • 4. One webhook endpoint for every subaccount
  • Tools inside each subaccount
    • Share a tool with all your subaccounts
    • Share an MCP server with all your subaccounts
  • Keys inside a subaccount
  • When a customer leaves
curl https://api.lelemon.cl/v2/subaccounts \ -H "Authorization: Bearer $LELEMON_API_KEY" \ -H "Idempotency-Key: create-sub-1042" \ --json '{ "name": "Picá Don Lucho", "externalRef": "restaurant-1042" }'
curl https://api.lelemon.cl/v2/agents \ -H "Authorization: Bearer $LELEMON_API_KEY" \ -H "Lelemon-Subaccount: sub_..."
curl https://api.lelemon.cl/v2/whatsapp/connections \ -H "Authorization: Bearer $LELEMON_API_KEY" \ -H "Lelemon-Subaccount: sub_..." \ -H "Idempotency-Key: connect-1042" \ --json '{ "phone": "+56912345678", "agentId": "agt_...", "connectionType": "coexistence" }'
curl https://api.lelemon.cl/v2/webhook-endpoints \ -H "Authorization: Bearer $LELEMON_API_KEY" \ --json '{ "url": "https://example.com/lelemon", "enabledEvents": ["*"], "scope": "customers" }'
curl https://api.lelemon.cl/v2/actions \ -H "Authorization: Bearer $LELEMON_API_KEY" \ -H "Lelemon-Subaccount: sub_..." \ --json '{ "name": "find_order", "description": "Finds the order of the customer in the store.", "request": { "method": "POST", "url": "https://erp.example.com/lelemon/find-order" }, "input": { "type": "object", "properties": { "orderNumber": { "type": "string" } } } }'