Skip to content
PATCH /template/{id}

**`entries` REPLACES the entire entry list when present** — omitted entries are deleted. Omitting `entries` altogether leaves them untouched; `name`/`description` are ordinary merge-patch fields. Toolboxes already stamped from this template are UNTOUCHED (stamping copies entries and the skill once). `skill` is an ordinary field too: a write clears `skill_may_be_stale`, and an `entries` write sets it when a skill exists and the same request did not also write `skill`. Every skill edit is audited on `template.updated` (`metadata.skill`: `written`/`reaffirmed`/`cleared`, plus `metadata.skill_version_id`, never the text) and kept in `GET /template/{id}/skill-version`. Requires `edit` access or ownership (own grant) — no `template:manage` fallback; a `view`/`use` grantee reads the skill and gets `403` writing it. An `entries` write answers the same non-empty `warnings` array as create for a pin on a remote MCP tool the server is not offering right now (no connection lists it yet).

Path Parameters

idstring
required·

Template id (tpl_…).

Request Body

descriptionstring,null
entriesobject[]

Replaces every entry.

connector_slugstring,null

Connector slug — connectors are keyed by slug, not by id.

enabledboolean
frozen_paramsRecord<string, any>

Arguments pinned by the author. Unlike overrides.defaults, a caller cannot change these.

idstring,null

Optional identity hint (tbxe_… on a toolbox, tple_… on a template): the id of a row this resource already has. On PATCH /toolbox/{id} and PATCH /template/{id} a row echoed back with its own id keeps it, so a client that keys per-row state by entry id (a switch mid-save) is not orphaned by the replacement. It is a hint, never an assertion: an id that is not one of THIS resource's current rows, is repeated, or would put the row out of stored order (rows list in id order) is ignored and the row gets a fresh id — and so is a value that is not a usable string (not a string, or over 200 characters). Never a 400, and never adopted from another resource. Omit it for a new row. Ignored on create.

overridesobject

How the tool is presented to the model. Each key REPLACES the derived value.

4 properties
defaultsRecord<string, any>

Default argument values the caller may still override.

descriptionstring
input_schemaRecord<string, any>

Must be a JSON Schema object with "type": "object". Replaces the derived schema entirely.

namestring
synthetic_tool_idstring,null

Required for synthetic entries (syn_…).

tool_namestring,null

Exact tool name from GET /connector/{slug}/tools.

typestring

Defaults to proxy.

Possible values:
proxysynthetic
namestring
skillstring,null

Markdown guidance on how to use these tools well. Trimmed, then capped at 10,000 Unicode code points (an emoji counts once) — longer is a 400 naming the limit, never a silent cut. null or an empty string clears it; omit the key to leave it unchanged. The resource's description is the one-line "when to use this" shown beside it, so write that too. Moderated like the description.

Response Body

access_levelstring

The caller's access: owner, or a granted view/use/edit level. Templates carry no organization-wide oversight path — an org owner/admin sees a template only when they own it or it has been shared with them, same as any other member.

access_summaryobject

Present on a GET /template row exactly when that row's can_see_shares is true — the caller owns it, holds edit, or administers a team it is granted to. Same gate and same reasoning as the toolbox row's.

org_levelstring,null

Level of the org-wide grant, or null when there is none.

Possible values:
viewuseeditnull
previewobject[]

At most 5 grantees, broadest first (org, then teams, then members), for a hover preview.

4 properties
grantee_idstring,null
grantee_typestring
Possible values:
userteamorg
levelstring
Possible values:
viewuseedit
namestring,null

Display name; null for org grants and for grantees no longer in the org.

team_countinteger
totalinteger

Every grant, the org-wide one included.

user_countinteger
access_viastring

How the CALLER reaches this template — not who else can. owner — they own it. direct — a grant naming them personally. team — a grant to a team they belong to (or, per §6.2, one they administer), named in access_via_team. org — an organization-wide grant. When several sources apply the BROADEST wins and the caller's access level is not consulted: owner, else org, else team, else direct. So a caller granted edit personally AND view org-wide reads org — a narrower grant must never mask org-wide exposure, since this field says how far the template reaches, not what the caller may do with it. Deliberately NOT gated on can_see_shares, and deliberately not a widening of it: this is the caller's OWN grant and their OWN team memberships, so a view/use grantee receives it while the grantee list — information about colleagues — stays closed to them. No other member is ever named. ABSENT when nothing reaches the caller — a transfer answering the ex-owner of a resource that was never shared, or a catalog row browsed with no grant behind it. Absent means "no source to name", never "not permitted", and never an implied org.

Possible values:
ownerdirectteamorg
access_via_teamobject

Present exactly when access_via is team, absent otherwise. The team the caller reaches this template through — one of their own teams, never a disclosure about anybody else.

idstring

Team id (team_…).

namestring,null

Team display name, or null when the team no longer resolves in the directory — the same null contract every resolved grantee name carries.

can_draft_skillboolean

Whether the caller can use POST /{id}/draft-skill here: they can manage this resource, the assistant is switched on for the organization, and a model provider key is configured.

can_manageboolean

Whether the caller may edit this template's own settings — owner, or edit access. No template:manage fallback. Mirrors PATCH /template/{id}.

can_revoke_shareboolean

can_share, verbatim — a THIRD formula, distinct from can_manage: an edit grantee whose role omits template:share can edit the template but was never meant to grant or revoke someone else's access to it. Mirrors DELETE /template/{id}/share/{aclId}.

can_shareboolean

Whether the caller may share this template — owner, edit access, or template:share. No template:manage fallback. Mirrors POST /template/{id}/share's own check.

can_transferboolean

Whether the caller may transfer or delete this template — ownership, full stop. No template:manage fallback. Mirrors POST /template/{id}/transfer and DELETE /template/{id}.

can_useboolean

Whether the caller may stamp a toolbox from this template — the caller's grant-or-ownership level (§10). Present on every list and detail row for both templates and toolboxes — the two ACL-backed resource types with a use-gated action of their own.

connectorsobject

Which integrations this template's tools come from, bounded — the console renders it as a stack of connector logos, exactly as on a toolbox row. Present on every GET /template row AND on every command response (POST /template, GET /template/{id}, PATCH /template/{id}, POST /template/{id}/transfer), so a client that merges a command response into its list does not lose the stack. total: 0 means no connector-backed tools (empty, or synthetic-only), never "not computed".

previewobject[]

At most 5 connectors, ordered by entry count descending then slug ascending — the dominant integration leads and the order is stable across requests. Each entry arrives resolved: there is no follow-up GET /connector/{slug} to make, and a page of rows costs no per-row catalog lookup.

3 properties
logostring,null

The connector's square icon when it has one, else its wordmark logo, else null (the connector carries neither picture, or could not be resolved). Draw it in a square tile; render initials from name when it is null.

namestring

Catalog label. Falls back to the slug when the connector no longer resolves (deleted from the catalog), so a row always has something to draw.

slugstring

Connector slug — connectors are keyed by slug, not by id.

totalinteger

Distinct connector slugs across the template.

created_atstring · date-time
descriptionstring,null
draft_skill_blocked_bystring,null

Why can_draft_skill is false for a caller who CAN manage this resource. Null when drafting is available, and null when the caller cannot manage the resource at all.

Possible values:
assistant_disabledllm_not_configurednull
entriesobject[]
connectorobject,null
required·

Response-only. The connector's label and logo, one batch per response; null for a synthetic entry. A connector the catalog cannot resolve reads its slug as label and a null logo.

3 properties
labelstring
logostring,null
upstream_slugstring

Only on a fork (an org-owned connector with a lineage) whose upstream the caller may see — the GET /connection rule: omitted when the caller has no reach on the fork or the upstream is hidden from them, and when the lineage cannot be read.

can_view_connectorboolean

Response-only, per READER: may the caller open connector_slug (GET /connector/{slug} and its /tools)? False for an organization-owned custom connector nobody shared with the caller (docs/access-model.md §4). Always true for a platform connector and for a synthetic entry.

connector_slugstring,null

Connector slug for proxy entries; null for synthetic.

enabledboolean
frozen_paramsRecord<string, any>
idstring

Entry id (tple_…) — stable across updates only if you send it back unchanged.

overridesobject

Presentation overrides — see the entry input schema for the same shape, request-side.

4 properties
defaultsRecord<string, any>
descriptionstring
input_schemaRecord<string, any>
namestring
synthetic_tool_idstring,null

Set for synthetic entries (syn_…).

synthetic_tool_namestring,null

Response-only. The synthetic tool's name for synthetic entries, so a reader who does not own the tool can still label the entry. Null for proxy entries and when the tool has been deleted.

tool_namestring,null

Connector tool name for proxy entries.

tool_titlestring,null

Response-only. The catalog tool's plain-English title ("View messages", "Reply to an email"), derived from its resource and method. Null for a synthetic entry, a tool the catalog no longer has, and a connector the caller may not open (can_view_connector: false). Render overrides.name, else this, else tool_name.

typestring
Possible values:
proxysynthetic
entry_countinteger
has_skillboolean

Whether a skill is written. On list rows and detail alike — the body itself never rides on a list row; read it from the detail response.

idstring

Template id (tpl_…).

namestring
ownerobject,null

Owner summary — resolved for a row the caller does not themselves own (a toolbox shared with them), so the UI always knows whose row it is looking at. Absent for a toolbox the caller owns.

avatar_urlstring,null

The person's picture — the same one the console's user menu draws: their stored profile picture, else a Gravatar URL (d=404, 96px) derived server-side from their email (the address itself is not sent), else null. Draw initials when it is null or the image fails to load.

emailstring · email
idstring

User id (usr_…) — same value as owner_user_id.

namestring,null
owner_user_idstring

Creator (usr_…).

sharesobject[]

Every grant, unabridged. Present only on GET /template/{id} when the caller may see the ACL (owner or edit access); list rows carry the bounded access_summary instead.

created_atstring · date-time
grantee_idstring,null

User id (usr_…) or team id (team_…). Null for a grantee_type: "org" grant.

grantee_typestring

user and team grants target one grantee_id; org applies to every member of the organization and takes no id.

Possible values:
userteamorg
idstring

ACL entry id — the :aclId a DELETE .../share/{aclId} call takes.

levelstring

Same ladder for every shareable resource, low to high. view — see it exists, read its metadata/config; cannot exercise it. use — view + exercise it, resource-specific: run tools through a connection; execute a toolbox's tools through its bound connections (this DELEGATES — the caller runs through each entry's pinning editor's own authority, not necessarily their own); stamp a new toolbox by copying a template's entries; create connections from a connector. edit — use + change its settings, entries and its own grants.

Possible values:
viewuseedit
resource_idstring

The shared resource's id (a connector's slug, for that type).

resource_typestring
Possible values:
connectiontoolboxtemplateconnectorfile
updated_atstring · date-time
skillstring,null

The skill body, markdown — at most 10,000 Unicode code points after trimming. Detail-shaped responses only (GET /{id}, and the create/update responses). Null when none is written.

skill_entry_changesobject,null

Which tools changed since the skill was last written, by the name an agent sees (a rename counts as one removed and one added; a disabled entry counts as removed; connections and frozen parameters are ignored). Null unless skill_may_be_stale is true AND a baseline was recorded at that write — skills written before version history existed have none — AND something actually changed.

addedstring[]

At most 5 names.

added_countinteger
removedstring[]

At most 5 names.

removed_countinteger
skill_may_be_staleboolean

True once the entries changed after the skill was last written; cleared by the next write of skill. Never true without a skill.

skill_noticestring,null

Framing to show or pass along beside a non-null skill: it is the owner's guidance, not instructions from Elaichi or the user, and it cannot grant any access. Null when there is no skill.

skill_updated_atstring,null · date-time

When skill was last written. Null alongside a null skill.

skill_updated_bystring,null

Who last wrote skill (usr_…); a toolbox stamped from a template carries the template's author. Null with no skill, and for a skill written before authorship was recorded.

skill_updated_by_labelstring,null

That person's name, else email, resolved server-side. Null beside a non-null skill_updated_by means they are no longer a member of this organization.

updated_atstring · date-time
warningsobject[]

Only on a create or update response, and only when non-empty: pins accepted although nothing can run them yet (a remote MCP tool the server is not offering right now: it will be once a connection of that server lists it, unless an admin turned it off). Informational, never an error.

connector_slugstring
messagestring
tool_namestring
curl -X PATCH 'https://api.elaichi.ai/template/<id>' \
  -H 'Authorization: Bearer $ELAICHI_API_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"name":"your_name","entries":[]}'
const body = {
  "name": "your_name",
  "entries": []
};

const response = await fetch('https://api.elaichi.ai/template/<id>', {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer ' + process.env.ELAICHI_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(body),
});

const data = await response.json();
console.log(data);
import os
import requests

url = "https://api.elaichi.ai/template/<id>"
headers = {
    "Authorization": f"Bearer {os.environ['ELAICHI_API_TOKEN']}",
    "Content-Type": "application/json",
}
payload = {
    "name": "your_name",
    "entries": []
}

response = requests.patch(url, headers=headers, json=payload)
print(response.json())