Signals API quickstart

Signals API quickstart

Use this page when you want the fastest path to a first successful Signal import. It is meant for engineers, operators, and coding agents who want to send one record into Zentrik before moving on to a larger source integration.

This guide is for the first successful API call only. If you are deciding whether to import manually, connect a supported source, or use the API at all, start with Import evidence into Discovery.

If you already know you want the API, this page shows the smallest working path:

  • create one signal
  • let Zentrik queue processing automatically
  • confirm the signal appears in Discovery
  • move on to the production template when you are ready for batching or pagination

Before you start

You need three things:

  • a workspace API key from Settings → API Keys
  • your workspace base URL including /api
  • one real record to send, usually as a transcript, support ticket, review, or discovery report

If you are evaluating the workflow for the first time, import one record manually in Discovery first. That gives you a simple baseline before you automate anything.

Hello World

Start with one transcript. This example creates a signal and waits for processing to finish.

python39 lines
#!/usr/bin/env python3
import json
import os
import time
import urllib.request

payload = {
    "name": "Advisor onboarding call",
    "signalType": "transcript",
    "text": "Customer interview transcript goes here.",
    "additionalContext": "Imported from an onboarding call.",
}

def request_json(method, path, body=None):
    request = urllib.request.Request(
        f"{os.environ['ZENTRIK_API_BASE'].rstrip('/')}{path}",
        data=json.dumps(body).encode("utf-8") if body is not None else None,
        method=method,
        headers={
            "Authorization": f"Bearer {os.environ['ZENTRIK_API_KEY']}",
            "Content-Type": "application/json",
            "Accept": "application/json",
        },
    )
    with urllib.request.urlopen(request, timeout=60) as response:
        raw = response.read().decode("utf-8")
        return response.status, json.loads(raw) if raw else None

code, created = request_json("POST", "/external/v1/signals", payload)
public_id = created["publicId"]
print(f"Created {public_id} jobId={created['jobId']}")

for _ in range(36):
    code, signal = request_json("GET", f"/external/v1/signals/{public_id}")
    print(f"{public_id} status={signal.get('status')} insights={len(signal.get('insightIds') or [])}")
    if signal.get("status") in {"processed", "failed"}:
        print(json.dumps(signal, indent=2))
        break
    time.sleep(5)

Expected result:

  • the create response returns a publicId and jobId
  • the signal moves from processing to processed
  • the signal appears in Discovery with linked insights when processing succeeds

Choose a signal type

Use the signal type that matches the source material:

  • transcript for interviews, onboarding calls, sales calls, and meeting notes with direct user evidence
  • support_ticket for support cases, ticket exports, or issue threads
  • review for survey responses, public reviews, or shorter open-ended feedback
  • discovery_report for synthesized research notes or analyst writeups

If you are unsure, start with the source that is closest to the original customer wording instead of a summarized derivative.

After you create a signal

The create endpoint queues processing automatically. You do not need to call a second endpoint for the first run.

The main fields to watch are:

  • status
  • insightIds
  • processing.lastJobId
  • processing.processedAt
  • processing.lastError

Use the explicit process endpoint only when you want to rerun an existing signal.

Next steps

When the Hello World flow works, move to one of these:

Troubleshooting

These items are about workflow and expectations in the product, not a broken OAuth client. If something contradicts what you see in your workspace, note your workspace name and the screen, then contact us.

The create call fails immediately

Check the API key, the base URL, and whether the base URL includes /api. A valid create response returns both a signal identifier and a queued job id.

The signal stays in processing

Check the signal record for processing.lastError and confirm the workspace is healthy before retrying. If you are testing locally, verify GET /api/readyz before sending another batch.