Freshdesk Connector
Ingest Freshdesk tickets, replies, private notes, and attachments into CortexDB.
Captures Freshdesk tickets, their full conversation thread (public replies + private notes), and their attachments as CortexDB experiences. Each item keeps its real source timestamp.
Two ways to run this connector
Self-hosted — pip install cortexdb-connectors then cortexdb-sync sync freshdesk. Managed —
CortexDB runs the connector as a worker. See the Connectors overview.
Upgrade to 0.2.20
Earlier versions silently lost data: a ticket that reached 10 conversations stopped ingesting new replies forever, a rate-limited detail fetch stored the ticket with no body, and attachments were dropped entirely. See Upgrading.
1. Prepare credentials in Freshdesk
Freshdesk → Profile settings → Your API Key. The connector authenticates as HTTP Basic with the API
key as the username and X as the password. You also need your Freshdesk domain, e.g.
acme.freshdesk.com.
2. Configure (managed dashboard)
Settings → Connectors → Add Connector → Freshdesk. Paste the domain and API key, set the scope template
(default org:<org>/source:freshdesk), and Start sync.
What gets written
| Event | Episode type | Notes |
|---|---|---|
| Ticket | issue | Subject + description; content prefixed [FreshDesk ticket #N] |
| Public reply | comment | Prefixed [FreshDesk reply on ticket #N]; tagged reply |
| Private note | comment | Prefixed [FreshDesk note on ticket #N]; tagged note |
| Ticket/reply attachment | document | Uploaded to /v1/blobs and ingested as content.kind="blob_ref" so the content processors extract and index the file |
Every episode carries thread_id = "freshdesk:ticket:<id>", an entity reference of type ticket, and
metadata with ticket_id, status, priority, and a source_url back to the agent view.
Visibility
All Freshdesk episodes are stored restricted — support data is customer-facing and sensitive.
Public replies and private notes land at the same visibility; the distinction is carried by the
reply / note tag and the content prefix.
Idempotency and history
Tickets and conversations use a content-versioned key:
ticket:<id>:<updated_at>:<content-digest>
conv:<id>:<created_at>:<content-digest>
freshdesk:att:<attachment_id>Each edited state is retained as a new version. The content digest is what makes edited replies and
merged tickets work: a Freshdesk merge moves conversations to the primary ticket without changing their
id or created_at, so a timestamp-only key would collide and the corrected attribution could never be
recorded. Attachments key on the stable attachment id, so a re-synced ticket replays instead of
re-uploading the bytes.
Real-time delivery (webhook)
Freshdesk automations don't sign their payloads, so the receiver authenticates on a static header:
export FRESHDESK_WEBHOOK_SECRET=<a long random string>
cortexdb-sync serve --port 8081Then in Freshdesk → Admin → Workflows → Automations, add a Trigger webhook action pointing at
POST https://<your-host>/webhooks/freshdesk/events with Authorization: Bearer <the same secret>.
The webhook path uses the same normalizer as polling, so running both serve and sync is safe.
Run it yourself
pip install cortexdb-connectors
pip install cortexdb-cli && cortexdb init
export FRESHDESK_DOMAIN=acme.freshdesk.com # required
export FRESHDESK_API_KEY=... # required
export FRESHDESK_INCLUDE_CONVERSATIONS=1 # 0 = tickets only, bodies still ingested
export FRESHDESK_INCLUDE_ATTACHMENTS=1 # 0 = skip attachment blobs
cortexdb-sync --api-url http://localhost:3141 sync freshdesk
cortexdb-sync --api-url http://localhost:3141 watch freshdesk --interval 300FRESHDESK_INCLUDE_CONVERSATIONS=0 drops only the reply and note episodes — the ticket description is
always ingested.
Limits and behaviour worth knowing
- Attachments over 32 MiB are recorded metadata-only: the filename survives, the bytes are not uploaded.
- Rate limits are handled: requests retry
429/5xxwithRetry-After, up to 5 attempts. - A ticket that cannot be fetched holds the cursor and is retried; after 5 consecutive failed cycles it
is dead-lettered and
cortexdb-sync statusreports it. - Deletions are not propagated from the poll path — a deleted reply remains as retained history.
Upgrading from 0.2.19 or earlier
0.2.20 fixed several silent data-loss paths. The most impactful: tickets that reached 10 conversations stopped ingesting — the thread was read from a preview array capped at 10 entries, so every later reply, note, and resolution was invisible while the sync reported success. To backfill:
cortexdb-sync status # note the current cursor first
cortexdb-sync sync freshdesk --since 2020-01-01T00:00:00ZRe-ingest is safe — idempotency keys dedupe anything already stored. Because keys now carry a content digest, the first sync after upgrading records one new version per currently-visible ticket state.