Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Conduyt Email Signature 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 Signature
paths:
/me/email-signature:
get:
operationId: getMyEmailSignature
summary: Get your own email signature in this workspace
description: 'One signature per workspace member. Returns the saved signature (or, when none is saved yet, the draft a first visit
starts from: saved false, html null), every field''s resolved value and source (fields: profile = the user, workspace
= the membership''s position and mobile, company = the Company details, signature = department and added networks),
and the context the editor previews with (the caller''s profile, position, the account''s branding and Company
details, the caller''s own active booking pages). signature.html and signature.plain are RENDERED AT READ TIME from
those live sources (exactly what Compose appends on the next send); a profile, membership, branding, Company
details or booking page change shows here with no re-save. When the current sources make the saved signature too
large to render, html and plain are null and renderError says why. A browser session, or an API key acting as its
user (needs the emails scope).'
tags:
- Email Signature
parameters: []
responses:
'200':
description: The caller's signature
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/EmailSignatureResponse'
example:
data:
saved: true
signature:
designId: classic
overrides:
title: Head of Customer Support
options:
accent: null
font: Original
fsize: m
psize: 80
shape: circle
lw: 120
istyle: accent
ishape: c
isz: 22
icol: null
iglyph: auto
divider: true
addons:
book:
'on': true
pageId: 9b2f1c4e-2a7d-4c2b-9b1e-3f5a6d7e8c90
signoff:
'on': false
text: Best regards,
banner:
'on': false
text: ''
url: ''
meet:
'on': false
text: Join my video meeting
url: ''
disclaimer:
'on': true
green:
'on': false
credit:
'on': true
compose:
newEmails: true
replies: true
useInCompose: true
html: <div data-conduyt-signature="v1"><table role="presentation">...</table></div>
plain: 'Jordan Tate
Head of Customer Support
Demolition Group'
renderError: null
updatedAt: 2026-10-15 17:02:11+00:00
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
description: not_a_member, the caller is not an active member of this workspace
put:
operationId: putMyEmailSignature
summary: Save your own email signature (replaces it)
description: 'Saving replaces the caller''s one signature in this workspace. Every part may be omitted and takes its default:
designId classic, overrides {} (every field follows its source), the default options, useInCompose true. Only the
choices are stored: the signature is rendered with the public generator''s engine from the live sources at every
use (this response, GET, and each send). Compose appends it (POST /messages with signature "new" or "reply"),
rendered at send time, when useInCompose and the matching options.compose flag are on. email is never an override (it is the
sign-in address). Links must be web addresses (overrides.web, banner and meeting links) or profile links (social).
options.addons.book.pageId must be one of the caller''s own active booking pages. A browser session, or an API key
acting as its user (emails scope, write tier).'
tags:
- Email Signature
parameters: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EmailSignatureInput'
examples:
basic:
summary: Pick a design and change the position
value:
designId: x02
overrides:
title: Head of Customer Support
dept: Support
options:
accent: '#0E1F3A'
addons:
disclaimer:
'on': true
useInCompose: true
responses:
'200':
description: Saved; the same shape as GET
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/EmailSignatureResponse'
'400':
description: invalid_json
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
description: not_a_member
'413':
description: signature_too_large, the rendered signature is over 64 KB
'422':
description: invalid_signature (an unknown key, a value out of range, a link that is not one, an unknown design or network) or booking_page_not_yours
/email-signature/designs:
get:
operationId: listEmailSignatureDesigns
summary: List the 36 email signature designs and the 62 networks
description: The 16 built-in designs and the 20 copied-style designs (the public generator's template file), each with its own accent, and the social networks a signature can link (the keys overrides.social takes). The same for every workspace. A browser session or an API key with the emails scope.
tags:
- Email Signature
parameters: []
responses:
'200':
description: Designs and networks
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
designs:
type: array
items:
type: object
properties:
id:
type: string
label:
type: string
desc:
type: string
group:
type: string
enum:
- builtin
- copied
groupLabel:
type: string
enum:
- Built-in
- Copied-style
accent:
type: string
counts:
type: object
properties:
all:
type: integer
builtin:
type: integer
copied:
type: integer
networks:
type: array
items:
type: object
properties:
key:
type: string
label:
type: string
placeholder:
type: string
required:
- designs
- counts
- networks
required:
- data
example:
data:
designs:
- id: classic
label: Classic
desc: Photo, details and a social column
group: builtin
groupLabel: Built-in
accent: '#5961F9'
- id: x02
label: Charcoal
desc: Dark block with two outline buttons
group: copied
groupLabel: Copied-style
accent: '#292929'
counts:
all: 36
builtin: 16
copied: 20
networks:
- key: linkedin
label: LinkedIn
placeholder: linkedin.com/in/you
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
components:
responses:
Forbidden:
description: Insufficient permissions
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Unauthorized:
description: Authentication required
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
schemas:
EmailSignatureResponse:
type: object
properties:
saved:
type: boolean
signature:
type: object
properties:
designId:
type: string
overrides:
type: object
options:
type: object
useInCompose:
type: boolean
html:
type:
- string
- 'null'
description: Rendered now from the live sources; null for an unsaved draft or with renderError
plain:
type:
- string
- 'null'
renderError:
type:
- string
- 'null'
description: Why the saved signature cannot be rendered from the current sources (too large)
else null: null
updatedAt:
type:
- string
- 'null'
format: date-time
fields:
type: object
description: Each field's value, source (profile, workspace, company, signature), whether it is custom, and its source value; the photo, logo, social links, disclaimer, brand colour and booking page in use.
context:
type: object
description: What the signature is filled from (profile, membership, branding, Company details, the caller's own booking pages).
EmailSignatureInput:
type: object
additionalProperties: false
properties:
designId:
description: One of the 36 design ids (GET /email-signature/designs). Default classic.
type: string
maxLength: 40
overrides:
description: Only the fields the member changed; an omitted (or null) field follows its source.
type: object
additionalProperties: {}
options:
description: 'Design and add-on choices: accent, font, fsize, psize, shape, lw, istyle, ishape, isz, icol, iglyph, divider, addons {book, signoff, banner, meet, disclaimer, green, credit}, compose {newEmails, replies}.'
type: object
additionalProperties: {}
useInCompose:
description: Compose appends the signature when true (default).
type: boolean
description: 'The signature must pass the design check: designId one of the 36 designs (GET /api/v1/email-signature/designs), overrides an object of the known fields (web a web address, social an object of network: link); otherwise a 422 (invalid_signature).'
ErrorResponse:
type: object
required:
- error
properties:
error:
type: string
code:
type: string
description: Machine-readable error code (e.g., TRIAL_EXPIRED, PLAN_LIMIT_REACHED)
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