---
title: "Get a template"
method: GET
path: "/template/{id}"
tags: ["Templates"]
---

# Get a template

`GET /template/{id}`

## Request

- Base URL: `https://api.elaichi.ai`
- URL: `https://api.elaichi.ai/template/{id}`
- Auth: HTTP bearer

Returns one template with its full entry list (a template never carries a `connection_id`), and `access_summary` when the caller may see who it is shared with. Only the owner or someone with a grant can open a template; anyone else gets `404`, never `403`, including a holder of `template:manage`.

## Path parameters

- `id` string, required

## Headers

- `X-Organization-Id` string

## Response `200`

OK

- object
  - `id` string: Template id (`tpl_…`).
  - `name` string
  - `description` string, nullable
  - `owner_user_id` string: Creator (`usr_…`).
  - `access_level` string: The caller's access: `owner`, or a granted `view`/`use`/`edit` level. An org owner or admin sees a template only when they own it or it has been shared with them, like any other member.
  - `owner` object, nullable: 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.
    - `id` string: User id (`usr_…`) — same value as `owner_user_id`.
    - `name` string, nullable
    - `email` string, email
    - `avatar_url` string, nullable: The person's picture: their stored profile picture, else a Gravatar URL (`d=404`, 96px) derived from their email (the address itself is not sent), else null. Draw initials when it is null or the image fails to load.
  - `entry_count` integer
  - `connectors` object: Which integrations this template's tools come from, summarized as at most a handful of connectors (the same shape 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`). `total: 0` means no connector-backed tools (empty, or synthetic-only), never "not computed".
    - `total` integer: Distinct connector slugs across the template.
    - `preview` object[]: At most 5 connectors, ordered by entry count descending then slug ascending, so 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.
      - `slug` string: Connector slug — connectors are keyed by slug, not by id.
      - `name` string: 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.
      - `logo` string, nullable: 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.
  - `created_at` string, date-time
  - `updated_at` string, date-time
  - `access_summary` object: 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_level` 'view' | 'use' | 'edit' | 'null', nullable: Level of the org-wide grant, or null when there is none.
    - `team_count` integer
    - `user_count` integer
    - `total` integer: Every grant, the org-wide one included.
    - `preview` object[]: At most 5 grantees, broadest first (org, then teams, then members), for a hover preview.
      - `grantee_type` 'user' | 'team' | 'org'
      - `grantee_id` string, nullable
      - `level` 'view' | 'use' | 'edit'
      - `name` string, nullable: Display name; null for org grants and for grantees no longer in the org.
  - `shares` AclEntry[]: A short list of the grants on this template. Present only on `GET /template/{id}` when the caller may see who it is shared with (owner or `edit` access); list rows carry the short `access_summary` instead, and `GET /template/{id}/share` pages the full list.
    - `id` string: Grant id (`acl_…`), the `{aclId}` that `DELETE .../share/{aclId}` takes.
    - `resource_type` 'connection' | 'toolbox' | 'template' | 'connector' | 'file'
    - `resource_id` string: The shared resource's id (a connector's slug, for that type).
    - `grantee_type` 'user' | 'team' | 'org': `user` and `team` grants target one `grantee_id`; `org` applies to every member of the organization and takes no id.
    - `grantee_id` string, nullable: User id (`usr_…`) or team id (`team_…`). Null for a `grantee_type: "org"` grant.
    - `level` 'view' | 'use' | 'edit': 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.
    - `created_at` string, date-time
    - `updated_at` string, date-time
  - `has_skill` boolean: 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.
  - `skill_may_be_stale` boolean: True once the entries changed after the skill was last written; cleared by the next write of `skill`. Never true without a skill.
  - `can_use` boolean: Whether the caller may stamp a toolbox from this template — based on the caller's ownership or grant level. Present on every list and detail row for both templates and toolboxes.
  - `can_share` boolean: 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_manage` boolean: Whether the caller may edit this template's own settings — owner, or `edit` access. No `template:manage` fallback. Mirrors `PATCH /template/{id}`.
  - `can_transfer` boolean: 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_revoke_share` boolean: Whether the caller may grant or revoke access to this template. It matches `can_share` and is separate from `can_manage`: an `edit` grantee whose role omits `template:share` can edit the template but cannot change who else has access. Mirrors `DELETE /template/{id}/share/{aclId}`.
  - `access_via` 'owner' | 'direct' | 'team' | 'org': How the caller reaches this template, not who else can. `owner`: they own it. `direct`: a grant names them personally. `team`: a grant to a team they belong to (or administer), named in `access_via_team`. `org`: an organization-wide grant. When several sources apply, the broadest wins and the access level plays no part: owner, else `org`, else `team`, else `direct`. A caller with `edit` personally and `view` org-wide reads `org`, because this field says how far the template reaches, not what the caller may do with it. It describes only the caller's own access, so a `view` or `use` grantee still gets it while the list of other grantees stays hidden. Absent when nothing reaches the caller (for example, the former owner after a transfer of a resource that was never shared); absent never means `org`.
  - `access_via_team` object: 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.
    - `id` string: Team id (`team_…`).
    - `name` string, nullable: Team display name, or null when the team no longer resolves in the directory — the same null contract every resolved grantee name carries.
  - `entries` object[]
    - `id` string: Entry id (`tple_…`) — stable across updates only if you send it back unchanged.
    - `type` 'proxy' | 'synthetic'
    - `synthetic_tool_id` string, nullable: Set for `synthetic` entries (`syn_…`).
    - `synthetic_tool_name` string, nullable: 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.
    - `connector_slug` string, nullable: Connector slug for `proxy` entries; null for synthetic.
    - `tool_name` string, nullable: Connector tool name for `proxy` entries.
    - `tool_title` string, nullable: 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`.
    - `connector` object, nullable: Response-only. The connector’s label and logo; null for a `synthetic` entry. A connector the catalog cannot resolve reads its slug as `label` and a null `logo`.
      - `label` string, required
      - `logo` string, nullable, required
      - `upstream_slug` string: Only on a fork whose upstream the caller may see, by the same rule as `GET /connection`: omitted when the caller has no access to the fork or the upstream is hidden from them, and when the upstream cannot be read.
    - `can_view_connector` boolean: Response-only, per reader: whether the caller may open `connector_slug` (`GET /connector/{slug}` and its `/tools`). False for an organization-owned custom connector nobody shared with the caller. Always true for a platform connector and for a synthetic entry.
    - `overrides` object: Presentation overrides — see the entry input schema for the same shape, request-side.
      - `name` string
      - `description` string
      - `input_schema` object
      - `defaults` object
    - `frozen_params` object
    - `enabled` boolean
  - `skill` string, nullable: 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_updated_at` string, date-time, nullable: When `skill` was last written. Null alongside a null `skill`.
  - `skill_notice` string, nullable: 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_by` string, nullable: 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_label` string, nullable: 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.
  - `skill_entry_changes` object, nullable: 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.
    - `added_count` integer
    - `removed_count` integer
    - `added` string[]: At most 5 names.
    - `removed` string[]: At most 5 names.
  - `can_draft_skill` boolean: 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.
  - `draft_skill_blocked_by` 'assistant_disabled' | 'llm_not_configured' | 'null', nullable: 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.
  - `warnings` object[]: 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_slug` string, required
    - `tool_name` string, required
    - `message` string, required

## Other responses

- `400`: Bad request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `429`: Rate limited

---

[API](https://skmtc.dev/elaichi/apis/elaichi-api.md) · [All operations](https://skmtc.dev/elaichi/apis/elaichi-api/llms.txt) · [OpenAPI document](https://skmtc.dev/elaichi/apis/elaichi-api/revisions/b22cfb7b6d15?raw)
