Integrations

Give agents tools from connected apps and your own MCP servers, and control which agent may use what.
View as Markdown

Jelliu agents act on other systems through tools. A voice or chat agent can look up a customer in your CRM, book on your calendar or run an automation while the conversation is still going. Those tools come from three places:

SourceWhat it isHow you set it upWhich agents get it
Connected appsCRMs, calendars, mailboxes and other business apps from Jelliu’s app catalogue, connected with the app’s own sign-in.Dashboard, IntegrationsEvery agent in the workspace, narrowed per agent with the agent settings.
Hosted automation providersZapier MCP, Make and Alegra’s MCP: presets that need only a connection token.API or dashboardAttached to every agent when you create the server.
Custom MCP serversAny Model Context Protocol server you run.API or dashboardOnly the agents you assign it to.

Information also flows the other way, from Jelliu to your systems, through webhooks and Zapier triggers.

How it works

Tools are resolved when the agent runs, on voice and on text channels alike. A tool call acts immediately with the credential of the connection, so the permissions of the connected account are the outer limit of what an agent can do there.

Connected apps

Connect apps in the dashboard under Integrations. Each app is authorized with its own sign-in or API key, and the connection belongs to the workspace.

Once an app is connected, its tools are made available to every agent in the workspace. Connecting an app is the request for your agents to use it; there is no separate step per agent. To narrow that, use per-agent access.

Connection status

The Integrations screen shows each connection’s state:

StatusMeaning
initiatedThe connection was started and is waiting for the person to finish authorizing it.
activeAuthorized. Its tools are available to agents.
failedAuthorization did not complete.
expiredThe app rejected the stored credential, for example because access was revoked on the app’s side. Reconnect it.
disabledTurned off in Jelliu. The grant may still exist in the app.

Reconnecting an app that is already connected, to refresh an expired grant, does not count as a new app against your plan.

Writing interactions back to your CRM

When a connected CRM holds the contact, Jelliu writes each finished interaction (a call or a text conversation) back to it. The result is reported to your webhooks as crm_sync.completed or crm_sync.failed:

{
"event": "crm_sync.completed",
"timestamp": "2026-09-14T15:43:11.024Z",
"data": {
"channel": "voice",
"source": { "kind": "call", "callId": "5b0d2f7e-9a41-4c3e-8f0a-2c6d1e7b9a10" },
"callId": "5b0d2f7e-9a41-4c3e-8f0a-2c6d1e7b9a10",
"conversationId": null,
"agentId": "7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4",
"campaignId": "0f3c8b52-6d1a-4e2f-9b7c-4a5e6d7f8a90",
"contactId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"results": [
{ "provider": "hubspot", "success": true, "externalId": "18273645", "error": null }
]
}
}

A write that fails temporarily is retried before it is reported, so you do not receive crm_sync.failed followed by crm_sync.completed for the same interaction. A write that was already made by an earlier attempt counts as a success. To build your own writeback instead, see CRM sync with webhooks.

Importing contacts from a CRM

Filling a campaign’s call list from a connected CRM is done in the dashboard, from the campaign’s contact import dialog. To load contacts through the API, use the campaign contacts endpoints described in Contacts.

Control access per agent

Four fields on PATCH /api/agents/{agentId} decide what an agent may do with the workspace’s connected apps and MCP servers. Apps are named by their lowercase catalogue slug, such as hubspot or gmail.

allowedToolkits
string[] | null

Which connected apps the agent may use. null (the default) means every app the workspace connects, including apps connected later. A list means exactly those apps. An empty list [] means none: the agent gets no app tools at all. Up to 300 slugs.

toolkitAccess
object | null

Read or write, per app: { "hubspot": "read", "gmail": "read_write" }. An app that is not listed, or null, keeps read_write. read restricts the agent to reading in that app.

disabledTools
object | null

Individual tools to switch off inside allowed apps, keyed by app: { "hubspot": ["HUBSPOT_DELETE_DEAL"] }. null and {} both mean nothing is disabled.

mcpEnabled
boolean

Whether the agent may carry MCP servers and app tools at all. Setting it to false also detaches every server already attached, in the same request. Setting it back to true attaches nothing; assign servers again explicitly.

curl -sS -X PATCH "https://api.jelliu.co/api/agents/7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"allowedToolkits": ["hubspot", "gmail"],
"toolkitAccess": { "gmail": "read" },
"disabledTools": { "hubspot": ["HUBSPOT_DELETE_DEAL"] }
}'

A write key is enough. Slugs are not checked against the catalogue: naming an app the workspace has not connected is harmless, because an agent only ever receives apps that are actually connected. The new tool surface is applied to the agent in the background after the update returns.

Agents that talk to anonymous people, such as a public website widget, turn whatever a visitor says into tool calls made with your business’s credentials. Give those agents allowedToolkits: [] or mcpEnabled: false unless they genuinely need a tool, and prefer read access.

Custom MCP servers

Register an MCP server once per workspace with /api/mcp-servers, then assign it to the agents that should use it.

MethodPathRequired
GET/api/mcp-serversread key
GET/api/mcp-servers/providersread key
GET/api/mcp-servers/{mcpServerId}read key
POST/api/mcp-serverswrite key
PATCH/api/mcp-servers/{mcpServerId}write key
DELETE/api/mcp-servers/{mcpServerId}write key
GET/api/agents/{agentId}/mcp-serversread key
POST/api/agents/{agentId}/mcp-serverswrite key
DELETE/api/agents/{agentId}/mcp-servers/{mcpServerId}write key

The MCP server object

FieldTypeDescription
iduuidServer id.
tenant_iduuidYour workspace.
namestringDisplay name, up to 200 characters.
descriptionstring or nullSent to the agent as the server description. Explain when to use the tools.
server_urlstringThe MCP endpoint.
transportSSE, STREAMABLE_HTTP or nullHow the voice engine connects. null leaves the engine’s default.
approval_modealways_ask, fine_grained or no_approvalWhether the agent must get approval before calling tools.
toolOverridesobjectPer-tool decisions in force, auto_approved or requires_approval.
providerzapier, make, alegra or nullDerived from the URL’s host on every read. null for a server you run.
agent_iduuid or nullSet only on rows the platform manages for one agent.
elevenlabs_mcp_idstring or nullThe server’s id at the voice engine. null if it was never registered.
created_at, updated_atISO 8601Timestamps.

The list endpoints (GET /api/mcp-servers and the per-agent list) return the same fields without toolOverrides. The secret token and custom headers are never returned by any endpoint.

Create a server

name
stringRequired

Up to 200 characters. Optional for a hosted provider, which defaults to the provider’s name.

serverUrl
stringRequired

The MCP endpoint, up to 2000 characters. It must resolve to a public address: private, internal and loopback URLs are rejected. Optional for Zapier and Alegra, whose endpoint is fixed.

secretToken
string

Sent to your server as Authorization: Bearer .... Up to 2000 characters. Stored encrypted.

customHeaders
object

Extra headers, as name/value strings. Up to 20 headers; names up to 200 characters, values up to 2000. Stored encrypted.

transport
string

STREAMABLE_HTTP or SSE. Set it to what your server actually speaks.

approvalMode
stringDefaults to always_ask

always_ask, fine_grained or no_approval. Hosted providers default to no_approval.

toolOverrides
object

Per-tool decisions, { "tool_name": "auto_approved" | "requires_approval" }. Only valid with approvalMode: "fine_grained". Up to 50 per request.

description
string

Up to 2000 characters.

provider
string

zapier, make or alegra to use a hosted provider preset.

curl -sS -X POST "https://api.jelliu.co/api/mcp-servers" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Inventory",
"description": "Stock levels and delivery dates. Use it before promising availability.",
"serverUrl": "https://mcp.example.com/mcp",
"secretToken": "your-server-token",
"transport": "STREAMABLE_HTTP",
"approvalMode": "no_approval"
}'

Response 201:

{
"data": {
"id": "e2b7c4d1-6f3a-4b8e-9c0d-1a2b3c4d5e6f",
"tenant_id": "9f0fafb4-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"agent_id": null,
"elevenlabs_mcp_id": "mcp_8Qx2Lr7Tn4Vw1Zp6",
"name": "Inventory",
"description": "Stock levels and delivery dates. Use it before promising availability.",
"server_url": "https://mcp.example.com/mcp",
"approval_mode": "no_approval",
"transport": "STREAMABLE_HTTP",
"created_at": "2026-09-14T16:00:00.000Z",
"updated_at": "2026-09-14T16:00:00.000Z",
"toolOverrides": {},
"provider": null
}
}

Creating a server registers it with the voice engine before anything is saved. If registration fails, nothing is created and the API answers 502 with code MCP_SYNC_FAILED.

When you send toolOverrides and some of them could not be applied, the server is still created, the response status is 207, and a toolOverridesSync object (synced, removed, failed, failures) sits next to data. Only the decisions that were applied are stored.

Match the transport. A server registered with the wrong transport looks healthy and never answers a tool call. If yours only speaks streamable HTTP, send "transport": "STREAMABLE_HTTP". You can fix it later with PATCH, which re-registers the server and keeps its id and assignments.

Approval modes and per-tool decisions

approvalModeBehaviour
always_askThe agent asks for approval before every tool call. The default for servers you run.
fine_grainedEach tool follows its entry in toolOverrides.
no_approvalEvery tool runs without asking. The default for hosted providers.

There is no per-tool off switch. toolOverrides accepts auto_approved and requires_approval; sending disabled is refused with 400:

The voice engine has no per-tool off switch (only auto_approved / requires_approval). To stop an agent using create_invoice, detach this MCP server from the agent instead.

Per-tool decisions with any mode other than fine_grained are also refused, because they would have no effect:

Per-tool decisions only apply when the server's approval mode is 'fine_grained'; this one is 'always_ask'. Set approvalMode to fine_grained in the same request, or drop the per-tool decisions.

To stop an agent using a server’s tools, remove the server from the agent or delete the server.

Update and delete

PATCH /api/mcp-servers/{mcpServerId} accepts name, description, serverUrl, secretToken, customHeaders, approvalMode, toolOverrides and transport. Send at least one field, otherwise the response is 400 with At least one field must be provided. Changing serverUrl or transport re-registers the server with the voice engine; the id and agent assignments are kept.

DELETE /api/mcp-servers/{mcpServerId} first detaches the server from every agent, then deletes it, and answers 204. If one agent cannot be detached, the delete is refused with 502 MCP_SYNC_FAILED and the server stays in place, so no agent is left pointing at a server that no longer exists. Retry after a moment.

Assign servers to agents

A custom server does nothing until you assign it to an agent.

curl -sS -X POST "https://api.jelliu.co/api/agents/7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4/mcp-servers" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "mcpServerId": "e2b7c4d1-6f3a-4b8e-9c0d-1a2b3c4d5e6f" }'

Response 201. This endpoint answers with a message rather than a data object:

{ "message": "MCP server assigned to agent" }

The assignment is pushed to the voice engine in the same request. If that fails, the assignment is rolled back and the error is returned, so a 201 means the agent really has the server.

  • GET /api/agents/{agentId}/mcp-servers lists the servers on an agent, in the list shape above. It can include Jelliu’s own tool gateway (mcp.jelliu.co), which the platform manages.
  • DELETE /api/agents/{agentId}/mcp-servers/{mcpServerId} removes one server from the agent and answers 204.

Hosted automation providers

Zapier MCP, Make and Alegra’s MCP have fixed connection facts, so Jelliu offers them as presets. You supply the token; Jelliu sets the transport and approval mode, and attaches the server to every agent as soon as it is created.

GET /api/mcp-servers/providers returns the catalogue:

providerEndpointCredentialNotes
zapierFixed: https://mcp.zapier.com/api/v1/connectsecretToken: the connection token from https://mcp.zapier.comYour agents act in the apps you connected to Zapier. Each tool call runs in your Zapier account.
makeRequired serverUrl: Make hosts per region, for example https://eu1.make.com/mcp/statelesssecretToken: an MCP token from MakeExposes the scenarios you published as on-demand tools.
alegraFixed: https://mcp.alegra.com/mcpsecretToken: usuario:token, sent as HTTP BasicYour Alegra accounting, including writes.

All three use STREAMABLE_HTTP; sending another transport is refused. A token is required:

Zapier needs the connection token from https://mcp.zapier.com

curl -sS -X POST "https://api.jelliu.co/api/mcp-servers" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "provider": "zapier", "secretToken": "'"$ZAPIER_MCP_TOKEN"'" }'

If you paste a provider URL that carries the token (Zapier’s ?token= variant, or Make’s /u/TOKEN/ path), Jelliu moves the token out of the URL into the encrypted secret, so it is never stored or displayed as part of the address. The same provider rules apply when you register a provider URL without setting provider.

When you later PATCH a provider server, clearing its token is refused (Zapier needs its connection token; rotate it instead of clearing it). Send the new token instead.

Errors

StatusCodeWhen
400VALIDATION_FAILEDInvalid body or id; a private or internal URL; a missing name, URL or provider token; disabled or non-fine_grained tool overrides; more than 50 overrides in one request.
403BILLING_ERRORThe agent already has as many MCP servers as the plan allows, for example MCP servers per agent limit reached (1 on the starter plan). Upgrade your plan in Settings → Plan for more.
403FORBIDDENAssigning to an agent whose tools are disabled: Este agente tiene las herramientas MCP desactivadas; actívalas en el agente antes de asignar un servidor. Or assigning a server the platform manages for a different agent.
404AGENT_NOT_FOUNDThe agent does not exist in your workspace.
404MCP_SERVER_NOT_FOUNDThe server does not exist in your workspace, or is managed by the platform.
409MCP_ALREADY_ASSIGNEDMCP server is already assigned to this agent.
409AGENT_PROVISIONINGAgent is still being configured — try assigning MCP servers in a few seconds. Retry after Retry-After.
502MCP_SYNC_FAILEDThe voice engine rejected or did not answer a registration, update, assignment or delete.

See Errors for the envelope and validation details.

Limits

MCP servers per agent, not counting Jelliu’s own tool gateway:

PlanServers per agentConnected apps per workspace
Starter12
Growth35
Business1010
EnterpriseUnlimitedUnlimited

Re-assigning a server that is already on the agent never counts against the cap.

Rate limits. The MCP server and assignment endpoints use the general per-workspace limit (see Rate limits). PATCH /api/agents/{agentId} shares the 10-per-minute budget for configuration changes.

The /api/integrations endpoints in the API reference predate the app catalogue. CRMs such as HubSpot, Salesforce or Pipedrive are no longer connected through them: creating one there saves an integration in error status with last_error set to, for example, hubspot ya no se conecta por aquí: conéctalo desde el catálogo de aplicaciones. Connect CRMs from Integrations in the dashboard.