Skip to content

Black Friday:

60% off

Cliedesk Pro

Every plan, every site count. Ends Cyber Monday.

00 days 00 hrs 00 min 00 sec
Claim 60% off

Developers

Connectors and sidebar apps (Cliedesk Pro)

This guide covers a feature of Cliedesk Pro. The free plugin is a complete help desk; see what Pro adds.

Module pro_connectors (cliedesk-pro/src/Modules/Connectors/, UI in cliedesk-pro/app/connectors/). It covers the HTTP connector builder, response mapping, test mode and health, templates and suggestions, “call connector” sidebar buttons and iframe sidebar apps with the plugin panels. AI-built panels are the module pro_ai_panels (see below).

One Action per connector

Every saved connector is the Action connector.{slug} (ConnectorAction). Its input schema and flags are read from the saved connector each time, so editing a connector needs no new registration:

Flag Value
automation true: rules and macros can run it
ai_tool true for read connectors (the AI tool registry, M5/M6, reads it); false for write connectors
dry_run_supported true: a dry run uses the connector’s test settings (mock or staging), never production
capability cliedesk_view_conversations (read), cliedesk_edit_conversation_fields (write)

Input: conversationId or contactId (the subject, scope-checked), via (agent, macro, button, panel, portal, test) and one property per agent or customer input. Conversation, contact and fixed inputs are not in the schema: the server always fills them (only an admin’s preset, a button default or a test sample, replaces them). Result: ok, outputs, explanation, mapped, card and variables (the scalar outputs; rules use them as {vars.name}).

People, rules (each active connector is in cliedesk_automation_actions and cliedesk_automation_contact_actions), macros (step {type: "connector", action: "connector.{slug}", input: "{JSON}"}), sidebar buttons, sidebar cards and later the AI agent and portal all run this Action, so the checks and the run log are the same everywhere.

Definition

The definition is JSON data, checked by Definition::normalize():

  • inputs[]: {name, label, type: text|number|bool, source: {kind, key?, value?}, required, description, format}. Kinds: conversation (key id, number, subject, status, priority or field:{key}), contact (id, name, email, phone, wp_user_id or field:{key}), fixed, agent (typed by a person), customer (“AI collects from customer”, stored now; the AI agent fills it later). format: "email" (and every contact.email input) accepts only a plain address: no quotes, backslashes, brackets or spaces, so the value cannot change a search expression of the service (Stripe query, Klaviyo filter).
  • steps[] (at most 10): {id, type: "request", method, url, headers[], body, bodyType: json|form|none, when} or {id, type: "action", action, input{}, when}. when is {left, op, right} with op eq, ne, contains, empty, not_empty, gt, lt.
  • Tokens: {inputs.name}, {outputs.name} (explanation), {steps.<id>.status}, {steps.<id>.body.a.b.0}. Values are URL-encoded in addresses and JSON-escaped in JSON bodies. Tokens may fill the path and query of a step URL, never its host or port. A filled URL with a . or .. path segment fails with connector_bad_url.
  • outputs[]: {name, path (JSONPath), step?, type: text|number|bool|list}. JSONPath subset: $, .name, ['name'], [0], [-1], [*], .* (no filters or scripts).
  • explanation, auth (none, bearer, basic with username, header / query with name and prefix), timeout (default 15, max 60), confirm, mapping[], card.title, test (mode, stagingUrl, mock, mocks{stepId}, sample{}).

Every save writes a version to Free’s config_versions (object type pro_connector); connectors.restore saves an older version as a new one.

Security

  • Requests go out only through Free’s SafeHttp (HTTPS, public addresses only, DNS pinned, no redirects, 1 MB responses). Private-network addresses fail with connector_blocked.
  • The credential is a vault row pro_connector.{uid}.auth (kind connector_auth); it is never returned, never in the definition and never logged. The credentials page shows where it is used (cliedesk_secret_usage).
  • The credential is bound to the definition saved when it was entered: the request hosts and the auth type with its header or parameter name (option cliedesk_pro_connector_bindings, uid => binding). A run, a test with an unsaved definition, a change or a restore that moves the secret to another host or place fails with connector_credential_unbound (422) until the credential is entered again. A secret saved before the binding existed is bound to the definition saved at the next change or run.
  • Staging tests never get the live secret: they use the staging secret (PUT /connectors/{id}/secret with staging: true, vault row pro_connector.{uid}.staging) or no credential at all.
  • connectors.test with an unsaved definition in live or staging mode is audited.
  • connectors.run refuses a connector with confirm unless the request sends confirm: true.
  • A connector that a sidebar button restricts (roles, a locked value, a confirmation) runs for people only through the button (connectors.run, connector.{slug}, panels and the AI get 403), unless they have cliedesk_manage_integrations; rules still run it. connectors.available leaves such connectors out for others and never returns fixed input values.
  • Mapped values are written only with edit rights: conversation fields need cliedesk_edit_conversation_fields, contact fields and custom records cliedesk_edit_contacts. A sidebar card run (via = panel) never writes.
  • The run log stores no request or response bodies.

Mapping and the connector source

Mapped field values are written with Fields::set_values() and field_values.source = 10 (Mapping:: SOURCE_CONNECTOR) with source_ref = connector:{id}. Free’s codes are 1–9; Free shows code 10 as “unknown” in field provenance until it names it. Transforms: date (PHP date format, default Y-m-d; epoch seconds or milliseconds), money (currency, minor for minor units), first.

Run log, health and jobs

Table cliedesk_pro_connector_logs: one row per run (via, mode, ok, HTTP status, error, duration, conversation, contact, actor). Failed runs inside another transaction are kept (Logs::write_durable()).

Job When What
cliedesk_pro_connector_logs_purge daily deletes runs older than pro_connectors.log_days (30)
cliedesk_pro_connector_spikes hourly notifies admins (cliedesk_notify, kind connector_errors) when at least spike_min_errors (5) runs and spike_error_pct (50%) failed in the last hour; once per 6 hours per connector
cliedesk_pro_connector_suggestions weekly keyword scan of unresolved conversations of the last 30 days

Templates and suggestions

Templates::all() (filter cliedesk_pro_connector_templates): stripe_customer, aftership, statuspage, hubspot_contact, licence_server (License Manager for WooCommerce; parameter base_url) and klaviyo_profile. Each has a mock response, so it passes the test console at once, and keywords for the suggestion scan. The scan is keyword based; AI-ranked suggestions come with the AI gateway (M5).

  • Buttons (setting pro_connectors.buttons): a native context panel pro_connector_buttons (“Actions”) with one card form per button. Each button is the registered rule action ext.pcb_{key} (kept out of the rule editor).
  • Apps (setting pro_connectors.apps): HTTPS pages on another origin. Bridge Actions: panel_apps.for, panel_apps.context (getContext) and panel_apps.run (runAction, only the app’s listed actions, audited). panel_apps.run fills conversationId, contactId and a subject id from the record on screen; an input that names another conversation or contact is refused (403). App origins drop the default port, and an app may not use the origin of the home, site or admin address. The JS side (app/connectors/bridge.ts, AppFrame.tsx) uses postMessage with origin and source checks and a sandboxed iframe:
parent.postMessage( { cliedesk: 1, id: 'r1', type: 'getContext' }, '*' );
parent.postMessage( { cliedesk: 1, id: 'r2', type: 'runAction', action: 'conversation.priority.set', input: { priority: 'high' } }, '*' );
parent.postMessage( { cliedesk: 1, type: 'resize', height: 420 }, '*' );
// Replies: { cliedesk: 1, id, ok: true, data } or { cliedesk: 1, id, ok: false, error }, posted to the app's origin.

The app fill is registered on the slot context.apps (props entity, entityId). Free’s AppPanels renders this slot after the native panels, in the conversation sidebar and on the contact page (M11).

  • Plugin panels (Panels\Adapters), registered when the plugin is detected: YITH Points and Rewards (ywpar_get_customer()), WPLoyalty (Wlr\App\Helpers\Base::getPointUserByEmail()), MailPoet (MailPoet\API\API::MP( 'v1' )), FluentCRM (FluentCrmApi( 'contacts' )), Klaviyo (the connector named in pro_connectors.klaviyo_connector) and WooCommerce product reviews. The email based panels use only verified identities: the linked WordPress user, or an email identity with verified_at.
  • Suggestions show as evidence only the conversations the reader may see.

AI-built panels

Module pro_ai_panels (Connectors/Panels/AiPanelsModule.php, depends on pro_connectors and pro_ai; UI app/connectors/AiPanelsSection.tsx, section Settings → Developer → AI-built panels). Tests: tests/phpunit/pro/connectors/AiPanelsTest.php, cliedesk-pro/app/__tests__/AiPanels.test.tsx.

  • Definition (PanelDefinition, JSON data): title, badge {text, tone}, places, outputs[] ({name, path, type, transform, format, currency, minor}: the panel’s own JSONPath over the connector’s last response), blocks[] (text, fields, list {source}, image, buttons with {label, url} or {button: key}), empty, linkHosts. Tokens {outputs.name} fill texts, field values and links. Rendered into Free’s card schema and checked with Cards::check().
  • Safety: no forms or free actions (a button item is an existing sidebar button, rendered with its own form, roles and confirmation); links and images only on the connector’s request hosts or linkHosts; a link that is a single token must fill to https on one of those hosts; tokens in a fixed link are URL-encoded. The AI may add a linkHosts entry only when the admin named that host in the description. An AI draft is checked leniently (a part that is not allowed is dropped and listed in generation.warnings), an admin’s save strictly (field errors).
  • Source connector: active, read, and no required agent or customer input (connector_panel_source, 422).
  • AI draft (PanelGenerator): (task reason), prompt connector_panels.generate with structured output. The description is the instruction; the connector description and the sample response are untrusted parts. AiGateway::submit(); cliedesk_ai_run_completed (option connector_panel) saves the checked answer as the asker’s draft. When blocked() is not null, generate answers 409 cliedesk_pro_ai_unavailable and the admin writes the panel by hand.
  • Versions: table cliedesk_pro_connector_panels (published definition, tested_hash, generation); every version is in Free’s config_versions (object type pro_connector_panel). A draft is the editor’s draft version (origin: ai|human in the snapshot). A draft is published only after a passing test of that exact definition (connector_panel_not_tested, 409). Publishing writes a live version (AI drafts: author_type AI, author_ref “admin copilot”, approved_by the admin) and is audited (connector_panels.publish). Rollback publishes a version that was live before (connector_panel_not_published, 409 otherwise) and is audited.
  • Sidebar: each published panel is the context panel aip_…; it runs connector.{slug} as the viewer with via = panel (scope, button restrictions and the run log as everywhere) and reads the response through Service::capture(). The response body never goes into the Action result. Drafts are never rendered for agents.

Routes (cliedesk_manage_integrations): GET|POST /connector-panels, GET /connector-panels/{id}, POST /connector-panels/generate ({connectorId | id, name?, description, sample?} → {panel, aiRunUid, pollUrl}), POST /connector-panels/preview ({connectorId, definition, sample}), POST /connector-panels/{id}/draft, POST /connector-panels/{id}/test ({version? | definition?, mode: mock|staging, conversationId?, contactId?}), POST /connector-panels/{id}/publish|rollback ({version}), POST /connector-panels/{id}/unpublish.

REST routes (cliedesk/v1)

GET|POST /connectors, GET|PATCH /connectors/{id}, POST /connectors/{id}/archive|restore|test|run, PUT /connectors/{id}/secret, GET /connectors/{id}/versions|health, GET /connectors/available|vocabulary, GET /connector-templates, POST /connector-templates/{key}/install, GET /connector-suggestions, POST /connector-suggestions/scan, POST /connector-suggestions/{template}/dismiss, GET|PUT /connector-buttons, GET|PUT /panel-apps, GET /panel-apps/for|context, POST /panel-apps/run.