@cxpa/sdk/agent

Environment variable names in these examples follow the per-agent conventionCXPA_<AGENT>_AGENT_API_KEY, CXPA_<AGENT>_INGEST_API_KEY. Keys are scoped per agent, so a single shared variable cannot serve two of them; name each after the agent it belongs to. The samples below use REVENUE_CHAT as that agent.

Exports

SymbolKindPurpose
triggerRunfunctionStart a platform-managed run (async — returns runId immediately).
triggerRunAndWaitfunctionStart a run and block until it terminates or a wait window elapses; returns the agent output inline.
triggerRunAndDownloadfunctionStart a run and stream the runtime's binary response back as a ReadableStream — for agents whose output is a file.
registerRunfunctionRegister an externally-triggered run and receive a credentials token.
ingestRunfunctionReport status for a standalone agent.
createAgentClientfactoryBuild a runtime client bound to a single (runId, agentApiKey).

The trigger payload

Every platform-triggered run arrives at your task with this envelope. It is the same shape whichever surface started the run — Run Now, a schedule, a zone app, an external trigger or a webhook.

ts
type CxpaPayload<TInput> = {
  /** Platform run id. Its presence means the platform owns the run row. */
  runId: string
  /** The input for this run — see the tutorial for how each trigger path composes it. */
  input?: TInput
  /** integration_id → connection, for the agent's active connections. */
  connectionIds?: Record<string, { integrationId: string; connectionId: string }>
  /** 60-minute JWT authorising credential resolution. */
  credentialsToken?: string
}

connectionIds and credentialsToken arrive together or not at all — an agent with no active connections receives neither. The agent API key is never in the payload; read it from the runtime environment.

triggerRun(options)

Wraps POST /api/agents/{agentId}/runs/trigger.

ts
import { triggerRun } from '@cxpa/sdk/agent'

const { runId, status } = await triggerRun({
  baseUrl: process.env.CXPA_API_URL!,
  ingestApiKey: process.env.CXPA_REVENUE_CHAT_INGEST_API_KEY!,
  agentId: 42,
  input: { url: 'https://example.com' },
})

triggerRunAndWait(options)

Wraps POST /api/agents/{agentId}/runs/trigger-and-wait. Synchronous variant of triggerRun — the call blocks until the run reaches a terminal state or the server-side wait window elapses, then returns either the full Run row (with output_data) or a { timedOut: true } placeholder.

Use it for agents whose value is the output payload itself: PDF reports, generated documents, AI-rendered responses.

ts
import { triggerRunAndWait } from '@cxpa/sdk/agent'

const result = await triggerRunAndWait({
  baseUrl: process.env.CXPA_API_URL!,
  ingestApiKey: process.env.CXPA_REVENUE_CHAT_INGEST_API_KEY!,
  agentId: 42,
  input: { topic: 'Q3 financial summary' },
  timeoutMs: 120_000, // server further caps at agent's max-run-duration
})

if (result.timedOut) {
  // Wait window elapsed; the run is still in flight. Fall back to polling.
  console.log('still running:', result.runId)
} else if (result.status === 'completed') {
  // result.output_data carries the agent payload
} else {
  // 'failed' | 'cancelled'
  throw new Error(`Run ${result.status}: ${result.error}`)
}

When to choose this over triggerRun

Use triggerRunUse triggerRunAndWait
Caller doesn't need output inlineCaller hands the output straight to the end user
Run may take longer than ~5 minutesRun completes in seconds or low minutes
You'll poll or wait for a callback yourselfYou want one HTTP request that returns the result

triggerRunAndDownload(options)

Wraps POST /api/agents/{agentId}/runs/trigger-and-download. For agents whose output is a generated file (PDF report, spreadsheet export, rendered image) rather than a JSON payload. The platform streams the runtime's response body straight through and never buffers it.

Only valid for platform-managed agents with output_kind = 'file_download' whose runtime supports streaming binary output. The platform records run metadata only (filename, mime type, byte count); the file bytes are not stored.

ts
import { triggerRunAndDownload } from '@cxpa/sdk/agent'
import { writeFile } from 'node:fs/promises'
import { Readable } from 'node:stream'

const result = await triggerRunAndDownload({
  baseUrl: process.env.CXPA_API_URL!,
  ingestApiKey: process.env.CXPA_REVENUE_CHAT_INGEST_API_KEY!,
  agentId: 42,
  input: { topic: 'Q3 financial summary' },
})

await writeFile(result.filename, Readable.fromWeb(result.body))
// `result.runId`, `result.contentType`, `result.contentLength` available too.

The returned body is a ReadableStream<Uint8Array> — pipe it once. In a server-side handler the stream is typically forwarded straight to the caller's own HTTP response so the user's browser saves the file without any intermediate buffering on your side.

When to choose this over triggerRunAndWait

Use triggerRunAndWaitUse triggerRunAndDownload
Output is a JSON payloadOutput is a binary file (PDF, spreadsheet, image)
You want output_data inline in JSONYou want the bytes streamed to disk or to a browser

registerRun(options)

Wraps POST /api/agents/{agentId}/runs/register.

ts
import { registerRun } from '@cxpa/sdk/agent'

const { runId, credentialsToken, connectionIds } = await registerRun({
  baseUrl: process.env.CXPA_API_URL!,
  ingestApiKey: process.env.CXPA_REVENUE_CHAT_INGEST_API_KEY!,
  agentId: 42,
  externalRunId: 'run_abc123',
})

credentialsToken authorises credential resolution; connectionIds is the map it is spent against, keyed by integration_id:

ts
const cxpa = createAgentClient({
  baseUrl, apiKey: process.env.CXPA_REVENUE_CHAT_AGENT_API_KEY!, runId, credentialsToken,
})
const cred = await cxpa.resolveCredential(connectionIds!.openai.connectionId)

Both fields are optional and arrive together or not at all — an agent with no active connections receives neither, since there would be nothing to resolve. The shape matches what the platform sends in the task payload when it triggers a run itself, so the same resolution code works on either path.

ingestRun(options)

Wraps POST /api/agents/{agentId}/runs/ingest. For managed_by = 'standalone' agents only.

ts
import { ingestRun } from '@cxpa/sdk/agent'

await ingestRun({
  baseUrl,
  ingestApiKey,
  agentId,
  externalRunId: 'exec_001',
  status: 'completed',
  output: { pages: 42 },
  outputs: 42,
})

createAgentClient(options)

Returns a client bound to one (runId, agentApiKey). Use it from inside a runtime task.

ts
import { createAgentClient } from '@cxpa/sdk/agent'

const cxpa = createAgentClient({
  baseUrl,
  // From the runtime environment — the payload never carries the agent key.
  apiKey: process.env.CXPA_REVENUE_CHAT_AGENT_API_KEY!,
  runId:  triggerPayload.runId,
  credentialsToken: triggerPayload.credentialsToken,
})

The trigger payload carries runId, input, connectionIds and credentialsToken. The agent API key is the one factor it never contains — set it as an environment variable on the runtime. Keys are scoped per agent, so give each agent its own variable rather than sharing one.

Methods

MethodHTTP under the hood
started()POST /callback { type: 'started' }
output({ output, outputs? })POST /callback { type: 'output' } (intermediate)
complete({ output, outputs? })POST /callback { type: 'output', complete: true }
fail({ message, name?, stack? })POST /callback { type: 'output', failed: true, error }
waiting({ tokenId, description, url?, output? })POST /callback { type: 'waiting' } — optional url overrides the {{run_url}} notification link
completeWaitpoint(payload?)POST /api/runs/{runId}/waitpoint (resume a paused HITL run)
resolveCredential(connectionId)GET /api/credentials/{id}/resolve

resolveCredential requires credentialsToken to have been passed at construction.

Errors

Every function and client method on this subpath throws ApiError on a non-2xx response — the same class the zone client uses. It is exported from @cxpa/sdk/agent and from @cxpa/sdk.

ts
import { createAgentClient, ApiError } from '@cxpa/sdk/agent'

try {
  await cxpa.resolveCredential(connectionId)
} catch (err) {
  if (err instanceof ApiError && err.status === 401) {
    // Key or credentials token rejected — see the endpoint's error table.
  }
  throw err
}

err.status is the HTTP status and err.message carries the platform's error string where one was returned. Status meanings are per endpoint — see Errors.