Skip to main content

CTI Adapter Setup

Pipelinq ships with a pluggable Computer Telephony Integration (CTI) adapter that delivers inbound screen-pop, outbound click-to-dial, automatic contactmoment creation and a disposition workflow against three platforms:

  • CallVoip (Dutch SME market leader)
  • RingCentral (international UCaaS)
  • Asterisk (self-hosted PBX)

Custom platforms can be added by registering a class that implements OCA\Pipelinq\Service\Cti\CtiAdapterInterface against the OCA\Pipelinq\Service\Cti\AdapterRegistry.

Spec

  • OpenSpec change: openspec/changes/cti-screenpop-adapter/
  • Issue: #175

High-level flow

Inbound call:
Telephony platform ─POST webhook▶ /api/cti/webhook/{platform}
└▶ adapter.verifyWebhookSignature(...)
└▶ adapter.handleInboundWebhook(...) ─▶ CtiWebhookResult
└▶ CtiService.handleWebhook(...) ─▶ event log + contactmoment

Outbound call:
Vue UI ─POST /api/cti/click-to-dial─▶ CtiService.originateCall(...)
└▶ adapter.originateCall(...) ─▶ platform REST API
└▶ contactmoment (outbound, pending)

Webhook URL

The platform should POST to:

POST https://<your-nextcloud>/index.php/apps/pipelinq/api/cti/webhook/<platform>

<platform> is one of callvoip, ringcentral, asterisk, or any custom identifier registered in the AdapterRegistry.

Configuration via admin UI

  1. Navigate to Pipelinq → Settings → CTI integration.
  2. Pick the platform, enter the API base URL, the OpenConnector credentials reference (the credentials themselves never live in Pipelinq), the screen-pop delay and the default outbound caller-ID.
  3. Click Test connection to verify the adapter resolves and the configuration parses.

Per-platform configuration keys

The following IAppConfig keys (under app id pipelinq) are read by the adapters at runtime — set them via occ config:app:set pipelinq <key> --value '<value>' (or via OpenConnector credential mapping):

AdapterKeyNotes
CallVoipcti_callvoip_api_base_urlREST API base.
CallVoipcti_callvoip_api_keyBearer token.
CallVoipcti_callvoip_webhook_secretHMAC-SHA256 shared secret.
RingCentralcti_ringcentral_api_base_urle.g. https://platform.ringcentral.com.
RingCentralcti_ringcentral_access_tokenOAuth bearer.
RingCentralcti_ringcentral_webhook_tokenValidation-Token header value.
Asteriskcti_asterisk_api_base_urlARI base.
Asteriskcti_asterisk_ari_userARI username.
Asteriskcti_asterisk_ari_passARI password.
Asteriskcti_asterisk_contextDefault from-internal.
Asteriskcti_asterisk_webhook_secretShared secret query param.
Alldefault_country_codeISO-3166 alpha-2; default NL.
Allcti_escalation_queueQueue for escalated disposition tasks.

Webhook authentication per platform

  • CallVoip — header X-Pipelinq-Signature = HMAC-SHA256(rawBody, webhook_secret).
  • RingCentral — header Validation-Token = configured OAuth access token (constant-time compared).
  • Asterisk — query parameter signature= = configured shared secret.

Adapter signature verification is fail-closed; an invalid signature is logged to ctiEventLog and responds with 422 Unprocessable Entity (the platform is expected to retry on 5xx, not on 4xx, so signature failures do not snowball).

Disposition outcomes

The Vue CtiDispositionModal collects subject + outcome + notes after every call. Outcomes drive workflow:

OutcomeSide-effect
resolvedCloses contactmoment.
callbackCreates a task of type terugbelverzoek (callback-management).
escalatedCreates a task of type opvolgtaak in cti_escalation_queue.
wrong-number / no-answer / abandonedCloses contactmoment with notes.

Recording metadata

Audio files stay on the telephony platform. Pipelinq only stores the recording URL and the platform-reported retention expiry on the contactmoment (recording_url, recording_retention_expires_at).

Event log

The CTI admin event log (Pipelinq → Settings → CTI event log) shows the last 30 days of received webhook events. Older events are purged by the OCA\Pipelinq\BackgroundJob\CtiEventLogCleanupJob (runs daily).