Skip to documentation

Signals

Signals are the imported transcripts, tickets, reviews, and reports that feed Discovery. Use these endpoints to bring in sources and add reviewed Evidence claims when processing misses an important point.

12 endpoints

GET

List signals

GET /external/v1/signals

List a bounded page of signals in your workspace. Signals are imported pieces of customer or market evidence such as transcripts, support tickets, reviews, and discovery reports.

Requirements

API scopes required:
signals:read

Request

Parameters

NameTypeDescription
limit numberMaximum number of items to return (default: 20, maximum: 100)
offset numberNumber of items to skip (default: 0)
externalId stringExact identifier of the record in its source system, such as a Fireflies transcript ID.
integrationId uuidOnly signals imported through this workspace integration.
sourceType stringComma-separated source filters. Each value matches a provider type such as fireflies, a source facet such as fireflies:transcript, or a source type.
initiativeId stringOnly signals with an accepted evidence link to this Initiative. Accepts the Initiative UUID or public ID, such as INITIATIVE-7.
studyId stringOnly signals attached to this Study as interviews. Accepts the Study UUID or public ID, such as STUDY-172.
status stringComma-separated processing statuses: pending, processing, processed, or failed.
accountId uuidSignals linked to this account directly, or through an insight linked to it. Only direct links appear in accountIds. Comma-separate several IDs to match any of them.
updatedSince iso-dateOnly signals whose own fields changed at or after this ISO-8601 timestamp, oldest change first. Pass the latest updatedAt you have received to sync incrementally, and dedupe by id. Links added later to insights, Initiatives, or Studies do not count as changes.
include stringComma-separated extras. 'raw' adds rawData: the whole stored data column, including every attributed transcript turn and the provider's import response. Opt-in because it can exceed several hundred KB per signal.

Responses

200
Success

Signals were successfully retrieved. Pagination metadata is returned in X-Total-Count, X-Limit, X-Offset, and X-Has-More headers.

Schema
Array<Signal>

Example Request

GET
/external/v1/signals
curl
curl -X GET https://zentrik.ai/api/external/v1/signals?limit=10 \
  -H 'Authorization: Bearer YOUR_API_KEY'

Example Response

200 OK
json
[
  {
    "id": "uuid",
    "name": "Support Ticket - 3/20/24, 10:00 AM",
    "publicId": "SIGNAL-42",
    "workspaceId": "workspace-uuid",
    "status": "processed",
    "context": "support_request",
    "signalType": null,
    "processorType": "zendesk",
    "providerType": "zendesk",
    "evidenceKind": "support_ticket",
    "analysisProfile": "support_ticket",
    "provenance": {
      "providerType": "zendesk",
      "evidenceKind": "support_ticket",
      "analysisProfile": "support_ticket"
    },
    "sourceFacet": "zendesk:support_ticket",
    "sourceLabel": "Zendesk support ticket",
    "sourceLinks": [
      {
        "name": "Open Zendesk ticket",
        "url": "https://example.zendesk.com/agent/tickets/12345",
        "type": "support_ticket",
        "primary": true
      }
    ],
    "source": {
      "type": "zendesk",
      "external_data": {
        "ticketId": "12345"
      }
    },
    "data": {
      "subject": "Users cannot reset password",
      "severity": "high"
    },
    "transcript": null,
    "import": null,
    "insightIds": [],
    "accountIds": [],
    "initiativeIds": [],
    "studyIds": [],
    "accountId": null,
    "accountExternalId": null,
    "externalId": "external-123",
    "createdAt": "2024-03-20T10:00:00Z",
    "updatedAt": "2024-03-20T10:00:00Z"
  }
]
GET

Get one signal

GET /external/v1/signals/:publicId

Retrieve a single signal by its public ID.

Requirements

API scopes required:
signals:read

Request

Parameters

NameTypeDescription
publicId *stringWorkspace-scoped public ID, such as SIGNAL-42
include stringComma-separated extras. 'raw' adds rawData: the whole stored data column. Opt-in because a processed transcript's column can exceed several hundred KB.

Responses

200
Success

The signal was successfully retrieved.

Schema
404
Not Found

No signal found with the provided ID.

Example Request

GET
/external/v1/signals/:publicId
curl
curl -X GET https://zentrik.ai/api/external/v1/signals/SIGNAL-42 \
  -H 'Authorization: Bearer YOUR_API_KEY'

Example Response

200 OK
json
{
  "id": "uuid",
  "name": "Support Ticket - 3/20/24, 10:00 AM",
  "publicId": "SIGNAL-42",
  "workspaceId": "workspace-uuid",
  "status": "processed",
  "context": "support_request",
  "signalType": null,
  "processorType": "zendesk",
  "providerType": "zendesk",
  "evidenceKind": "support_ticket",
  "analysisProfile": "support_ticket",
  "provenance": {
    "providerType": "zendesk",
    "evidenceKind": "support_ticket",
    "analysisProfile": "support_ticket"
  },
  "sourceFacet": "zendesk:support_ticket",
  "sourceLabel": "Zendesk support ticket",
  "sourceLinks": [
    {
      "name": "Open Zendesk ticket",
      "url": "https://example.zendesk.com/agent/tickets/12345",
      "type": "support_ticket",
      "primary": true
    }
  ],
  "source": {
    "type": "zendesk",
    "external_data": {
      "ticketId": "12345"
    }
  },
  "data": {
    "sessionId": "session-123"
  },
  "transcript": null,
  "import": null,
  "insightIds": [
    "insight-uuid"
  ],
  "accountIds": [],
  "initiativeIds": [
    "initiative-uuid"
  ],
  "studyIds": [],
  "accountId": null,
  "accountExternalId": null,
  "externalId": "external-123",
  "createdAt": "2024-03-20T10:00:00Z",
  "updatedAt": "2024-03-20T10:00:00Z"
}
POST

Create a signal

POST /external/v1/signals

Create a new signal by sending the text you want Zentrik to analyze. This is the recommended public API flow for transcripts, support tickets, reviews, structured feedback records, and discovery reports. Advanced raw signal bodies are also accepted on this same endpoint and are auto-queued.

Requirements

API scopes required:
signals:write

Request

Request body (application/json)

namestring

Required non-blank string for raw signals. Optional for typed text signals, which generate a name from the signal type and timestamp when omitted, null, or blank. Invalid names return 400 before an import run or signal is created.

textstring
Required

The raw transcript, support ticket, review, structured feedback record, or discovery report text that Zentrik should process into insights. Transcript input may be copied or exported with speaker labels, timestamps, captions, markdown headings, and common meeting metadata; Zentrik preserves the source and normalizes its conversation structure automatically.

signalType'transcript' | 'meeting_notes' | 'ai_notes' | 'reconstructed_notes' | 'support_ticket' | 'review' | 'feedback_record' | 'discovery_report'
Required

What kind of text you are sending. Use meeting_notes for notes, ai_notes for an AI summary, and reconstructed_notes for material rebuilt from notes and recollection. These are not transcripts. New text signals are automatically queued for processing after creation.

providerTypestring

Optional source system or channel identifier, such as google_meet, granola, app_store, reddit, g2, manual_csv, or external_api. Keep the provider separate from the content type: Google Meet can supply a transcript or notes.

evidenceKindstring

Optional evidence shape override. For typed text this defaults from signalType and usually does not need to be sent.

analysisProfile'default_transcript' | 'support_ticket' | 'survey_response' | 'discovery_report' | 'community_discussion'

Optional processing profile override. For typed text this defaults from signalType.

additionalContextstring

Optional notes to help Zentrik interpret the text correctly. Use this for things like where the text came from, what batch it belongs to, or any lightweight analyst note. This is treated as supplemental context, not an instruction override.

occurredAtiso-date

Optional timestamp representing when the original signal happened. When provided, it is used as the signal creation timestamp for trend accuracy.

productIdsuuid[]

Optional list of products to narrow the product context used during processing.

accountIduuid

Optional account to associate with this signal and the insights created from typed text processing.

accountIdsuuid[]

Optional list of account IDs to associate directly with this signal. Use accountId for the common single-account case.

accountExternalIdstring

Optional stable client-side account identifier, such as crm-example-account. Prefer this for CRM automations that should not persist backend UUIDs.

participants{ email?: string; contactId?: uuid; accountId?: uuid; name?: string; role?: string; affiliation?: "external" | "internal" | "unknown" }[]

People observed in this record. Add a valid email or an existing Contact ID. Mark colleagues as internal. Zentrik changes People only when participantPolicy requests it.

participantPolicy'none' | 'match_existing' | 'create_missing'

Controls participant handling. Omit it or use none for no People changes. Use match_existing to link only saved People, or create_missing to create reliably identified People.

createMissingAccountsboolean

When participantPolicy is create_missing, also allow one missing Account to be created from each unambiguous professional email domain. Defaults to false; public email domains never create Accounts.

sourceKeystring

Stable namespace for externalId, such as granola.note or crm.call. Set it when several clients send records into the same workspace.

externalIdstring

Stable record identifier within sourceKey. Later deliveries reuse the Signal and can add newly available participant links. Use Idempotency-Key only to replay one exact request.

sourceLinks{ name?: string; url: string; type?: string; primary?: boolean }[]

Links users should land on from Zentrik, such as the original app store review, G2 review, Reddit thread or comment, Gartner report, support ticket, source row, or meeting link. HTTP and HTTPS URLs are normalized and returned on the Signal object.

sourceExternalDataobject

Provider-specific metadata to keep with the signal, such as reviewId, rating, locale, reportId, threadId, productSlug, or dataset. For Granola, send noteId for a public note ID or granolaDocumentId for a legacy desktop ID; send both when known. Zentrik stores this under source.external_data.

Responses

201
Created

The signal was successfully created and queued for asynchronous processing. Create responses include a queued job id.

Schema

Example Request

POST
/external/v1/signals
json
{
  "name": "G2 Reviews - March Batch",
  "text": "Users love the product overall, but several reviewers mention that exports are hard to find and slow to complete for large datasets.",
  "signalType": "review",
  "providerType": "g2",
  "externalId": "g2-review:review-row-1",
  "additionalContext": "Public review batch collected from G2 and Capterra.",
  "occurredAt": "2025-03-11T14:30:00Z",
  "productIds": [
    "product-uuid-1"
  ],
  "participants": [
    {
      "email": "buyer@example.com",
      "name": "Primary product contact",
      "role": "VP Product",
      "affiliation": "external"
    }
  ],
  "participantPolicy": "create_missing",
  "createMissingAccounts": false,
  "sourceExternalData": {
    "reviewId": "review-row-1",
    "rating": 3,
    "productSlug": "example-product"
  },
  "sourceLinks": [
    {
      "name": "Open G2 review",
      "url": "https://www.g2.com/products/example-product/reviews/review-row-1",
      "type": "review",
      "primary": true
    }
  ]
}

Example Response

201 Created
json
{
  "id": "uuid",
  "name": "Review - 3/11/25, 2:30 PM",
  "publicId": "SIGNAL-43",
  "workspaceId": "workspace-uuid",
  "status": "processing",
  "context": null,
  "signalType": "review",
  "processorType": "manual-text",
  "providerType": "g2",
  "evidenceKind": "review",
  "analysisProfile": "survey_response",
  "provenance": {
    "providerType": "g2",
    "evidenceKind": "review",
    "analysisProfile": "survey_response"
  },
  "sourceFacet": "g2:review",
  "sourceLabel": "G2 Review",
  "sourceLinks": [
    {
      "name": "Open G2 review",
      "url": "https://www.g2.com/products/example-product/reviews/review-row-1",
      "type": "review",
      "primary": true
    }
  ],
  "source": {
    "type": "manual-text",
    "external_data": {
      "reviewId": "review-row-1",
      "rating": 3,
      "productSlug": "example-product",
      "links": [
        {
          "name": "Open G2 review",
          "url": "https://www.g2.com/products/example-product/reviews/review-row-1",
          "type": "review",
          "primary": true
        }
      ]
    }
  },
  "data": {
    "s3Key": "signals/manual-text/workspace-uuid/uuid.txt",
    "productIds": [
      "product-uuid-1"
    ],
    "accountId": "account-uuid-1",
    "accountExternalId": "crm-example-account",
    "additionalContext": "Public review batch collected from G2 and Capterra.",
    "uploadedAt": "2025-03-21T10:00:00Z"
  },
  "insightIds": [],
  "accountId": "account-uuid-1",
  "accountIds": [
    "account-uuid-1"
  ],
  "contactIds": [
    "contact-uuid-1"
  ],
  "externalId": "g2-review:review-row-1",
  "createdAt": "2025-03-11T14:30:00Z",
  "updatedAt": "2025-03-21T10:00:00Z",
  "jobId": "job-123",
  "processing": {
    "lastJobId": "job-123",
    "startedAt": "2025-03-21T10:00:00Z",
    "processedAt": null,
    "failedAt": null,
    "lastError": null
  }
}
POST

Create Evidence for a signal

POST /external/v1/signals/:publicId/evidence

Add a reviewed, source-linked Evidence claim to an existing Signal when processing misses an important point. The description is the reviewer-authored claim. Optionally include extracts as one exact, continuous quotation from the stored Signal text; the API verifies it before saving. Read the Signal source and its Evidence before retrying a timed-out request to avoid duplicates.

Requirements

API scopes required:
signals:read
signal-evidence:curate

Request

Parameters

NameTypeDescription
publicId *stringWorkspace-scoped Signal ID, such as SIGNAL-42.

Request body (application/json)

titlestring
Required

Standalone Evidence title, 3–500 characters.

descriptionstring
Required

Reviewed source-scoped claim and context, 3–10,000 characters. This is not stored as a verbatim extract.

extractsstring | null

Optional exact, continuous quote from the persisted Signal text. The API rejects text that is not a literal passage. Omit or send null when the claim is supported by context rather than a short quote.

categorystring
Required

Evidence category, such as Product request, Product bug, Positive product feedback, Market / decision context, or Other.

productIduuid | null

Optional product assignment in this workspace.

featureIdsuuid[]

Optional feature assignments. Each feature must belong to the selected product and workspace.

Responses

201
Created

The Evidence claim was attached to the Signal and returned in the same shape as Evidence detail reads.

Schema
SignalEvidence
400
Invalid request

A field is missing, unsupported, or outside its allowed length or category.

403
Missing scope

The API key needs signals:read and signal-evidence:curate.

404
Not found

The Signal does not exist in this workspace.

Example Request

POST
/external/v1/signals/:publicId/evidence
curl
curl -X POST https://zentrik.ai/api/external/v1/signals/SIGNAL-42/evidence \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"title":"Filter reports by date range","description":"The participant needs a date range filter on reports.","category":"Product request"}'

Example Response

201 Created
json
{
  "id": "evidence-uuid",
  "publicId": "EVIDENCE-123",
  "title": "Filter reports by date range",
  "description": "The participant needs a date range filter on reports.",
  "extracts": null,
  "category": "Product request",
  "evidenceType": "need",
  "signalId": "signal-uuid",
  "resolvedAt": null,
  "resolution": null,
  "resolvedByUserId": null,
  "dismissedAt": null
}
PATCH

Update a signal

PATCH /external/v1/signals/:publicId

Update fields of an existing signal, such as metadata or linked insights. Do not use a metadata patch to replace source text. Use the preview and source-revisions endpoints for a reviewed source correction; repeating a create request does not replace source text. Once sourceRevision is above zero, source, data, importMetadata, and status cannot be replaced through metadata updates.

Requirements

API scopes required:
signals:write

Request

Parameters

NameTypeDescription
publicId *stringWorkspace-scoped public ID, such as SIGNAL-43

Request body (application/json)

sourceobject

Updated source descriptor for the signal.

dataobject

Updated arbitrary context payload.

insightIdsstring[]

Replace the list of linked insight IDs. A link added here stays until it is removed here. Removing an insight also removes it from this signal's evidence, so later evidence changes do not link it again.

externalIdstring

Updated external record identifier.

status'pending' | 'processed'

Processing status for the signal.

contextstring

Persisted signal context, such as user_interview or support_request.

Responses

200
Updated

The signal was successfully updated.

Schema

Example Request

PATCH
/external/v1/signals/:publicId
curl
curl -X PATCH https://zentrik.ai/api/external/v1/signals/SIGNAL-43 \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"insightIds": ["insight-uuid"]}'
DELETE

Delete a signal

DELETE /external/v1/signals/:publicId

Permanently delete a signal from the workspace.

Requirements

API scopes required:
signals:delete

Request

Parameters

NameTypeDescription
publicId *stringWorkspace-scoped public ID, such as SIGNAL-43

Responses

200
Success

The signal was successfully deleted.

Schema
{ message: string }

Example Request

DELETE
/external/v1/signals/:publicId
curl
curl -X DELETE https://zentrik.ai/api/external/v1/signals/SIGNAL-43 \
  -H 'Authorization: Bearer YOUR_API_KEY'

Example Response

200 OK
json
{
  "message": "Deleted"
}
POST

Process a signal

POST /external/v1/signals/:publicId/process

Queue signal processing for an existing signal. Use this for explicit re-runs or manual retries.

Requirements

API scopes required:
signals:write

Request

Parameters

NameTypeDescription
publicId *stringWorkspace-scoped public ID, such as SIGNAL-43.

Responses

201
Queued

The signal was queued for asynchronous processing.

Schema
{ jobId: string }

Example Request

POST
/external/v1/signals/:publicId/process
curl
curl -X POST https://zentrik.ai/api/external/v1/signals/SIGNAL-43/process \
  -H 'Authorization: Bearer YOUR_API_KEY'

Example Response

201 Created
json
{
  "jobId": "job-456"
}
GET

Preview source correction

GET /external/v1/signals/:publicId/source-revision

Check whether an imported manual-text or manual-transcript Signal can be corrected. The response includes a sourceToken, revision number, Evidence counts, blockers, and up to 500 downstream target IDs for review. downstreamTruncated means the target list is incomplete. Connected providers, Granola, Studies, downstream links, and curated Evidence require review and cannot be corrected with this operation. Availability also requires the source-correction rollout to be enabled. The preview does not reserve the Signal; the write checks all conditions again, including queue state.

Requirements

API scopes required:
signals:read

Request

Parameters

NameTypeDescription
publicId *stringWorkspace-scoped Signal ID.

Responses

200
Preview

Current source token and correction impact. Blockers prevent a write.

Schema
SourceRevisionPreview

Example Response

200 OK
json
{
  "publicId": "SIGNAL-43",
  "sourceRevision": 0,
  "sourceToken": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "eligible": true,
  "blockers": [],
  "impact": {
    "generatedEvidence": 1,
    "protectedEvidence": 0,
    "downstreamLinks": 0,
    "truncated": false
  },
  "downstream": [],
  "downstreamTruncated": false,
  "processing": "explicit_process_required"
}
GET

Read stored signal source text

GET /external/v1/signals/:publicId/source-text

Read the current persisted source body in the API key workspace. This is the stored text available to processing, not a provider refresh or an analyst summary. The ordinary Signal include=raw response may expose only an S3 pointer. The response is private and not cached.

Requirements

API scopes required:
signals:read

Request

Parameters

NameTypeDescription
publicId *stringWorkspace-scoped Signal ID.

Responses

200
Success

Persisted source text and its current revision and date.

Schema
SourceText
404
Not found

The Signal does not exist in this workspace.

409
Unavailable

The stored source body is missing or empty.

Example Response

200 OK
json
{
  "publicId": "SIGNAL-43",
  "sourceRevision": 0,
  "occurredAt": "2026-03-18T14:51:17.000Z",
  "sourceToken": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "text": "The complete imported source record."
}
POST

Correct imported source text

POST /external/v1/signals/:publicId/source-revisions

Correct the imported copy of one source, without changing its Signal ID, external ID, provider, product scope, Accounts, or People. Requires an Idempotency-Key header (1–200 characters), the sourceToken from a fresh preview, corrected native text, and a reason. The transaction archives the old source and uncurated, unlinked generated Evidence, removes those obsolete captures, and sets status to pending. It does not queue processing. Use the revision-specific process route from the receipt, then read the Signal status, processing receipt, and Evidence. A lost response is safe to retry with the same API key, Idempotency-Key, and exact body; a different body returns 409. Replaying returns the original acceptance receipt, not current processing status. Never remove curated links to bypass a blocker.

Requirements

API scopes required:
signals:write

Request

Parameters

NameTypeDescription
publicId *stringWorkspace-scoped Signal ID.

Request body (application/json)

expectedSourceTokenstring
Required

Exact 64-character token returned by the current preview. A stale token returns 409.

textstring
Required

Corrected native source text. Nonblank, at most 100,000 characters. Replaces competing text aliases and derived transcript artifacts.

reasonstring
Required

Nonblank correction reason, at most 1,000 characters. Retained with the audit record.

occurredAtiso-date

Verified source date, only when it also needs correction. Otherwise the date is unchanged.

Responses

201
Correction accepted

A durable correction receipt. This is not a processing-complete receipt.

Schema
SourceRevisionReceipt
400
Invalid correction

Missing Idempotency-Key, unsupported fields, or invalid text, reason, token, or date.

409
Review required

Stale source, changed request key input, disabled rollout, active processing, provider ownership, curated Evidence, downstream links, or an impact above 200 Evidence rows. No correction is applied.

Example Request

POST
/external/v1/signals/:publicId/source-revisions
curl
curl -X POST https://zentrik.ai/api/external/v1/signals/SIGNAL-43/source-revisions \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: source-correction-43-v1' \
  -d '{"expectedSourceToken":"REPLACE_WITH_PREVIEW_TOKEN","text":"Original provider text, not an analyst summary.","reason":"Correct the imported text mapping."}'

Example Response

201 Created
json
{
  "id": "revision-uuid",
  "signalId": "signal-uuid",
  "revision": 1,
  "sourceToken": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "replayed": false,
  "processingQueued": false,
  "nextAction": "Use POST /signals/SIGNAL-43/source-revisions/1/process, then read the Signal status, processing receipt, and Evidence."
}
GET

Read a source correction record

GET /external/v1/signals/:publicId/source-revisions/:revision

Read the durable correction record, including its reason, acceptance time, afterToken, and beforeSnapshot. The snapshot contains the prior source, raw data, original body, source date, and removed generated Evidence. It may contain sensitive source content; protect it like the original Signal. History is deleted with the Signal or workspace. Restoring old text requires a new reviewed correction; this endpoint does not restore or reprocess anything.

Requirements

API scopes required:
signals:read

Request

Parameters

NameTypeDescription
publicId *stringWorkspace-scoped Signal ID.
revision *integerRevision number from the acceptance receipt or the Signal sourceRevision field.

Responses

200
Correction record

Audit record and original source snapshot.

Schema
SourceRevisionHistory
POST

Process a corrected source revision

POST /external/v1/signals/:publicId/source-revisions/:revision/process

Start processing for one accepted source revision through the existing Signal queue. The route checks that the requested revision is still current before and after the queue handoff, so a later correction cannot be mistaken for the revision being processed. It is safe to retry while the same revision is pending or already in flight. Read the Signal status, processing receipt, and Evidence after completion.

Requirements

API scopes required:
signals:write

Request

Parameters

NameTypeDescription
publicId *stringWorkspace-scoped Signal ID.
revision *integerAccepted source revision to process.

Responses

201
Processing started

The accepted revision was handed to the existing processing queue.

Schema
SourceRevisionProcessingReceipt
409
Revision changed

The requested revision is no longer current. Read the current Signal before processing.

Example Response

201 Created
json
{
  "publicId": "SIGNAL-43",
  "sourceRevision": 1,
  "jobId": "job-uuid",
  "processingQueued": true,
  "nextAction": "Read the Signal status, processing receipt, and Evidence after the job completes."
}

Creation Modes

The recommended public API flow is typed text ingestion. Sendtext andsignalTypeto create a manual signal that is automatically queued for AI processing into insights.

Supported signal types: transcript, meeting_notes, ai_notes, reconstructed_notes, support_ticket, review, feedback_record, discovery_report

Transcript normalization: copied text, Markdown, speaker labels, timestamps, SRT, and WebVTT are accepted without a connected meeting provider. Known meeting headers become metadata; ambiguous text remains unresolved rather than receiving an invented speaker.

Canonical provenance: processorType controls routing, providerType identifies the source system, evidenceKind describes the evidence shape, and analysisProfile selects the extraction behavior.

Source links: send sourceLinks with final URLs for the original review, thread, report, ticket, source row, or meeting so Zentrik can render direct evidence actions in Discovery.

Profile mapping: transcript → transcript analysis; support_ticket → ticket analysis; review and feedback_record → feedback/review analysis; notes and discovery_report → discovery-report analysis. Notes retain their content type and are never converted into speaker turns.

Async behavior: create returns a processing signal plus a jobId

Inferred context: you do not need to send a context label. Zentrik infers the best matching interaction context during processing.

Advanced/raw ingestion: the same create endpoint also supports lower-level fields such as processorType, providerType, evidenceKind, source, and data.

Those fields are intentionally omitted from the primary docs here because most public API users only need the typed text flow.

Data Models

Signals are intentionally flexible. The core fields help you track provenance while thesource anddata payloads carry your custom structure.

Signal Object

FieldTypeDescription
sourceRevisionintegerSource correction generation, starting at zero. Match this value to the accepted correction before treating a processing result as current.
iduuidThe unique identifier for the signal.
namestringDisplay name for the signal. For typed text signals, Zentrik can generate this automatically from the signal type and timestamp.
publicIdstringWorkspace-scoped, human-readable identifier in the form "SIGNAL-123". Useful for referencing signals in UI and exports.
workspaceIduuidID of the workspace this signal belongs to.
status'pending' | 'processing' | 'processed' | 'failed'Processing status of the signal. Create responses that queue work now typically return processing immediately, then later settle to processed or failed.
signalType'transcript' | 'meeting_notes' | 'ai_notes' | 'reconstructed_notes' | 'support_ticket' | 'review' | 'feedback_record' | 'discovery_report' | nullPresent for manual text signals. Indicates which typed ingestion flow created the signal.
processorTypestringCanonical operational processor route, such as manual-text, manual-transcript, gong, or zendesk.
providerTypestringCanonical source system or channel, such as external_api, manual, gong, zendesk, gmail_mailbox, app_store, reddit, or g2.
evidenceKindstringCanonical evidence shape, such as transcript, support_ticket, review, feedback_record, forum_discussion, discovery_report, or email_thread.
analysisProfile'default_transcript' | 'support_ticket' | 'survey_response' | 'discovery_report' | 'community_discussion'Canonical prompt/extraction profile used by processing.
provenance{ providerType: string; evidenceKind: string; analysisProfile: string }Canonical signal provenance grouped for clients that do not need operational processor routing.
sourceFacetstringDerived filter/grouping key in the form providerType:evidenceKind.
sourceLabelstringDerived display label for the source facet.
sourceLinks{ name: string; url: string; type: string; primary?: boolean }[]Normalized source links users can open from Discovery to inspect the original evidence. These are derived from sourceLinks on create and legacy URL fields stored in source.external_data, data, or import metadata.
contextstring | nullNormalized interaction context inferred or stored for the signal, such as user_interview, feature_feedback, or support_request. Most clients do not need to send this on create.
source{ type: string; external_data?: object }Provider-specific source payload. Canonical provenance lives in processorType, providerType, evidenceKind, and analysisProfile.
dataobject | nullThe source-shaped payload you sent on create, and only that. Keys Zentrik writes into the stored column while processing (attribution, import receipts, storage keys, processing timestamps) are projected into transcript, import, and processing instead of echoed here. Null when you sent none.
transcript{ coveragePercent, totalTurnCount, resolvedTurnCount, externalTurnCount, internalTurnCount, unresolvedTurnCount, participantCount, analysis } | nullFor transcript evidence: how much of the call was attributed to a named speaker, and what processing decided to do with it. Null for other evidence kinds.
transcript.analysis{ outcome: 'no_analytical_content' | 'analyzed_no_insights' | 'analyzed_with_insights'; reason: string; generatedInsightCount: number } | nullWhy a processed call did or did not produce insights. no_analytical_content means the call never reached insight analysis; analyzed_no_insights means it was analyzed in full and nothing in it was supported well enough to become an insight; analyzed_with_insights means it produced them. generatedInsightCount counts what that processing run produced rather than the length of insightIds, so a call can report analyzed_no_insights and still list insights a person linked by hand. Null until the signal has been processed, so a call with no insights and no analysis is still in flight rather than declined.
importobject | nullScalar provenance facts from the import that created this signal, such as provider, filename, sheet, row, and record IDs. Null when the signal was not imported.
rawDataobject | nullThe whole stored data column, returned only when a read request includes ?include=raw. A processed transcript carries every attributed turn and the provider import response and can exceed several hundred KB, so it is opt-in per request and never returned on a list.
insightIdsuuid[]Insights linked to this signal, either directly or through at least one of its evidence claims.
accountIdsuuid[]List of account IDs linked directly to this signal.
contactIdsuuid[]Workspace people linked to this signal from participant resolution or later curation.
initiativeIdsuuid[] | undefinedInitiatives with an accepted evidence link to this signal, however the link was made: by a person, through a Study, or by accepting a suggestion. Pending suggestions are not included. Returned on list and detail reads; read an Initiative, including its teams, with GET /external/v1/initiatives/:id.
studyIdsuuid[] | undefinedStudies this signal is attached to as an interview, including interviews excluded from findings. Returned on list and detail reads.
accountIduuid | nullLegacy single-account field. When multiple accounts are linked, this returns the first linked account ID.
accountExternalIdstring | nullClient-provided external account identifier when the signal was created with accountExternalId.
externalIdstring | nullIdentifier of the record in the external system (for example, a ticket or event identifier).
createdAtiso-dateTimestamp when the signal was first created.
updatedAtiso-dateTimestamp of the last modification.
jobIdstring | undefinedReturned on create/process responses when an asynchronous processing job has been queued.
processing{ lastJobId?: string | null; startedAt?: string | null; processedAt?: string | null; failedAt?: string | null; lastError?: string | null } | nullOperational processing metadata. Use this to debug queue progress and retries before assuming a signal is stuck.