Start work from your systems
Your service receives the event and starts a task with a project API key.
You need: a deployed runtime (Deploy) and a project API key for the environment you target (Credentials).
1. Give your service the key
export INTROSPECTION_TOKEN=<api-key>
export INTROSPECTION_PROJECT=<project-slug>
export INTROSPECTION_DP_URL=<data-plane-url> # for tasks, conversations, and files commands
export INTROSPECTION_API_BASE_URL=https://api.introspection.dev # for tasks createThe key’s environment picks staging or production. With a key, tasks create
takes --runtime-id and that same --environment; --runtime is refused.
2. Start one task per event
Return at once. conversation_metadata makes the task findable later.
import { IntrospectionClient } from "@introspection-sdk/introspection-node";
const client = new IntrospectionClient(); // reads INTROSPECTION_TOKEN
app.post("/webhooks/events", async (req, res) => {
const { id, text } = req.body;
const runner = await client.runtimes("triage-agent").run();
const handle = await runner.tasks.start({
prompt: `New event ${id}:\n\n${text}`,
conversation_metadata: { event_id: id },
});
res.status(202).json({ task_id: handle.run.task_id });
});For per-customer memory, open the runner with an identity (who owns a task).
3. Find the task for an event
introspection conversations list --filter metadata=event_id:<event-id> --query "[].id" -o tableconversation_metadata can never be edited or deleted: keep personal data out of it.
4. Run a batch
Your organization runs 5 tasks at once by default; the rest wait as queued,
and a task queued for over an hour is cancelled
(Limits). Send waves sized to that:
const runner = await client.runtimes("triage-agent").run();
for (let i = 0; i < tickets.length; i += 5) {
const wave = await Promise.all(
tickets.slice(i, i + 5).map((t) =>
runner.tasks.start({ prompt: `Triage ticket ${t}`, tags: ["batch:2026-10-15"] }),
),
);
await Promise.all(wave.map((h) => h.text())); // waits for each run to settle
}List the batch later with runner.tasks.list({ tag: "batch:2026-10-15" }).
5. Collect the outputs
introspection tasks stream <task-id> returns when the run settles; then list
and download its outputs (Send files in and out).
Verify
introspection tasks list --limit 20 -o tableExpect your tasks as idle (turn finished) or failed.
Or ask your agent: “Write a webhook handler that starts a triage-agent task per event.”
Receive email or third-party webhooks
Introspection receives webhooks only for its own Slack connectors. Point anything else, including inbound email, at your service, then start a task with the message and attachments:
introspection tasks create --runtime-id <runtime-id> -e production \
--file @./invoice.pdf --prompt "From: billing@acme.com. Subject: Invoice 88. Process it."Keep one task per email thread: store thread ID → task ID, or start from the SDK
with conversation_metadata: { thread_id } and find it as in step 3. The agent
can’t send email: give it a draft tool and let
your service send the reply.
Relay another chat app
Start a task on a thread’s first message, send later ones with
runner.tasks.runs.create(taskId, ...), and post handle.text() back.
Continue a task later
introspection tasks prompt <task-id> --prompt "..." adds a turn at any age;
the task restarts with its history, outputs, and memory.
Limits
| Not supported | Do this instead |
|---|---|
| Inbound email address, generic webhook receiver | Your service receives it (above). |
| Sending email | Your service sends the agent’s draft. |
Tag or metadata filter on tasks list in the CLI | conversations list --filter metadata=... (step 3), or the SDK’s tasks.list({ tag }). |