> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lettr.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Update Template

> Update an existing email template's name and/or content. If content (html or json) is provided, a new active version will be created with extracted merge tags. If `project_id` is not provided, the template will be looked up in the team's default project.

Updates an existing template by its slug. You can update the template name, project assignment, or content. Providing new `html` or `json` content creates a new version of the template automatically.

The `html` and `json` fields are mutually exclusive. If neither is provided, only metadata (name, project) is updated without creating a new version.


## OpenAPI

````yaml PUT /templates/{slug}
openapi: 3.1.0
info:
  title: Lettr API
  version: 1.0.0
  description: >-
    Lettr Email API - Send transactional emails with tracking, attachments, and
    personalization.
  contact:
    name: Lettr Support
    url: https://lettr.com
  license:
    name: Proprietary
    url: https://lettr.com/terms
servers:
  - url: https://app.lettr.com/api
    description: Production
security: []
tags:
  - name: Emails
    description: Email sending operations
  - name: Templates
    description: Email template management operations
  - name: Domains
    description: Domain management operations
  - name: Webhooks
    description: Webhook management operations
  - name: Audience
    description: 'Audience management: lists, contacts, topics, properties, and segments'
  - name: Campaigns
    description: >-
      Campaign operations: listing, stats, engagement events, and
      dispatch/scheduling
paths:
  /templates/{slug}:
    put:
      tags:
        - Templates
      summary: Update Template
      description: >-
        Update an existing email template's name and/or content. If content
        (html or json) is provided, a new active version will be created with
        extracted merge tags. If `project_id` is not provided, the template will
        be looked up in the team's default project.
      operationId: updateTemplate
      parameters:
        - name: slug
          in: path
          required: true
          description: The template slug (URL-friendly identifier)
          schema:
            type: string
            example: welcome-email
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTemplateRequest'
            examples:
              update_name:
                summary: Update template name only
                value:
                  name: Updated Welcome Email
              update_html:
                summary: Update with new HTML content
                value:
                  html: >-
                    <html><body><p>Hello {{NAME}}, welcome
                    aboard!</p></body></html>
              update_json:
                summary: Update with new Topol JSON content
                value:
                  json: >-
                    {"tagName":"mj-container","children":[{"tagName":"mj-text","content":"Hello
                    {{FIRST_NAME}}!"}]}
              update_name_and_content:
                summary: Update name and content together
                value:
                  name: New Newsletter
                  html: >-
                    <html><body><p>Welcome
                    {{SUBSCRIBER_NAME}}!</p></body></html>
              update_with_project:
                summary: Update template in specific project
                value:
                  project_id: 5
                  name: Renamed Template
      responses:
        '200':
          description: Template updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateTemplateResponse'
              example:
                message: Template updated successfully.
                data:
                  id: 123
                  name: Updated Welcome Email
                  slug: welcome-email
                  project_id: 5
                  folder_id: 10
                  active_version: 2
                  merge_tags:
                    - key: NAME
                      required: true
                  created_at: '2026-01-15T10:00:00+00:00'
                  updated_at: '2026-01-28T14:30:00+00:00'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          description: Template or project not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                template_not_found:
                  summary: Template not found
                  value:
                    message: Template with slug 'welcome-email' was not found.
                    error_code: not_found
                project_not_found:
                  summary: Project not found
                  value:
                    message: >-
                      Project with ID '123' was not found or you don't have
                      access to it.
                    error_code: not_found
                no_default_project:
                  summary: No default project configured
                  value:
                    message: No default project is configured for this team.
                    error_code: not_found
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
              examples:
                both_content:
                  summary: Both html and json provided
                  value:
                    message: Validation failed.
                    error_code: validation_error
                    errors:
                      json:
                        - The json field prohibits html from being present.
                invalid_json:
                  summary: Invalid JSON syntax
                  value:
                    message: Validation failed.
                    error_code: validation_error
                    errors:
                      json:
                        - The provided JSON is not valid.
                name_too_long:
                  summary: Name exceeds max length
                  value:
                    message: Validation failed.
                    error_code: validation_error
                    errors:
                      name:
                        - The name must not be greater than 255 characters.
        '500':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                message: Failed to update template. Please try again later.
                error_code: send_error
      security:
        - bearerAuth: []
components:
  schemas:
    UpdateTemplateRequest:
      type: object
      description: >-
        Request to update an existing email template. All fields are optional -
        provide only what you want to change. If `html` or `json` is provided, a
        new active version will be created.
      properties:
        project_id:
          type: integer
          minimum: 1
          description: >-
            Project ID to find the template in. If not provided, uses the team's
            default project.
          example: 5
        name:
          type: string
          maxLength: 255
          description: New name for the template
          example: Updated Welcome Email
        html:
          type: string
          description: >-
            New HTML content for the template. Creates a new active version.
            Mutually exclusive with `json`.
          example: <html><body><p>Hello {{NAME}}!</p></body></html>
        json:
          type: string
          description: >-
            New JSON content for Topol visual editor templates. Creates a new
            active version. Mutually exclusive with `html`.
          example: >-
            {"tagName":"mj-container","children":[{"tagName":"mj-text","content":"Hello
            {{FIRST_NAME}}!"}]}
    UpdateTemplateResponse:
      type: object
      description: Response after successfully updating a template
      required:
        - message
        - data
      properties:
        message:
          type: string
          description: Human-readable response message
          example: Template updated successfully.
        data:
          $ref: '#/components/schemas/UpdatedTemplateView'
    ErrorResponse:
      type: object
      required:
        - message
        - error_code
      description: Error response for non-validation errors (400, 409, 500, 502).
      properties:
        message:
          type: string
          description: Human-readable error message
          example: The sender domain could not be determined from the email address.
        error_code:
          $ref: '#/components/schemas/ErrorCode'
    ValidationErrorResponse:
      type: object
      required:
        - message
        - error_code
        - errors
      properties:
        message:
          type: string
          description: Human-readable error message
          example: Validation failed.
        error_code:
          type: string
          description: Error code (always `validation_error` for 422 responses)
          const: validation_error
          example: validation_error
        errors:
          type: object
          description: Field-specific validation errors
          additionalProperties:
            type: array
            items:
              type: string
          example:
            from:
              - The sender email address is required.
            to:
              - At least one recipient email address is required.
    UpdatedTemplateView:
      type: object
      description: View of an updated template
      required:
        - id
        - name
        - slug
        - project_id
        - folder_id
        - active_version
        - merge_tags
        - created_at
        - updated_at
      properties:
        id:
          type: integer
          description: Unique identifier for the template
          example: 123
        name:
          type: string
          description: Name of the template
          example: Updated Welcome Email
        slug:
          type: string
          description: URL-friendly identifier for the template
          example: welcome-email
        project_id:
          type: integer
          description: ID of the project containing this template
          example: 5
        folder_id:
          type: integer
          description: ID of the folder containing this template
          example: 10
        active_version:
          type: integer
          description: Version number of the active template version
          example: 2
        merge_tags:
          type: array
          description: List of merge tags extracted from the template content
          items:
            $ref: '#/components/schemas/MergeTagView'
        created_at:
          type: string
          format: date-time
          description: When the template was created
          example: '2026-01-15T10:00:00+00:00'
        updated_at:
          type: string
          format: date-time
          description: When the template was last updated
          example: '2026-01-28T14:30:00+00:00'
    UnauthorizedResponse:
      type: object
      required:
        - message
      description: Error response for authentication failures (401).
      properties:
        message:
          type: string
          description: Human-readable error message
          example: API key is required.
    ErrorCode:
      type: string
      description: >-
        Error codes returned by the API.


        | Code | HTTP Status | Description |

        |------|-------------|-------------|

        | `validation_error` | 422 | Request validation failed. Check the
        `errors` object for field-specific messages. |

        | `invalid_domain` | 400 | The sender domain could not be determined
        from the email address. |

        | `unconfigured_domain` | 400 | The sender domain is not configured or
        approved for sending. |

        | `send_error` | 400, 500 | General error during email send preparation
        or domain registration. |

        | `retrieval_error` | 400, 500 | Failed to retrieve resources (e.g.,
        sandbox key without associated user, upstream error). |

        | `transmission_failed` | 502 | Email transmission to the upstream
        provider failed. |

        | `resource_already_exists` | 409 | The resource (e.g., domain) already
        exists. |

        | `not_found` | 404 | The specified resource was not found. |

        | `template_not_found` | 404 | The specified template, project, or
        template version was not found. |

        | `insufficient_scope` | 403 | The API key does not have the required
        scope for this endpoint. |

        | `schedule_cancellation_failed` | 409, 500 | Could not cancel the
        scheduled transmission (already sent or upstream error). |

        | `quota_exceeded` | 429 | Monthly sending quota exceeded. Upgrade your
        plan to continue sending. |

        | `daily_quota_exceeded` | 429 | Daily sending quota exceeded. Try again
        tomorrow. |

        | `campaign_not_sendable` | 422 | The campaign cannot be sent in its
        current state (not a draft, or missing subject/sender/content). |

        | `campaign_not_scheduled` | 422 | The campaign is not scheduled, so it
        cannot be unscheduled. |
      enum:
        - validation_error
        - invalid_domain
        - unconfigured_domain
        - send_error
        - retrieval_error
        - transmission_failed
        - resource_already_exists
        - not_found
        - template_not_found
        - insufficient_scope
        - schedule_cancellation_failed
        - quota_exceeded
        - daily_quota_exceeded
        - campaign_not_sendable
        - campaign_not_scheduled
      example: invalid_domain
    MergeTagView:
      type: object
      description: >-
        A single merge tag. Loop merge tags (for iterating over arrays) include
        a 'children' property with nested field definitions.
      required:
        - key
        - required
      properties:
        key:
          type: string
          description: The merge tag key/name used in templates
          example: first_name
        required:
          type: boolean
          description: Whether this merge tag is required when sending emails
          example: true
        type:
          type: string
          description: The data type of the merge tag (only present for loop children)
          enum:
            - text
            - number
            - image
            - button
          example: text
        children:
          type: array
          description: >-
            Child merge tags for loop blocks. Each child represents a field
            available within the loop iteration.
          items:
            $ref: '#/components/schemas/MergeTagChild'
    MergeTagChild:
      type: object
      description: A child merge tag within a loop block
      required:
        - key
      properties:
        key:
          type: string
          description: The child merge tag key/name
          example: item_name
        type:
          type: string
          description: The data type of the child merge tag
          enum:
            - text
            - number
            - image
            - button
          example: text
  responses:
    UnauthorizedError:
      description: Unauthorized - Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/UnauthorizedResponse'
          examples:
            missing_key:
              summary: Missing API key
              value:
                message: API key is required.
            invalid_key:
              summary: Invalid API key
              value:
                message: Invalid API key.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key for authentication

````