Conduyt Email Templates API

Reusable email/SMS templates

Operations 6

GET /emails/templates List email templates #
POST /emails/templates Create an email template #
GET /emails/templates/{id} Get an email template by ID #
PATCH /emails/templates/{id} Update an email template #
DELETE /emails/templates/{id} Delete an email template #
POST /emails/templates/test-send Send a test email from a template #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/conduyt-com:conduyt-com-email-templates-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

conduyt-com-email-templates-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Conduyt Email Templates API
  version: 1.0.0
  description: 'The Conduyt CRM API provides programmatic access to your CRM data including

    contacts, companies, deals, pipelines, tasks, notes, automations, invoices,

    email sequences, and more.


    ## Authentication


    All authenticated endpoints require a Bearer token (API key) in the

    `Authorization` header:


    ```

    Authorization: Bearer cdy_

    ```


    API keys are generated in **Settings > API Keys** within the Conduyt

    dashboard. Keys use the `cdy_` prefix and are hashed with bcrypt on

    creation — the full key is shown exactly once at creation time.


    Session cookie authentication (`conduyt_session`) is also supported for

    browser-based clients but is not recommended for integrations.


    ## Rate Limiting


    API keys enforce a per-key rate limit. New keys default to 100 requests per

    minute and can be configured at creation time or with PATCH `/api-keys/{id}`.

    Some public and provider-facing endpoints also enforce stricter per-IP or

    per-account limits. When exceeded, the API returns `429 Too Many Requests`

    with a `Retry-After` header indicating seconds until the next allowed

    request.


    | Endpoint Group | Limit |

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

    | API keys | Default 100 / min per key |

    | Login/reset | 5 / min per IP |

    | Registration | 3 / hour per IP |

    | Contact/Deal create | 30 / min per IP |

    | Inbound messages | 120 / min per account/IP |


    ## Pagination


    List endpoints support cursor-based pagination via query parameters:


    - `page` — Page number (default: 1)

    - `per_page` — Items per page (default: 50, max: 200)

    - `limit` — Accepted as an alias of `per_page` on `GET /contacts`; if both are

    sent they must carry the same value.


    A page size above the maximum, a non-integer, a value below 1, or a

    pagination key repeated with different values is rejected with `400`

    (the message names the parameter and the rule); nothing is silently

    clamped or ignored.


    Responses include a `meta` object: `{ page, per_page, total }`.


    An operation that documents its own pagination rules follows those instead.

    `GET /sms-providers/options` pages with an opaque `cursor` and a `limit`

    that is capped at 50 rather than rejected; its responses carry

    `meta: { nextCursor, truncated }`.


    ## Response Format


    All successful responses wrap data in a `data` envelope:

    ```json

    { "data": { ... } }

    ```


    Error responses use:

    ```json

    { "error": "Human-readable error message" }

    ```


    ## Multi-Tenancy


    Conduyt is multi-tenant. All data is scoped to the authenticated user''s

    current account. API keys are bound to a specific account at creation time.


    ## Webhook Events


    Outbound webhooks fire on events including:

    `contact.created`, `contact.updated`, `contact.deleted`,

    `deal.created`, `deal.updated`, `deal.won`, `deal.lost`,

    `task.created`, `task.completed`, `note.created`,

    `appointment.created`, `appointment.updated`,

    `form.submitted`, `invoice.paid`


    Payloads are signed with HMAC-SHA256 using the webhook''s secret. Retry

    schedule: 1m, 5m, 30m, 2h, 12h, 72h (7 total attempts including the initial delivery).'
  contact:
    name: Conduyt Support
    url: https://conduyt.app
    email: support@conduyt.app
  license:
    name: Proprietary
    url: https://conduyt.app/terms
servers:
- url: https://conduyt.app/api/v1
  description: Production
security:
- BearerAuth: []
tags:
- name: Email Templates
  description: Reusable email/SMS templates
paths:
  /emails/templates:
    get:
      operationId: listEmailTemplates
      summary: List email templates
      tags:
      - Email Templates
      parameters:
      - name: category
        in: query
        required: false
        description: Query parameter read by this route.
        schema:
          type: string
      - name: channel
        in: query
        required: false
        description: Query parameter read by this route.
        schema:
          type: string
      - name: is_active
        in: query
        required: false
        description: Query parameter read by this route.
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
          default: 1
          minimum: 1
        x-default-provenance: handler_literal
      - name: per_page
        in: query
        required: false
        description: Items per page (max 200)
        schema:
          type: integer
          default: 50
          minimum: 1
          maximum: 200
        x-default-provenance: handler_literal
      - name: provider
        in: query
        required: false
        description: Query parameter read by this route.
        schema:
          type: string
      responses:
        '200':
          description: Paginated templates
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items: {}
                  meta:
                    type: object
                    properties:
                      page:
                        type: integer
                      perPage:
                        type: integer
                      total:
                        type: integer
                      totalPages:
                        type: integer
                    required:
                    - page
                    - perPage
                    - total
                    - totalPages
                required:
                - data
                - meta
    post:
      operationId: createEmailTemplate
      summary: Create an email template
      description: 'Email templates built in the editor keep their builder state in hidden markers: CONDUYT_BLOCKS and CONDUYT_META

        (subject B, preheader, custom head HTML, footer HTML). Metadata precedence: the CONDUYT_META marker in bodyHtml

        wins over one in body; the editor writes it to bodyHtml only, and body''s marker is read only when bodyHtml has

        none. A request that would leave DIFFERENT markers in body and bodyHtml is refused with 400

        template_meta_conflict ("body and bodyHtml both carry a CONDUYT_META marker and they differ"). Stored rows are

        never rewritten.


        Pasted HTML (email only): send bodyMode "html" with html (your own designed email, up to 100 KB). The

        stored bodyHtml is built from html: the builder''s blocks (from bodyHtml in the request, else the stored row)

        are kept, and body defaults to the HTML''s visible text when none is sent. Sends use the pasted HTML as the

        body with only what every email gets: merge fields rendered, the preheader / head / footer HTML from the

        metadata, open tracking, and an unsubscribe link unless the HTML already carries {{unsubscribe_url}} (or

        {{unsubscribeUrl}}). bodyMode "blocks" takes the builder''s bodyHtml; switching back keeps the pasted HTML

        (returned as html). Refusals (400, nothing written): html_required (bodyMode html without html, or empty),

        html_too_large (over 100 KB: Gmail clips emails over 102 KB), html_script (a anywhere in the HTML), html_without_html_mode (html

        without bodyMode html), invalid_body_mode (not "blocks" / "html", or on an SMS template), body_html_required

        (bodyMode blocks without bodyHtml), body_mode_conflict (bodyMode blocks with html-mode metadata in bodyHtml),

        html_conditional_comment (an Outlook conditional comment that ends before its , is never closed, or

        has an unreadable condition), html_office_markup (VML / Office elements outside an Outlook-only block),

        html_duplicate_attribute (an element inside an Outlook-only block with the same attribute twice).

        A template returned by POST, PATCH or GET /emails/templates/{id} carries bodyMode ("blocks" / "html"; null

        for SMS) and html (the pasted HTML in html mode, the kept copy in blocks mode, else null); a LIST row carries

        bodyMode only (fetch the template by id for html).'
      tags:
      - Email Templates
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EmailTemplateCreate'
      responses:
        '201':
          description: Template created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataEnvelope'
        '400':
          $ref: '#/components/responses/BadRequest'
      parameters:
      - name: dry_run
        in: query
        required: false
        description: Validate the mutation without persisting changes.
        schema:
          type: boolean
      - name: sandbox
        in: query
        required: false
        description: Run the mutation in sandbox mode.
        schema:
          type: boolean
  /emails/templates/{id}:
    get:
      operationId: getEmailTemplate
      summary: Get an email template by ID
      tags:
      - Email Templates
      parameters:
      - $ref: '#/components/parameters/IdParam'
      responses:
        '200':
          description: Template details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataEnvelope'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateEmailTemplate
      summary: Update an email template
      description: 'Email templates built in the editor keep their builder state in hidden markers: CONDUYT_BLOCKS and CONDUYT_META

        (subject B, preheader, custom head HTML, footer HTML). Metadata precedence: the CONDUYT_META marker in bodyHtml

        wins over one in body; the editor writes it to bodyHtml only, and body''s marker is read only when bodyHtml has

        none. A request that would leave DIFFERENT markers in body and bodyHtml is refused with 400

        template_meta_conflict ("body and bodyHtml both carry a CONDUYT_META marker and they differ"). Stored rows are

        never rewritten.


        Pasted HTML (email only): send bodyMode "html" with html (your own designed email, up to 100 KB). The

        stored bodyHtml is built from html: the builder''s blocks (from bodyHtml in the request, else the stored row)

        are kept, and body defaults to the HTML''s visible text when none is sent. Sends use the pasted HTML as the

        body with only what every email gets: merge fields rendered, the preheader / head / footer HTML from the

        metadata, open tracking, and an unsubscribe link unless the HTML already carries {{unsubscribe_url}} (or

        {{unsubscribeUrl}}). bodyMode "blocks" takes the builder''s bodyHtml; switching back keeps the pasted HTML

        (returned as html). Refusals (400, nothing written): html_required (bodyMode html without html, or empty),

        html_too_large (over 100 KB: Gmail clips emails over 102 KB), html_script (a anywhere in the HTML), html_without_html_mode (html

        without bodyMode html), invalid_body_mode (not "blocks" / "html", or on an SMS template), body_html_required

        (bodyMode blocks without bodyHtml), body_mode_conflict (bodyMode blocks with html-mode metadata in bodyHtml),

        html_conditional_comment (an Outlook conditional comment that ends before its , is never closed, or

        has an unreadable condition), html_office_markup (VML / Office elements outside an Outlook-only block),

        html_duplicate_attribute (an element inside an Outlook-only block with the same attribute twice).

        A template returned by POST, PATCH or GET /emails/templates/{id} carries bodyMode ("blocks" / "html"; null

        for SMS) and html (the pasted HTML in html mode, the kept copy in blocks mode, else null); a LIST row carries

        bodyMode only (fetch the template by id for html).'
      tags:
      - Email Templates
      parameters:
      - $ref: '#/components/parameters/IdParam'
      - name: dry_run
        in: query
        required: false
        description: Validate the mutation without persisting changes.
        schema:
          type: boolean
      - name: sandbox
        in: query
        required: false
        description: Run the mutation in sandbox mode.
        schema:
          type: boolean
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EmailTemplateUpdate'
      responses:
        '200':
          description: Template updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataEnvelope'
        '400':
          $ref: '#/components/responses/BadRequest'
    delete:
      operationId: deleteEmailTemplate
      summary: Delete an email template
      tags:
      - Email Templates
      parameters:
      - $ref: '#/components/parameters/IdParam'
      - name: dry_run
        in: query
        required: false
        description: Validate the mutation without persisting changes.
        schema:
          type: boolean
      - name: sandbox
        in: query
        required: false
        description: Run the mutation in sandbox mode.
        schema:
          type: boolean
      responses:
        '200':
          description: Template deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id: {}
                      deleted:
                        type: boolean
                      archived:
                        type: boolean
                    required:
                    - id
                    - deleted
                    - archived
                required:
                - data
  /emails/templates/test-send:
    post:
      operationId: testSendEmailTemplate
      summary: Send a test email from a template
      tags:
      - Email Templates
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                templateId:
                  description: 'A saved email template of this account. When given, the template is what is sent: a subject and html given beside it are not read. Absent, null or empty = no template (subject and html are used).'
                  anyOf:
                  - type: string
                    pattern: ^$|^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
                  - type: 'null'
                subject:
                  description: With html, the subject of an unsaved template (used when templateId is absent, null or empty).
                  anyOf:
                  - type: string
                    minLength: 1
                  - type: 'null'
                html:
                  description: With subject, the stored base HTML of an unsaved template (used when templateId is absent, null or empty).
                  anyOf:
                  - type: string
                    minLength: 1
                  - type: 'null'
                toEmail:
                  anyOf:
                  - type: string
                  - type: 'null'
              description: 'This endpoint has conditional or cross-field request requirements. Flat requiredFields are intentionally omitted; read endpoint notes/description and validation errors for valid field combinations. Either templateId (a saved template: a subject and html given beside it are not read), or both subject and html (the draft).'
      responses:
        '200':
          description: Test email sent
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      sent:
                        type: boolean
                      to: {}
                      subject: {}
                    required:
                    - sent
                    - to
                    - subject
                required:
                - data
      parameters:
      - name: dry_run
        in: query
        required: false
        description: Validate the mutation without persisting changes.
        schema:
          type: boolean
      - name: sandbox
        in: query
        required: false
        description: Run the mutation in sandbox mode.
        schema:
          type: boolean
components:
  schemas:
    EmailTemplateCreateHtml:
      type: object
      required:
      - name
      - channel
      - bodyMode
      - html
      properties:
        name:
          type: string
        channel:
          type: string
          enum:
          - email
        subject:
          type: string
        body:
          type: string
          description: Optional; defaults to the HTML's visible text.
        bodyHtml:
          type: string
          description: Optional; only its builder markers (blocks, metadata) are read and kept.
        bodyMode:
          type: string
          enum:
          - html
        html:
          type: string
          maxLength: 102400
          description: 'Your own email HTML. Up to 100 KB (UTF-8 bytes; Gmail clips emails over 102 KB); no <script>. Merge fields like {{contact.firstName}} work inside it. Outlook''s conditional comments (<!--[if mso]> … <![endif]-->, <!--[if !mso]><!--> … <!--<![endif]-->) and the VML / Office elements inside them are kept with their content sanitised (scripts, frames, event handlers and javascript:/data: URLs removed), while a conditional comment that cannot be read safely (html_conditional_comment) or VML outside an Outlook-only block (html_office_markup) is refused with a 400 that names it.'
        category:
          type: string
        isActive:
          type: boolean
          default: true
    EmailTemplateCreateBlocks:
      type: object
      required:
      - name
      - channel
      - body
      properties:
        name:
          type: string
        channel:
          type: string
          enum:
          - sms
          - email
        subject:
          type: string
        body:
          type: string
        bodyHtml:
          type: string
        bodyMode:
          type: string
          enum:
          - blocks
          description: 'Email only. "blocks" = built from the editor blocks: send the builder bodyHtml. Omitted = bodyHtml stored as sent.'
        category:
          type: string
        isActive:
          type: boolean
          default: true
      not:
        required:
        - html
    DataEnvelope:
      type: object
      properties:
        data:
          description: Response payload (shape varies by endpoint)
    EmailTemplateUpdate:
      type: object
      description: 'Partial update: send only the fields to change. html requires bodyMode "html"; bodyMode "html" requires html;

        bodyMode "blocks" requires bodyHtml. Builder markers the request leaves out are kept from the stored template.'
      properties:
        name:
          type: string
        subject:
          type: string
        body:
          type: string
        bodyHtml:
          type: string
        bodyMode:
          type: string
          enum:
          - blocks
          - html
        html:
          type: string
          maxLength: 102400
        category:
          type: string
        provider:
          type: string
        isActive:
          type: boolean
      dependentRequired:
        html:
        - bodyMode
      allOf:
      - if:
          properties:
            bodyMode:
              const: html
          required:
          - bodyMode
        then:
          required:
          - html
      - if:
          properties:
            bodyMode:
              const: blocks
          required:
          - bodyMode
        then:
          required:
          - bodyHtml
          not:
            required:
            - html
    ErrorResponse:
      type: object
      required:
      - error
      properties:
        error:
          type: string
        code:
          type: string
          description: Machine-readable error code (e.g., TRIAL_EXPIRED, PLAN_LIMIT_REACHED)
    EmailTemplateCreate:
      description: 'Two shapes. Built from the editor''s blocks (or plain): name, channel and body are required, bodyHtml optional,

        bodyMode "blocks" or omitted. Pasted HTML (email only): name, channel "email", bodyMode "html" and html are

        required; body is optional (it defaults to the HTML''s visible text).'
      oneOf:
      - $ref: '#/components/schemas/EmailTemplateCreateBlocks'
      - $ref: '#/components/schemas/EmailTemplateCreateHtml'
  parameters:
    IdParam:
      name: id
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Resource UUID
  responses:
    BadRequest:
      description: Bad request — validation error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: 'API key authentication. Generate keys in Settings > API Keys.

        Keys use the `cdy_` prefix.


        Example: `Authorization: Bearer cdy_a1b2c3d4e5f6...`

        '
x-mcp:
  transport:
  - stdio
  - http
  orchestration: code
  endpoint_tools: hidden