Skip to content

Webhooks Integration with TSplus Remote Support

Overview

Webhooks let you connect TSplus Remote Support to your own systems (ticketing, CRM, SIEM, internal tools). When an event happens in your subscription, Remote Support sends an HTTP POST request — containing a JSON payload describing the event — to a URL that you control.

Each request is cryptographically signed so your server can verify that it genuinely comes from Remote Support and was not tampered with.

Typical use cases:

  • Automatically create or update a ticket when a support session ends.
  • Archive session chat transcripts in your own storage.
  • Trigger internal notifications or automation workflows.

Prerequisites

To configure webhooks, make sure you have:

  • A subscription administrator account.
  • A publicly reachable HTTPS endpoint able to receive POST requests.
  • The ability to read HTTP request headers and the raw request body on your server (required to verify the signature).

Configuring a webhook

  1. Open the TSplus Remote Support admin console.

  2. In the left menu, expand Integration and click Webhooks.

    Admin console: Integration menu with the Webhooks entry

  3. Click Add a webhook.

    Webhooks list with the Add a webhook button

  4. Fill in the form:

    • URL — the HTTPS endpoint that will receive the events.
    • Description (optional) — a label to help you identify this endpoint.
    • Events — select at least one event type to subscribe to.
  5. Click Save.

    Add a webhook form

  6. A secret is generated and displayed once. Copy it now and store it securely — it is used to verify the signature of incoming requests and will not be shown again.

    Webhook secret shown once after creation

Security: For your protection, the URL is validated when you save it. Endpoints pointing to localhost or private/internal IP addresses are rejected.

Managing your webhooks

From the Webhooks list you can:

  • Send a test event (flask icon) — enqueues a sample delivery so you can confirm your endpoint receives and accepts requests.
  • Edit (pencil icon) — change the URL, description, subscribed events, or enable/disable the endpoint.
  • Delete (trash icon) — permanently remove the endpoint.

Each endpoint shows a status:

  • Active — the endpoint is enabled and receiving events.
  • Disabled — the endpoint was manually disabled.
  • Auto-disabled — Remote Support automatically disabled the endpoint after 10 consecutive failed deliveries. Fix the endpoint and re-enable it from the Edit form.

To inspect individual delivery attempts, filter past events, or retry a failed delivery, see Webhook Delivery Tracking.

Payload format

Every event is delivered as a POST request with a JSON body and the following headers:

HeaderDescription
Content-Typeapplication/json
X-Webhook-SignatureHMAC-SHA256 signature of the raw body, prefixed with sha256=
X-Webhook-IdUnique event identifier (use it for idempotency on your side)
X-Webhook-TimestampISO 8601 timestamp of the delivery
User-AgentRemoteSupport-Webhook/1.0

All events share a common envelope. Only the content of data changes depending on the event type:

{
"id": "evt_abc123def456",
"type": "session.ended",
"created_at": "2026-07-10T15:00:00Z",
"subscription_key": "XXXX-XXXX-XXXX",
"data": { }
}

session.started

Sent when a new support session is created (the first agent connects to a computer).

{
"id": "evt_abc123def456",
"type": "session.started",
"created_at": "2026-07-10T14:30:00Z",
"subscription_key": "XXXX-XXXX-XXXX",
"data": {
"remote_support_id": "ABC123",
"computer_name": "Front-desk PC",
"started_at": "2026-07-10T14:30:00Z"
}
}

session.ended

Sent when a support session ends (all participants disconnected). The payload includes the full chat transcript collected during the session.

{
"id": "evt_xyz789ghi012",
"type": "session.ended",
"created_at": "2026-07-10T15:00:00Z",
"subscription_key": "XXXX-XXXX-XXXX",
"data": {
"remote_support_id": "ABC123",
"computer_name": "Front-desk PC",
"started_at": "2026-07-10T14:30:00Z",
"ended_at": "2026-07-10T15:00:00Z",
"duration_seconds": 1800,
"is_abnormal_closure": false,
"chat_transcript": [
{ "timestamp": "2026-07-10T14:31:00Z", "sender": "agent", "message": "Hello, how can I help you?" },
{ "timestamp": "2026-07-10T14:31:30Z", "sender": "client", "message": "My screen is black" }
]
}
}

is_abnormal_closure is true only when a session is closed by the platform after an unexpected relay restart. In that case the chat_transcript is empty.

participant.joined

Sent when an agent joins a session.

{
"id": "evt_join789abc",
"type": "participant.joined",
"created_at": "2026-07-10T14:32:00Z",
"subscription_key": "XXXX-XXXX-XXXX",
"data": {
"remote_support_id": "ABC123",
"user_name": "Jane Doe",
"joined_at": "2026-07-10T14:32:00Z"
}
}

participant.left

Sent when an agent leaves a session. duration_seconds is how long that agent was connected.

{
"id": "evt_left456def",
"type": "participant.left",
"created_at": "2026-07-10T14:37:00Z",
"subscription_key": "XXXX-XXXX-XXXX",
"data": {
"remote_support_id": "ABC123",
"user_name": "Jane Doe",
"duration_seconds": 300,
"left_at": "2026-07-10T14:37:00Z"
}
}

unattended.connected

Sent when a session is established through unattended access (an agent connecting with a password to a computer that is already online, as opposed to a live user manually sharing their screen). It fires exactly like session.started, but only for unattended-access sessions. user_name identifies the agent connecting.

{
"id": "evt_unatt123on",
"type": "unattended.connected",
"created_at": "2026-07-10T14:30:00Z",
"subscription_key": "XXXX-XXXX-XXXX",
"data": {
"remote_support_id": "ABC123",
"computer_name": "Front-desk PC",
"user_name": "Jane Doe",
"connected_at": "2026-07-10T14:30:00Z"
}
}

unattended.disconnected

Sent when an unattended-access session ends (all participants disconnected). It fires exactly like session.ended, but only for unattended-access sessions; no single participant is attributed since the session as a whole ends. duration_seconds is how long the session lasted.

{
"id": "evt_unatt456off",
"type": "unattended.disconnected",
"created_at": "2026-07-10T15:30:00Z",
"subscription_key": "XXXX-XXXX-XXXX",
"data": {
"remote_support_id": "ABC123",
"computer_name": "Front-desk PC",
"duration_seconds": 3600,
"disconnected_at": "2026-07-10T15:30:00Z"
}
}

file.transferred

Sent when a file is transferred during a session. Only metadata is sent — the file content is never stored nor transmitted. direction is "upload" (agent to remote machine) or "download" (remote machine to agent). user_name identifies the agent, and may be empty when a download cannot be attributed to a single agent.

{
"id": "evt_file456abc",
"type": "file.transferred",
"created_at": "2026-07-10T14:45:00Z",
"subscription_key": "XXXX-XXXX-XXXX",
"data": {
"remote_support_id": "ABC123",
"user_name": "Jane Doe",
"file_name": "diagnostic.zip",
"file_size_bytes": 2048576,
"direction": "download",
"timestamp": "2026-07-10T14:45:00Z"
}
}

Verifying the signature

Your endpoint should always verify the signature before trusting a request. Anyone who knows your URL could otherwise send fake events; without the secret, they cannot produce a valid signature.

To verify a request:

  1. Read the raw request body (the exact bytes received — do not re-serialize the JSON).
  2. Compute HMAC-SHA256(rawBody, yourSecret) and hex-encode it.
  3. Prefix it with sha256= and compare it to the X-Webhook-Signature header using a constant-time comparison.

Node.js

const crypto = require('crypto');
function verifyWebhook(rawBody, signatureHeader, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody, 'utf8')
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Python

import hmac
import hashlib
def verify_webhook(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode("utf-8"), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header or "")

Delivery and retries

  • Your endpoint should respond with a 2xx status code as quickly as possible. The request times out after 10 seconds.
  • If a delivery fails, Remote Support retries with an exponential backoff schedule: 10s, 30s, 1min, 5min, 15min, 1h, 4h, 24h (up to 8 attempts over 24 hours).
  • Retries happen on connection errors, HTTP 429, and 5xx responses. Other 4xx responses are treated as permanent failures and are not retried.
  • After 10 consecutive failed deliveries, the endpoint is automatically disabled.

To avoid processing the same event twice (for example after a retry), use the X-Webhook-Id header (or the id field in the payload) as an idempotency key.

Available events

EventDescription
session.startedA new support session was created (first agent connects).
session.endedA support session has ended. Includes duration and the full chat transcript.
participant.joinedAn agent joined a session.
participant.leftAn agent left a session. Includes how long they were connected.
unattended.connectedAn unattended computer came online.
unattended.disconnectedAn unattended computer went offline. Includes how long it stayed connected.
file.transferredA file was transferred during a session (metadata only: name, size, direction).