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.
#!/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:
- Signals import template for batching, retries, polling, and richer payload mapping
- Signals API reference for the full endpoint contract
- Import evidence into Discovery if you need the product-level decision guide
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.