Skip to content

Ticket Sync

Path: Evidence request detail (the Ticket Sync section)

Ticket Sync gives every evidence request an AuditBoard-style two-way link to an external ticketing system. From the evidence request you can open a ticket in your tracker, close it, and hold a single comment thread that stays in sync in both directions: an internal comment is pushed out to the ticket, and an external reply posted on the ticket flows back in as an inbound webhook and appears in the same thread. The provider is pluggable — the demo runs a self-contained mock, and a generic HMAC-signed webhook, Jira, and ServiceNow sit behind the same interface for real deployments.

Prerequisites — a real provider is buyer-configured

Two-way ticket sync against a real tracker is not turnkey out of the box. It needs a provider that you configure. A stock Community Edition install does not have Jira/ServiceNow/webhook credentials set, so the only out-of-the-box behavior is the mock provider (a self-contained demonstration that mints a synthetic mock-TCK-<n> and echoes a reply — it contacts no external system). The demo's working ticket flow is the mock, not a live integration.

To enable a real integration, set TICKET_PROVIDER and the matching credentials:

  • webhookTICKET_WEBHOOK_URL + TICKET_WEBHOOK_SECRET
  • jiraJIRA_BASE_URL + JIRA_API_TOKEN
  • servicenowSERVICENOW_BASE_URL + SERVICENOW_API_TOKEN

Without credentials, selecting a real provider leaves it gated: every ticket operation raises ProviderNotConfigured, surfaced as HTTP 503 naming the keys to set (the inbound webhook similarly stays closed without TICKET_WEBHOOK_SECRET). The in-app Setup readiness checklist flags Ticket Sync accordingly. Full key list in Configuration below.

Key Elements

  • Ticket Sync section — On the evidence request detail modal. Shows the linked ticket (provider, external id, deep link, sync state) and the comment thread.
  • Comment thread — Interleaves internal comments (left in DefendFlow) and external comments (arrived from the ticket), each labelled by source.
  • Provider — The org-configured ticketing backend. The demo default is the mock provider; real deployments point at a webhook, Jira, or ServiceNow.

Creating and Closing a Ticket

A ticket is created from one evidence request, using the org-configured provider:

POST   /api/v1/orgs/{org_id}/evidence-requests/{request_id}/ticket        # create + link
GET    /api/v1/orgs/{org_id}/evidence-requests/{request_id}/ticket        # read the link
POST   /api/v1/orgs/{org_id}/evidence-requests/{request_id}/ticket/close  # close it
DELETE /api/v1/orgs/{org_id}/evidence-requests/{request_id}/ticket        # unlink it

Create takes no body — the provider derives the ticket title/description from the evidence request. The response is the ticket link: its provider, external_id, the external_url deep link, the sync_state (synced / pending / error), and timestamps.

  1. Open the evidence request and find the Ticket Sync section.
  2. Create ticket — the provider mints the external ticket and the link appears with a deep link to it.
  3. Close when the work is done, or Unlink to detach without closing.

An evidence request holds one ticket link at a time; creating a second returns 409 Conflict.

Two-Way Comment Sync

The comment thread is the heart of the integration. Both endpoints live under the evidence request:

GET  /api/v1/orgs/{org_id}/evidence-requests/{request_id}/comments  # the thread
POST /api/v1/orgs/{org_id}/evidence-requests/{request_id}/comments  # add an internal comment

Outbound — Posting a comment (body: { "body": "..." }) records it as an internal comment. If a ticket is linked, the same comment is pushed to the provider, and the provider's external comment id is stamped onto the internal comment for de-duplication. With the mock provider the call also returns an echo: a synthetic external reply, so you can see the round trip on the demo without any external system.

Inbound — When someone comments on the real ticket, the provider calls back:

POST /api/v1/webhooks/tickets/inbound

The handler resolves the event to a request via the external_id of a known ticket link (the wire never supplies a raw org or request id), then records the external comment as a external comment in the same thread and can apply an optional PBC status update. Inbound comments are de-duplicated on external_comment_id, so a redelivered webhook does not double-post.

Provider Matrix

The active provider is chosen by the ticket_provider setting; an unknown value falls back to the mock provider.

Provider Value Behavior Use when
Mock mock Mints a synthetic mock-TCK-<n> ticket and echoes an external reply when you comment, so the two-way flow is visible end-to-end. Contacts no external system. The default on the demo and any offline environment.
Webhook webhook Generic provider: outbound events are HMAC-signed POSTs to your endpoint; inbound replies arrive via the inbound webhook. You want to integrate any tracker via a small adapter you host.
Jira jira Real Jira integration behind the same interface. You run Jira and supply its base URL + API token.
ServiceNow servicenow Real ServiceNow integration behind the same interface. You run ServiceNow and supply its instance URL + API token.

Demo default is Mock

The demo runs the mock provider. Creating a ticket returns a synthetic mock-TCK-<n> id, and posting a comment immediately echoes an external reply into the thread — so the round-trip sync is demonstrable with no external tracker wired up.

Jira and ServiceNow are configure-your-own

Jira and ServiceNow are implemented behind the same interface but are not active on the demo. Until their credentials are set, every ticket operation raises ProviderNotConfigured, which the endpoints surface as HTTP 503 (with a message naming the keys to set) rather than crashing the request.

The Generic Webhook Provider

The webhook provider lets you integrate any tracker without a bespoke backend. Outbound ticket events (ticket.create, ticket.close, ticket.comment) are sent as JSON POSTs to your ticket_webhook_url, and your system sends external comments and status changes back to the inbound webhook.

HMAC signature scheme

Both directions are authenticated with an HMAC over the raw request body:

  • Header: X-Signature
  • Algorithm: HMAC-SHA256, formatted as sha256=<hex digest>
  • Signed value: the exact raw body bytes (outbound events serialize the JSON deterministically — compact separators, sorted keys — so the signature is stable)
  • Secret: the shared ticket_webhook_secret

Outbound, the provider sets X-Signature on every POST it sends you. Inbound, the webhook handler reads X-Signature, recomputes the expected signature over the raw body, and compares it in constant time. A missing or mismatched signature is rejected with 401. If no shared secret is configured, inbound sync is closed by default and the endpoint returns 503.

Inbound payload

The inbound webhook body is a JSON object keyed by the ticket's external_id:

{
  "external_id": "mock-TCK-1",
  "comment": {
    "external_comment_id": "ext-42",
    "author": "Jane (ext)",
    "body": "Attached the SOC 2 report."
  },
  "status": "submitted"
}

external_id is required and resolves the event to a linked ticket. The optional comment becomes an external comment (de-duplicated on external_comment_id), and the optional status updates the PBC request. The response is { "success": true, "applied": ... }.

Configuration

All keys are environment-driven settings:

Key Purpose
TICKET_PROVIDER Active provider: mock (default), webhook, jira, or servicenow
TICKET_WEBHOOK_URL Outbound endpoint for the generic webhook provider
TICKET_WEBHOOK_SECRET Shared HMAC secret for outbound signing and inbound verification
JIRA_BASE_URL Jira instance base URL
JIRA_API_TOKEN Jira API token
SERVICENOW_BASE_URL ServiceNow instance base URL
SERVICENOW_API_TOKEN ServiceNow API token

A provider is considered configured only when its credentials are present; until then it stays gated and any ticket operation returns 503. The inbound webhook is similarly gated on TICKET_WEBHOOK_SECRET — without it, inbound sync stays closed.

Who Can Do What

Action Required permission
View the ticket link and comment thread Org read
Add a comment Org read
Create / close / unlink a ticket Org configure
Inbound webhook None — authorized by the HMAC X-Signature, not an org login

Reading the thread and leaving a comment need only read access, so anyone working the evidence request can participate. Creating, closing, or unlinking the ticket requires the org configure permission. The inbound webhook is a separate, unauthenticated-by-login path: it is authorized solely by the HMAC signature over the raw body.