@happyrobot-ai/sdk 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,10 +44,11 @@ const { run_id } = await client.workflows.triggerRun("my-workflow", {
44
44
 
45
45
  ```ts
46
46
  const client = new HappyRobotClient({
47
- apiKey: "sk_live_...", // Required. API key (sk_live_... or sk_test_...)
48
- timeout: 30_000, // Optional. Request timeout in ms. Defaults to 30000
49
- maxRetries: 2, // Optional. Retries on 429/5xx with exponential backoff. Defaults to 2
50
- fetch: customFetch, // Optional. Custom fetch implementation
47
+ apiKey: "sk_live_...", // Required. API key (sk_live_... or sk_test_...)
48
+ cluster: "eu", // Optional. "us" (default) or "eu"
49
+ timeout: 30_000, // Optional. Request timeout in ms. Defaults to 30000
50
+ maxRetries: 2, // Optional. Retries on 429/5xx with exponential backoff. Defaults to 2
51
+ fetch: customFetch, // Optional. Custom fetch implementation
51
52
  });
52
53
  ```
53
54
 
@@ -65,9 +66,9 @@ import { triggerAndWait } from "@happyrobot-ai/sdk/helpers";
65
66
  const { run, sessions } = await triggerAndWait(client, {
66
67
  workflowId: "my-workflow",
67
68
  payload: { phone: "+1234567890" },
68
- timeoutMs: 300_000, // Optional. Defaults to 5 minutes
69
- pollIntervalMs: 2_000, // Optional. Defaults to 2 seconds
70
- fetchSessions: true, // Optional. Fetch sessions on completion. Defaults to true
69
+ timeoutMs: 300_000, // Optional. Defaults to 5 minutes
70
+ pollIntervalMs: 2_000, // Optional. Defaults to 2 seconds
71
+ fetchSessions: true, // Optional. Fetch sessions on completion. Defaults to true
71
72
  environment: "production", // Optional. Defaults to "production"
72
73
  });
73
74
 
@@ -83,12 +84,12 @@ import { createVoiceAgent } from "@happyrobot-ai/sdk/helpers";
83
84
 
84
85
  const { workflow, publishResult } = await createVoiceAgent(client, {
85
86
  name: "Sales Agent",
86
- template: "voice-agent", // "voice-agent" (outbound) or "inbound-voice-agent"
87
+ template: "voice-agent", // "voice-agent" (outbound) or "inbound-voice-agent"
87
88
  prompt: "You are a helpful sales assistant...",
88
89
  initialMessage: "Hi, how can I help you today?",
89
90
  publish: true,
90
91
  environment: "production",
91
- folderId: "folder-id", // Optional
92
+ folderId: "folder-id", // Optional
92
93
  });
93
94
  ```
94
95
 
@@ -109,33 +110,33 @@ const { workflow } = await createFromTemplate(client, {
109
110
 
110
111
  ## Resources
111
112
 
112
- | Property | Class | Description |
113
- |---|---|---|
114
- | `client.workflows` | `WorkflowsResource` | Workflow CRUD, publishing, runs, and templates |
115
- | `client.versions` | `VersionsResource` | Version management (fork, publish, lock, test) |
116
- | `client.nodes` | `NodesResource` | Node CRUD, config schema, and available variables |
117
- | `client.runs` | `RunsResource` | Run details, cancellation, and annotations |
118
- | `client.sessions` | `SessionsResource` | Session details, messages, and SSE streaming |
119
- | `client.messages` | `MessagesResource` | Message quality flags |
120
- | `client.variables` | `VariablesResource` | Workflow-scoped variables |
121
- | `client.phoneNumbers` | `PhoneNumbersResource` | Phone number management |
122
- | `client.sipTrunks` | `SipTrunksResource` | SIP trunk management |
123
- | `client.integrations` | `IntegrationsResource` | Integration and event discovery |
124
- | `client.contacts` | `ContactsResource` | Contact lookup and history |
125
- | `client.knowledgeBases` | `KnowledgeBasesResource` | Knowledge base document management |
126
- | `client.workflowFolders` | `WorkflowFoldersResource` | Workflow folder organization |
127
- | `client.mcp` | `MCPResource` | MCP server management |
128
- | `client.billing` | `BillingResource` | Billing usage details and totals |
129
- | `client.apiKey` | `ApiKeyResource` | API key introspection |
130
- | `client.artifacts` | `ArtifactsResource` | Resolve fresh artifact URLs |
131
- | `client.adversarialSuites` | `AdversarialSuitesResource` | Adversarial suite management and execution |
132
- | `client.adversarialTests` | `AdversarialTestsResource` | Adversarial test management and execution |
133
- | `client.northstars` | `NorthstarsResource` | Northstar quality criteria management |
134
- | `client.customEvals` | `CustomEvalsResource` | Custom eval management and execution |
135
- | `client.issues` | `IssuesResource` | Quality issue (flag) status management |
136
- | `client.auditRemarks` | `AuditRemarksResource` | Audit remark feedback management |
137
- | `client.chat` | `ChatResource` | Chat session management, messaging, and file uploads |
138
- | `client.voice` | `VoiceResource` | Voice call token creation |
113
+ | Property | Class | Description |
114
+ | -------------------------- | --------------------------- | ---------------------------------------------------- |
115
+ | `client.workflows` | `WorkflowsResource` | Workflow CRUD, publishing, runs, and templates |
116
+ | `client.versions` | `VersionsResource` | Version management (fork, publish, lock, test) |
117
+ | `client.nodes` | `NodesResource` | Node CRUD, config schema, and available variables |
118
+ | `client.runs` | `RunsResource` | Run details, cancellation, and annotations |
119
+ | `client.sessions` | `SessionsResource` | Session details, messages, and SSE streaming |
120
+ | `client.messages` | `MessagesResource` | Message quality flags |
121
+ | `client.variables` | `VariablesResource` | Workflow-scoped variables |
122
+ | `client.phoneNumbers` | `PhoneNumbersResource` | Phone number management |
123
+ | `client.sipTrunks` | `SipTrunksResource` | SIP trunk management |
124
+ | `client.integrations` | `IntegrationsResource` | Integration and event discovery |
125
+ | `client.contacts` | `ContactsResource` | Contact lookup and history |
126
+ | `client.knowledgeBases` | `KnowledgeBasesResource` | Knowledge base document management |
127
+ | `client.workflowFolders` | `WorkflowFoldersResource` | Workflow folder organization |
128
+ | `client.mcp` | `MCPResource` | MCP server management |
129
+ | `client.billing` | `BillingResource` | Billing usage details and totals |
130
+ | `client.apiKey` | `ApiKeyResource` | API key introspection |
131
+ | `client.artifacts` | `ArtifactsResource` | Resolve fresh artifact URLs |
132
+ | `client.adversarialSuites` | `AdversarialSuitesResource` | Adversarial suite management and execution |
133
+ | `client.adversarialTests` | `AdversarialTestsResource` | Adversarial test management and execution |
134
+ | `client.northstars` | `NorthstarsResource` | Northstar quality criteria management |
135
+ | `client.customEvals` | `CustomEvalsResource` | Custom eval management and execution |
136
+ | `client.issues` | `IssuesResource` | Quality issue (flag) status management |
137
+ | `client.auditRemarks` | `AuditRemarksResource` | Audit remark feedback management |
138
+ | `client.chat` | `ChatResource` | Chat session management, messaging, and file uploads |
139
+ | `client.voice` | `VoiceResource` | Voice call token creation |
139
140
 
140
141
  ---
141
142
 
@@ -183,22 +184,22 @@ const { data } = await client.workflows.listRuns("my-workflow");
183
184
  const { run_id } = await client.workflows.triggerRun("my-workflow", { payload: { phone: "+1..." } });
184
185
  ```
185
186
 
186
- | Method | HTTP | Path | Description |
187
- |---|---|---|---|
188
- | `list(query?)` | GET | `/workflows` | List workflows, paginated |
189
- | `listAll(query?)` | GET | `/workflows` | Async generator over all pages |
190
- | `create(body)` | POST | `/workflows` | Create a new workflow |
191
- | `get(workflowId)` | GET | `/workflows/:id` | Get workflow by ID or slug |
192
- | `update(workflowId, body)` | PATCH | `/workflows/:id` | Update name, description, etc. |
193
- | `delete(workflowId)` | DELETE | `/workflows/:id` | Delete a workflow |
194
- | `duplicate(workflowId, body?)` | POST | `/workflows/:id/duplicate` | Duplicate a workflow |
195
- | `publish(workflowId, body?)` | POST | `/workflows/:id/publish` | Publish the latest version |
196
- | `unpublish(workflowId)` | POST | `/workflows/:id/unpublish` | Unpublish a workflow |
197
- | `cancelRuns(workflowId)` | POST | `/workflows/:id/cancel-runs` | Cancel all active runs |
198
- | `listTemplates(query?)` | GET | `/workflows/templates` | List workflow templates |
199
- | `listVersions(workflowId, query?)` | GET | `/workflows/:id/versions` | List versions for a workflow |
200
- | `listRuns(workflowId, query?)` | GET | `/workflows/:id/runs` | List runs for a workflow |
201
- | `triggerRun(workflowId, body?)` | POST | `/workflows/:id/runs` | Trigger a new run |
187
+ | Method | HTTP | Path | Description |
188
+ | ---------------------------------- | ------ | ---------------------------- | ------------------------------ |
189
+ | `list(query?)` | GET | `/workflows` | List workflows, paginated |
190
+ | `listAll(query?)` | GET | `/workflows` | Async generator over all pages |
191
+ | `create(body)` | POST | `/workflows` | Create a new workflow |
192
+ | `get(workflowId)` | GET | `/workflows/:id` | Get workflow by ID or slug |
193
+ | `update(workflowId, body)` | PATCH | `/workflows/:id` | Update name, description, etc. |
194
+ | `delete(workflowId)` | DELETE | `/workflows/:id` | Delete a workflow |
195
+ | `duplicate(workflowId, body?)` | POST | `/workflows/:id/duplicate` | Duplicate a workflow |
196
+ | `publish(workflowId, body?)` | POST | `/workflows/:id/publish` | Publish the latest version |
197
+ | `unpublish(workflowId)` | POST | `/workflows/:id/unpublish` | Unpublish a workflow |
198
+ | `cancelRuns(workflowId)` | POST | `/workflows/:id/cancel-runs` | Cancel all active runs |
199
+ | `listTemplates(query?)` | GET | `/workflows/templates` | List workflow templates |
200
+ | `listVersions(workflowId, query?)` | GET | `/workflows/:id/versions` | List versions for a workflow |
201
+ | `listRuns(workflowId, query?)` | GET | `/workflows/:id/runs` | List runs for a workflow |
202
+ | `triggerRun(workflowId, body?)` | POST | `/workflows/:id/runs` | Trigger a new run |
202
203
 
203
204
  ---
204
205
 
@@ -216,17 +217,17 @@ await client.versions.testAll("version-id");
216
217
  const issues = await client.versions.getPromptIssues("version-id");
217
218
  ```
218
219
 
219
- | Method | HTTP | Path | Description |
220
- |---|---|---|---|
221
- | `get(versionId)` | GET | `/versions/:id` | Get version with node summary and changelog |
222
- | `update(versionId, body)` | PATCH | `/versions/:id` | Update name or description |
223
- | `fork(versionId)` | POST | `/versions/:id/fork` | Clone a version |
224
- | `publish(versionId, body?)` | POST | `/versions/:id/publish` | Publish a version |
225
- | `unpublish(versionId)` | POST | `/versions/:id/unpublish` | Unpublish a version |
226
- | `lock(versionId)` | POST | `/versions/:id/lock` | Lock a version (prevent edits) |
227
- | `unlock(versionId)` | POST | `/versions/:id/unlock` | Unlock a version |
228
- | `testAll(versionId)` | POST | `/versions/:id/test-all` | Run test-all validation |
229
- | `getPromptIssues(versionId)` | GET | `/versions/:id/prompt-issues` | Get prompt quality issues for all prompt nodes |
220
+ | Method | HTTP | Path | Description |
221
+ | ---------------------------- | ----- | ----------------------------- | ---------------------------------------------- |
222
+ | `get(versionId)` | GET | `/versions/:id` | Get version with node summary and changelog |
223
+ | `update(versionId, body)` | PATCH | `/versions/:id` | Update name or description |
224
+ | `fork(versionId)` | POST | `/versions/:id/fork` | Clone a version |
225
+ | `publish(versionId, body?)` | POST | `/versions/:id/publish` | Publish a version |
226
+ | `unpublish(versionId)` | POST | `/versions/:id/unpublish` | Unpublish a version |
227
+ | `lock(versionId)` | POST | `/versions/:id/lock` | Lock a version (prevent edits) |
228
+ | `unlock(versionId)` | POST | `/versions/:id/unlock` | Unlock a version |
229
+ | `testAll(versionId)` | POST | `/versions/:id/test-all` | Run test-all validation |
230
+ | `getPromptIssues(versionId)` | GET | `/versions/:id/prompt-issues` | Get prompt quality issues for all prompt nodes |
230
231
 
231
232
  ---
232
233
 
@@ -245,16 +246,16 @@ const vars = await client.nodes.getAvailableVars("version-id", "node-id");
245
246
  const result = await client.nodes.test("version-id", "node-id");
246
247
  ```
247
248
 
248
- | Method | HTTP | Path | Description |
249
- |---|---|---|---|
250
- | `list(versionId)` | GET | `/versions/:vId/nodes` | List all nodes in a version |
251
- | `addBatch(versionId, body)` | POST | `/versions/:vId/nodes` | Add nodes in batch (1–50) |
252
- | `get(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId` | Get a single node |
253
- | `update(versionId, nodeId, body)` | PUT | `/versions/:vId/nodes/:nId` | Update a node |
254
- | `delete(versionId, nodeId)` | DELETE | `/versions/:vId/nodes/:nId` | Delete a node |
255
- | `getConfigSchema(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId/config-schema` | Get field types and requirements |
256
- | `getAvailableVars(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId/available-vars` | Get upstream variables available to this node |
257
- | `test(versionId, nodeId, body?)` | POST | `/versions/:vId/nodes/:nId/test` | Test a single node (version must not be published) |
249
+ | Method | HTTP | Path | Description |
250
+ | ------------------------------------- | ------ | ------------------------------------------ | -------------------------------------------------- |
251
+ | `list(versionId)` | GET | `/versions/:vId/nodes` | List all nodes in a version |
252
+ | `addBatch(versionId, body)` | POST | `/versions/:vId/nodes` | Add nodes in batch (1–50) |
253
+ | `get(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId` | Get a single node |
254
+ | `update(versionId, nodeId, body)` | PUT | `/versions/:vId/nodes/:nId` | Update a node |
255
+ | `delete(versionId, nodeId)` | DELETE | `/versions/:vId/nodes/:nId` | Delete a node |
256
+ | `getConfigSchema(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId/config-schema` | Get field types and requirements |
257
+ | `getAvailableVars(versionId, nodeId)` | GET | `/versions/:vId/nodes/:nId/available-vars` | Get upstream variables available to this node |
258
+ | `test(versionId, nodeId, body?)` | POST | `/versions/:vId/nodes/:nId/test` | Test a single node (version must not be published) |
258
259
 
259
260
  ---
260
261
 
@@ -269,14 +270,14 @@ await client.runs.cancel("run-id");
269
270
  await client.runs.mark("run-id", { annotation: "correct" });
270
271
  ```
271
272
 
272
- | Method | HTTP | Path | Description |
273
- |---|---|---|---|
274
- | `get(runId)` | GET | `/runs/:id` | Get run details |
275
- | `getSessions(runId, query?)` | GET | `/runs/:id/sessions` | Get sessions for a run |
276
- | `getRecordings(runId)` | GET | `/runs/:id/recordings` | Get recordings for a run |
277
- | `getFlags(runId, query?)` | GET | `/runs/:id/flags` | Get quality flags for a run |
278
- | `cancel(runId)` | POST | `/runs/:id/cancel` | Cancel a run |
279
- | `mark(runId, body)` | POST | `/runs/:id/mark` | Annotate a run (correct / incorrect / critical) |
273
+ | Method | HTTP | Path | Description |
274
+ | ---------------------------- | ---- | ---------------------- | ----------------------------------------------- |
275
+ | `get(runId)` | GET | `/runs/:id` | Get run details |
276
+ | `getSessions(runId, query?)` | GET | `/runs/:id/sessions` | Get sessions for a run |
277
+ | `getRecordings(runId)` | GET | `/runs/:id/recordings` | Get recordings for a run |
278
+ | `getFlags(runId, query?)` | GET | `/runs/:id/flags` | Get quality flags for a run |
279
+ | `cancel(runId)` | POST | `/runs/:id/cancel` | Cancel a run |
280
+ | `mark(runId, body)` | POST | `/runs/:id/mark` | Annotate a run (correct / incorrect / critical) |
280
281
 
281
282
  ---
282
283
 
@@ -288,16 +289,17 @@ const { data } = await client.sessions.getMessages("session-id");
288
289
 
289
290
  // SSE streaming
290
291
  for await (const event of await client.sessions.stream("session-id")) {
291
- if (event.event === "message") console.log(event.data.role, event.data.content);
292
+ if (event.event === "message")
293
+ console.log(event.data.role, event.data.content);
292
294
  if (event.event === "session_ended") break;
293
295
  }
294
296
  ```
295
297
 
296
- | Method | HTTP | Path | Description |
297
- |---|---|---|---|
298
- | `get(sessionId)` | GET | `/sessions/:id` | Get session details |
299
- | `getMessages(sessionId, query?)` | GET | `/sessions/:id/messages` | Get paginated messages for a session |
300
- | `stream(sessionId, query?)` | GET | `/sessions/:id/stream` | Open SSE stream of session messages |
298
+ | Method | HTTP | Path | Description |
299
+ | -------------------------------- | ---- | ------------------------ | ------------------------------------ |
300
+ | `get(sessionId)` | GET | `/sessions/:id` | Get session details |
301
+ | `getMessages(sessionId, query?)` | GET | `/sessions/:id/messages` | Get paginated messages for a session |
302
+ | `stream(sessionId, query?)` | GET | `/sessions/:id/stream` | Open SSE stream of session messages |
301
303
 
302
304
  ---
303
305
 
@@ -305,13 +307,16 @@ for await (const event of await client.sessions.stream("session-id")) {
305
307
 
306
308
  ```ts
307
309
  const { data } = await client.messages.listFlags("message-id");
308
- await client.messages.createFlag("message-id", { type: "incorrect", note: "..." });
310
+ await client.messages.createFlag("message-id", {
311
+ type: "incorrect",
312
+ note: "...",
313
+ });
309
314
  ```
310
315
 
311
- | Method | HTTP | Path | Description |
312
- |---|---|---|---|
313
- | `listFlags(messageId, query?)` | GET | `/messages/:id/flags` | List quality flags for a message |
314
- | `createFlag(messageId, body)` | POST | `/messages/:id/flags` | Create a quality flag on a message |
316
+ | Method | HTTP | Path | Description |
317
+ | ------------------------------ | ---- | --------------------- | ---------------------------------- |
318
+ | `listFlags(messageId, query?)` | GET | `/messages/:id/flags` | List quality flags for a message |
319
+ | `createFlag(messageId, body)` | POST | `/messages/:id/flags` | Create a quality flag on a message |
315
320
 
316
321
  ---
317
322
 
@@ -323,8 +328,8 @@ const resolved = await client.artifacts.resolve({
323
328
  });
324
329
  ```
325
330
 
326
- | Method | HTTP | Path | Description |
327
- |---|---|---|---|
331
+ | Method | HTTP | Path | Description |
332
+ | --------------- | ---- | -------------------- | ------------------------------------------ |
328
333
  | `resolve(body)` | POST | `/artifacts/resolve` | Resolve fresh presigned URLs for artifacts |
329
334
 
330
335
  ---
@@ -335,17 +340,20 @@ Variables are scoped to a workflow.
335
340
 
336
341
  ```ts
337
342
  const { data } = await client.variables.list("workflow-id");
338
- await client.variables.create("workflow-id", { name: "MY_VAR", value: "hello" });
343
+ await client.variables.create("workflow-id", {
344
+ name: "MY_VAR",
345
+ value: "hello",
346
+ });
339
347
  await client.variables.update("workflow-id", "variable-id", { value: "world" });
340
348
  await client.variables.delete("workflow-id", "variable-id");
341
349
  ```
342
350
 
343
- | Method | HTTP | Path | Description |
344
- |---|---|---|---|
345
- | `list(workflowId, query?)` | GET | `/workflows/:wId/variables` | List variables for a workflow |
346
- | `create(workflowId, body)` | POST | `/workflows/:wId/variables` | Create a variable |
347
- | `update(workflowId, variableId, body)` | PATCH | `/workflows/:wId/variables/:vId` | Update a variable |
348
- | `delete(workflowId, variableId)` | DELETE | `/workflows/:wId/variables/:vId` | Delete a variable |
351
+ | Method | HTTP | Path | Description |
352
+ | -------------------------------------- | ------ | -------------------------------- | ----------------------------- |
353
+ | `list(workflowId, query?)` | GET | `/workflows/:wId/variables` | List variables for a workflow |
354
+ | `create(workflowId, body)` | POST | `/workflows/:wId/variables` | Create a variable |
355
+ | `update(workflowId, variableId, body)` | PATCH | `/workflows/:wId/variables/:vId` | Update a variable |
356
+ | `delete(workflowId, variableId)` | DELETE | `/workflows/:wId/variables/:vId` | Delete a variable |
349
357
 
350
358
  ---
351
359
 
@@ -366,20 +374,20 @@ await client.phoneNumbers.createSipTrunk("id");
366
374
  await client.phoneNumbers.validateTollFreeNumbers({ phone_numbers: [...] });
367
375
  ```
368
376
 
369
- | Method | HTTP | Path | Description |
370
- |---|---|---|---|
371
- | `list(query?)` | GET | `/phone-numbers` | List all phone numbers |
372
- | `buy(body)` | POST | `/phone-numbers` | Purchase a new phone number |
373
- | `update(id, body)` | PUT | `/phone-numbers/:id` | Update name or caller ID |
374
- | `getUsage(id)` | GET | `/phone-numbers/:id/usage` | Get usage info |
375
- | `getTollFreeVerification(id)` | GET | `/phone-numbers/:id/tollfree-verification` | Get toll-free verification status |
376
- | `createTollFreeVerification(id, body)` | POST | `/phone-numbers/:id/tollfree-verification` | Start toll-free verification |
377
- | `deleteTollFreeVerification(verificationSid)` | DELETE | `/phone-numbers/tollfree-verification/:sid` | Delete a toll-free verification |
378
- | `createSipTrunk(id)` | POST | `/phone-numbers/:id/sip-trunk` | Create a SIP trunk for a number |
379
- | `freeUp(id)` | POST | `/phone-numbers/:id/free-up-number` | Release a number from workflows |
380
- | `delete(id)` | POST | `/phone-numbers/:id/delete-number` | Permanently delete a number |
381
- | `removeFromWorkflow(id, body)` | POST | `/phone-numbers/:id/remove-from-workflow` | Remove from a specific workflow |
382
- | `validateTollFreeNumbers(body)` | POST | `/phone-numbers/validate-toll-free-numbers` | Check for conflicts |
377
+ | Method | HTTP | Path | Description |
378
+ | --------------------------------------------- | ------ | ------------------------------------------- | --------------------------------- |
379
+ | `list(query?)` | GET | `/phone-numbers` | List all phone numbers |
380
+ | `buy(body)` | POST | `/phone-numbers` | Purchase a new phone number |
381
+ | `update(id, body)` | PUT | `/phone-numbers/:id` | Update name or caller ID |
382
+ | `getUsage(id)` | GET | `/phone-numbers/:id/usage` | Get usage info |
383
+ | `getTollFreeVerification(id)` | GET | `/phone-numbers/:id/tollfree-verification` | Get toll-free verification status |
384
+ | `createTollFreeVerification(id, body)` | POST | `/phone-numbers/:id/tollfree-verification` | Start toll-free verification |
385
+ | `deleteTollFreeVerification(verificationSid)` | DELETE | `/phone-numbers/tollfree-verification/:sid` | Delete a toll-free verification |
386
+ | `createSipTrunk(id)` | POST | `/phone-numbers/:id/sip-trunk` | Create a SIP trunk for a number |
387
+ | `freeUp(id)` | POST | `/phone-numbers/:id/free-up-number` | Release a number from workflows |
388
+ | `delete(id)` | POST | `/phone-numbers/:id/delete-number` | Permanently delete a number |
389
+ | `removeFromWorkflow(id, body)` | POST | `/phone-numbers/:id/remove-from-workflow` | Remove from a specific workflow |
390
+ | `validateTollFreeNumbers(body)` | POST | `/phone-numbers/validate-toll-free-numbers` | Check for conflicts |
383
391
 
384
392
  ---
385
393
 
@@ -395,15 +403,15 @@ await client.sipTrunks.update("trunk-id", { name: "Updated" });
395
403
  await client.sipTrunks.delete("trunk-id");
396
404
  ```
397
405
 
398
- | Method | HTTP | Path | Description |
399
- |---|---|---|---|
400
- | `list()` | GET | `/sip-trunks` | List all SIP trunks |
401
- | `listOptions()` | GET | `/sip-trunks/options` | Lightweight list of trunk options |
402
- | `create(body)` | POST | `/sip-trunks` | Create a SIP trunk |
403
- | `createBulk(body)` | POST | `/sip-trunks/bulk` | Create multiple SIP trunks |
404
- | `get(trunkId)` | GET | `/sip-trunks/:id` | Get a SIP trunk |
405
- | `update(trunkId, body)` | PUT | `/sip-trunks/:id` | Update a SIP trunk |
406
- | `delete(trunkId)` | DELETE | `/sip-trunks/:id` | Delete a SIP trunk |
406
+ | Method | HTTP | Path | Description |
407
+ | ----------------------- | ------ | --------------------- | --------------------------------- |
408
+ | `list()` | GET | `/sip-trunks` | List all SIP trunks |
409
+ | `listOptions()` | GET | `/sip-trunks/options` | Lightweight list of trunk options |
410
+ | `create(body)` | POST | `/sip-trunks` | Create a SIP trunk |
411
+ | `createBulk(body)` | POST | `/sip-trunks/bulk` | Create multiple SIP trunks |
412
+ | `get(trunkId)` | GET | `/sip-trunks/:id` | Get a SIP trunk |
413
+ | `update(trunkId, body)` | PUT | `/sip-trunks/:id` | Update a SIP trunk |
414
+ | `delete(trunkId)` | DELETE | `/sip-trunks/:id` | Delete a SIP trunk |
407
415
 
408
416
  ---
409
417
 
@@ -435,25 +443,25 @@ await client.integrations.whatsApp.phoneNumbers({ credential_id: "...", business
435
443
  await client.integrations.whatsApp.messageTemplates({ credential_id: "...", business_account_id: "..." });
436
444
  ```
437
445
 
438
- | Method | HTTP | Path | Description |
439
- |---|---|---|---|
440
- | `list(query?)` | GET | `/integrations` | List all integrations |
441
- | `get(id)` | GET | `/integrations/:id` | Get integration and its events |
442
- | `createCredential(id, body)` | POST | `/integrations/:id/create-credential` | Create a credential for a form-based integration |
443
- | `googleSheets.spreadsheets(query?)` | GET | `/integrations/google-sheets/spreadsheets` | List spreadsheets |
444
- | `googleSheets.worksheets(query)` | GET | `/integrations/google-sheets/worksheets` | List worksheets in a spreadsheet |
445
- | `googleSheets.columns(query)` | GET | `/integrations/google-sheets/columns` | List columns in a worksheet |
446
- | `googleSheets.rows(query)` | GET | `/integrations/google-sheets/rows` | List rows in a worksheet |
447
- | `slack.channels(query?)` | GET | `/integrations/slack/channels` | List Slack channels |
448
- | `slack.users(query?)` | GET | `/integrations/slack/users` | List Slack users |
449
- | `teams.teams(query?)` | GET | `/integrations/teams/teams` | List Microsoft Teams teams |
450
- | `teams.channels(query?)` | GET | `/integrations/teams/channels` | List Microsoft Teams channels |
451
- | `teams.users(query?)` | GET | `/integrations/teams/users` | List Microsoft Teams users |
452
- | `twilioSms.phoneNumbers(query?)` | GET | `/integrations/twilio-sms/phone-numbers` | List Twilio SMS numbers |
453
- | `whatsApp.businesses(query)` | GET | `/integrations/whatsapp/businesses` | List WhatsApp businesses |
454
- | `whatsApp.businessAccounts(query)` | GET | `/integrations/whatsapp/business-accounts` | List WhatsApp business accounts |
455
- | `whatsApp.phoneNumbers(query)` | GET | `/integrations/whatsapp/phone-numbers` | List WhatsApp phone numbers |
456
- | `whatsApp.messageTemplates(query)` | GET | `/integrations/whatsapp/message-templates` | List WhatsApp message templates |
446
+ | Method | HTTP | Path | Description |
447
+ | ----------------------------------- | ---- | ------------------------------------------ | ------------------------------------------------ |
448
+ | `list(query?)` | GET | `/integrations` | List all integrations |
449
+ | `get(id)` | GET | `/integrations/:id` | Get integration and its events |
450
+ | `createCredential(id, body)` | POST | `/integrations/:id/create-credential` | Create a credential for a form-based integration |
451
+ | `googleSheets.spreadsheets(query?)` | GET | `/integrations/google-sheets/spreadsheets` | List spreadsheets |
452
+ | `googleSheets.worksheets(query)` | GET | `/integrations/google-sheets/worksheets` | List worksheets in a spreadsheet |
453
+ | `googleSheets.columns(query)` | GET | `/integrations/google-sheets/columns` | List columns in a worksheet |
454
+ | `googleSheets.rows(query)` | GET | `/integrations/google-sheets/rows` | List rows in a worksheet |
455
+ | `slack.channels(query?)` | GET | `/integrations/slack/channels` | List Slack channels |
456
+ | `slack.users(query?)` | GET | `/integrations/slack/users` | List Slack users |
457
+ | `teams.teams(query?)` | GET | `/integrations/teams/teams` | List Microsoft Teams teams |
458
+ | `teams.channels(query?)` | GET | `/integrations/teams/channels` | List Microsoft Teams channels |
459
+ | `teams.users(query?)` | GET | `/integrations/teams/users` | List Microsoft Teams users |
460
+ | `twilioSms.phoneNumbers(query?)` | GET | `/integrations/twilio-sms/phone-numbers` | List Twilio SMS numbers |
461
+ | `whatsApp.businesses(query)` | GET | `/integrations/whatsapp/businesses` | List WhatsApp businesses |
462
+ | `whatsApp.businessAccounts(query)` | GET | `/integrations/whatsapp/business-accounts` | List WhatsApp business accounts |
463
+ | `whatsApp.phoneNumbers(query)` | GET | `/integrations/whatsapp/phone-numbers` | List WhatsApp phone numbers |
464
+ | `whatsApp.messageTemplates(query)` | GET | `/integrations/whatsapp/message-templates` | List WhatsApp message templates |
457
465
 
458
466
  ---
459
467
 
@@ -467,13 +475,13 @@ const interactions = await client.contacts.getInteractions("contact-id");
467
475
  const memories = await client.contacts.getMemories("contact-id");
468
476
  ```
469
477
 
470
- | Method | HTTP | Path | Description |
471
- |---|---|---|---|
472
- | `list(query?)` | GET | `/contacts` | List contacts (cursor-paginated) |
473
- | `resolve(query)` | GET | `/contacts/resolve` | Look up a contact by phone number or email |
474
- | `get(contactId)` | GET | `/contacts/:id` | Get contact by ID |
475
- | `getInteractions(contactId)` | GET | `/contacts/:id/interactions` | Get call/message history for a contact |
476
- | `getMemories(contactId)` | GET | `/contacts/:id/memories` | Get AI memories for a contact |
478
+ | Method | HTTP | Path | Description |
479
+ | ---------------------------- | ---- | ---------------------------- | ------------------------------------------ |
480
+ | `list(query?)` | GET | `/contacts` | List contacts (cursor-paginated) |
481
+ | `resolve(query)` | GET | `/contacts/resolve` | Look up a contact by phone number or email |
482
+ | `get(contactId)` | GET | `/contacts/:id` | Get contact by ID |
483
+ | `getInteractions(contactId)` | GET | `/contacts/:id/interactions` | Get call/message history for a contact |
484
+ | `getMemories(contactId)` | GET | `/contacts/:id/memories` | Get AI memories for a contact |
477
485
 
478
486
  ---
479
487
 
@@ -482,20 +490,22 @@ const memories = await client.contacts.getMemories("contact-id");
482
490
  ```ts
483
491
  const kbs = await client.knowledgeBases.list();
484
492
  const files = await client.knowledgeBases.listFiles("kb-id");
485
- const urls = await client.knowledgeBases.getUploadUrls("kb-id", { files: [{ name: "doc.pdf", content_type: "application/pdf" }] });
493
+ const urls = await client.knowledgeBases.getUploadUrls("kb-id", {
494
+ files: [{ name: "doc.pdf", content_type: "application/pdf" }],
495
+ });
486
496
  await client.knowledgeBases.triggerChunking("kb-id");
487
497
  await client.knowledgeBases.deleteFile("kb-id", "file-id");
488
498
  await client.knowledgeBases.delete("kb-id");
489
499
  ```
490
500
 
491
- | Method | HTTP | Path | Description |
492
- |---|---|---|---|
493
- | `list()` | GET | `/knowledge-bases` | List all knowledge bases |
494
- | `listFiles(kbId)` | GET | `/knowledge-bases/:id/files` | List documents in a knowledge base |
495
- | `getUploadUrls(kbId, body)` | POST | `/knowledge-bases/:id/upload-urls` | Get pre-signed S3 upload URLs |
496
- | `triggerChunking(kbId)` | POST | `/knowledge-bases/:id/trigger-chunking` | Start document processing/chunking |
497
- | `deleteFile(kbId, fileId)` | DELETE | `/knowledge-bases/:id/files/:fileId` | Delete a file from a knowledge base |
498
- | `delete(kbId)` | DELETE | `/knowledge-bases/:id` | Delete a knowledge base |
501
+ | Method | HTTP | Path | Description |
502
+ | --------------------------- | ------ | --------------------------------------- | ----------------------------------- |
503
+ | `list()` | GET | `/knowledge-bases` | List all knowledge bases |
504
+ | `listFiles(kbId)` | GET | `/knowledge-bases/:id/files` | List documents in a knowledge base |
505
+ | `getUploadUrls(kbId, body)` | POST | `/knowledge-bases/:id/upload-urls` | Get pre-signed S3 upload URLs |
506
+ | `triggerChunking(kbId)` | POST | `/knowledge-bases/:id/trigger-chunking` | Start document processing/chunking |
507
+ | `deleteFile(kbId, fileId)` | DELETE | `/knowledge-bases/:id/files/:fileId` | Delete a file from a knowledge base |
508
+ | `delete(kbId)` | DELETE | `/knowledge-bases/:id` | Delete a knowledge base |
499
509
 
500
510
  ---
501
511
 
@@ -509,13 +519,13 @@ await client.workflowFolders.update("folder-id", { name: "Updated" });
509
519
  await client.workflowFolders.delete("folder-id");
510
520
  ```
511
521
 
512
- | Method | HTTP | Path | Description |
513
- |---|---|---|---|
514
- | `list(query?)` | GET | `/workflow-folders` | List folders (paginated) |
515
- | `create(body)` | POST | `/workflow-folders` | Create a folder |
516
- | `get(folderId)` | GET | `/workflow-folders/:id` | Get a folder |
517
- | `update(folderId, body)` | PUT | `/workflow-folders/:id` | Update a folder |
518
- | `delete(folderId)` | DELETE | `/workflow-folders/:id` | Delete a folder |
522
+ | Method | HTTP | Path | Description |
523
+ | ------------------------ | ------ | ----------------------- | ------------------------ |
524
+ | `list(query?)` | GET | `/workflow-folders` | List folders (paginated) |
525
+ | `create(body)` | POST | `/workflow-folders` | Create a folder |
526
+ | `get(folderId)` | GET | `/workflow-folders/:id` | Get a folder |
527
+ | `update(folderId, body)` | PUT | `/workflow-folders/:id` | Update a folder |
528
+ | `delete(folderId)` | DELETE | `/workflow-folders/:id` | Delete a folder |
519
529
 
520
530
  ---
521
531
 
@@ -527,25 +537,33 @@ await client.mcp.create({ name: "My MCP", url: "https://..." });
527
537
  await client.mcp.refresh("mcp-id");
528
538
  ```
529
539
 
530
- | Method | HTTP | Path | Description |
531
- |---|---|---|---|
532
- | `list(query?)` | GET | `/mcp` | List MCP servers (paginated) |
533
- | `create(body)` | POST | `/mcp` | Register a new MCP server |
540
+ | Method | HTTP | Path | Description |
541
+ | ---------------- | ---- | ------------------ | ----------------------------------- |
542
+ | `list(query?)` | GET | `/mcp` | List MCP servers (paginated) |
543
+ | `create(body)` | POST | `/mcp` | Register a new MCP server |
534
544
  | `refresh(mcpId)` | POST | `/mcp/:id/refresh` | Re-discover tools for an MCP server |
535
545
 
546
+ **OAuth2 (`auth_type: "oauth2"`)**: set `oauth2_credential_id` to the UUID of an **OAuth 2.0** integration credential (same org) configured with your provider’s token URL. Do not send `auth_token`; the API fetches a short-lived access token when creating, listing refresh, or when workflows run.
547
+
536
548
  ---
537
549
 
538
550
  ## `client.billing`
539
551
 
540
552
  ```ts
541
- const details = await client.billing.getDetails({ start: "2024-01-01", end: "2024-01-31" });
542
- const totals = await client.billing.getTotals({ start: "2024-01-01", end: "2024-01-31" });
553
+ const details = await client.billing.getDetails({
554
+ start: "2024-01-01",
555
+ end: "2024-01-31",
556
+ });
557
+ const totals = await client.billing.getTotals({
558
+ start: "2024-01-01",
559
+ end: "2024-01-31",
560
+ });
543
561
  ```
544
562
 
545
- | Method | HTTP | Path | Description |
546
- |---|---|---|---|
547
- | `getDetails(query)` | GET | `/billing/usage/details` | Detailed billing line items |
548
- | `getTotals(query)` | GET | `/billing/usage/totals` | Aggregated billing totals |
563
+ | Method | HTTP | Path | Description |
564
+ | ------------------- | ---- | ------------------------ | --------------------------- |
565
+ | `getDetails(query)` | GET | `/billing/usage/details` | Detailed billing line items |
566
+ | `getTotals(query)` | GET | `/billing/usage/totals` | Aggregated billing totals |
549
567
 
550
568
  ---
551
569
 
@@ -555,9 +573,9 @@ const totals = await client.billing.getTotals({ start: "2024-01-01", end: "2024-
555
573
  const info = await client.apiKey.describe();
556
574
  ```
557
575
 
558
- | Method | HTTP | Path | Description |
559
- |---|---|---|---|
560
- | `describe()` | GET | `/api-key/describe` | Introspect the current API key (ID, name, org, etc.) |
576
+ | Method | HTTP | Path | Description |
577
+ | ------------ | ---- | ------------------- | ---------------------------------------------------- |
578
+ | `describe()` | GET | `/api-key/describe` | Introspect the current API key (ID, name, org, etc.) |
561
579
 
562
580
  ---
563
581
 
@@ -567,35 +585,43 @@ Adversarial suites group multiple adversarial tests and can auto-generate them f
567
585
 
568
586
  ```ts
569
587
  const { suite } = await client.adversarialSuites.get("suite-id");
570
- await client.adversarialSuites.update("suite-id", { name: "New Name", generation_count: 10 });
588
+ await client.adversarialSuites.update("suite-id", {
589
+ name: "New Name",
590
+ generation_count: 10,
591
+ });
571
592
  await client.adversarialSuites.delete("suite-id");
572
593
 
573
594
  // Generate tests from the suite's generation_prompt using AI
574
595
  await client.adversarialSuites.generate("suite-id", { version_id: "v-id" });
575
596
 
576
597
  // Generate a mermaid workflow graph for visualization
577
- await client.adversarialSuites.generateGraph("suite-id", { version_id: "v-id" });
598
+ await client.adversarialSuites.generateGraph("suite-id", {
599
+ version_id: "v-id",
600
+ });
578
601
 
579
602
  // Run all tests in the suite
580
- const { suite_run_id } = await client.adversarialSuites.run("suite-id", { version_id: "v-id" });
603
+ const { suite_run_id } = await client.adversarialSuites.run("suite-id", {
604
+ version_id: "v-id",
605
+ });
581
606
 
582
607
  // Poll results
583
608
  const { runs } = await client.adversarialSuites.listRuns("suite-id");
584
609
  const { run } = await client.adversarialSuites.getRun("suite-run-id");
585
- const { test_runs } = await client.adversarialSuites.getRunTestRuns("suite-run-id");
610
+ const { test_runs } =
611
+ await client.adversarialSuites.getRunTestRuns("suite-run-id");
586
612
  ```
587
613
 
588
- | Method | HTTP | Path | Description |
589
- |---|---|---|---|
590
- | `get(suiteId)` | GET | `/adversarial-suites/:id` | Get suite with optional mermaid graph |
591
- | `update(suiteId, body)` | PATCH | `/adversarial-suites/:id` | Update name, model, timeout, generation settings |
592
- | `delete(suiteId)` | DELETE | `/adversarial-suites/:id` | Delete a suite |
593
- | `generate(suiteId, body?)` | POST | `/adversarial-suites/:id/generate` | AI-generate tests from the suite's generation prompt |
594
- | `generateGraph(suiteId, body)` | POST | `/adversarial-suites/:id/generate-graph` | Generate a mermaid workflow visualization |
595
- | `run(suiteId, body)` | POST | `/adversarial-suites/:id/run` | Execute all tests asynchronously, returns `suite_run_id` |
596
- | `listRuns(suiteId, query?)` | GET | `/adversarial-suites/:id/runs` | List suite runs |
597
- | `getRun(suiteRunId)` | GET | `/adversarial-suites/runs/:runId` | Get a suite run with aggregate pass/fail counts |
598
- | `getRunTestRuns(suiteRunId)` | GET | `/adversarial-suites/runs/:runId/test-runs` | List individual test results within a suite run |
614
+ | Method | HTTP | Path | Description |
615
+ | ------------------------------ | ------ | ------------------------------------------- | -------------------------------------------------------- |
616
+ | `get(suiteId)` | GET | `/adversarial-suites/:id` | Get suite with optional mermaid graph |
617
+ | `update(suiteId, body)` | PATCH | `/adversarial-suites/:id` | Update name, model, timeout, generation settings |
618
+ | `delete(suiteId)` | DELETE | `/adversarial-suites/:id` | Delete a suite |
619
+ | `generate(suiteId, body?)` | POST | `/adversarial-suites/:id/generate` | AI-generate tests from the suite's generation prompt |
620
+ | `generateGraph(suiteId, body)` | POST | `/adversarial-suites/:id/generate-graph` | Generate a mermaid workflow visualization |
621
+ | `run(suiteId, body)` | POST | `/adversarial-suites/:id/run` | Execute all tests asynchronously, returns `suite_run_id` |
622
+ | `listRuns(suiteId, query?)` | GET | `/adversarial-suites/:id/runs` | List suite runs |
623
+ | `getRun(suiteRunId)` | GET | `/adversarial-suites/runs/:runId` | Get a suite run with aggregate pass/fail counts |
624
+ | `getRunTestRuns(suiteRunId)` | GET | `/adversarial-suites/runs/:runId/test-runs` | List individual test results within a suite run |
599
625
 
600
626
  ---
601
627
 
@@ -605,11 +631,16 @@ Individual adversarial tests simulate a user trying to break the agent's behavio
605
631
 
606
632
  ```ts
607
633
  const { test } = await client.adversarialTests.get("test-id");
608
- await client.adversarialTests.update("test-id", { adversarial_prompt: "Try to get PII", timeout_seconds: 120 });
634
+ await client.adversarialTests.update("test-id", {
635
+ adversarial_prompt: "Try to get PII",
636
+ timeout_seconds: 120,
637
+ });
609
638
  await client.adversarialTests.delete("test-id");
610
639
 
611
640
  // Run a single test
612
- const { test_run_id } = await client.adversarialTests.run("test-id", { version_id: "v-id" });
641
+ const { test_run_id } = await client.adversarialTests.run("test-id", {
642
+ version_id: "v-id",
643
+ });
613
644
 
614
645
  // Poll results
615
646
  const { runs } = await client.adversarialTests.listRuns("test-id");
@@ -617,15 +648,15 @@ const { run } = await client.adversarialTests.getRun("run-id");
617
648
  const { messages } = await client.adversarialTests.getRunMessages("run-id");
618
649
  ```
619
650
 
620
- | Method | HTTP | Path | Description |
621
- |---|---|---|---|
622
- | `get(testId)` | GET | `/adversarial-tests/:id` | Get test details |
623
- | `update(testId, body)` | PATCH | `/adversarial-tests/:id` | Update prompt, model, variables, timeout |
624
- | `delete(testId)` | DELETE | `/adversarial-tests/:id` | Delete a test |
625
- | `run(testId, body)` | POST | `/adversarial-tests/:id/run` | Execute a test asynchronously, returns `test_run_id` |
626
- | `listRuns(testId, query?)` | GET | `/adversarial-tests/:id/runs` | List test runs with audit remarks |
627
- | `getRun(runId)` | GET | `/adversarial-tests/runs/:runId` | Get a single run with full audit remarks |
628
- | `getRunMessages(runId)` | GET | `/adversarial-tests/runs/:runId/messages` | Get the full conversation from a test run |
651
+ | Method | HTTP | Path | Description |
652
+ | -------------------------- | ------ | ----------------------------------------- | ---------------------------------------------------- |
653
+ | `get(testId)` | GET | `/adversarial-tests/:id` | Get test details |
654
+ | `update(testId, body)` | PATCH | `/adversarial-tests/:id` | Update prompt, model, variables, timeout |
655
+ | `delete(testId)` | DELETE | `/adversarial-tests/:id` | Delete a test |
656
+ | `run(testId, body)` | POST | `/adversarial-tests/:id/run` | Execute a test asynchronously, returns `test_run_id` |
657
+ | `listRuns(testId, query?)` | GET | `/adversarial-tests/:id/runs` | List test runs with audit remarks |
658
+ | `getRun(runId)` | GET | `/adversarial-tests/runs/:runId` | Get a single run with full audit remarks |
659
+ | `getRunMessages(runId)` | GET | `/adversarial-tests/runs/:runId/messages` | Get the full conversation from a test run |
629
660
 
630
661
  ---
631
662
 
@@ -635,7 +666,10 @@ Northstars are quality criteria that define how the agent should behave. They ar
635
666
 
636
667
  ```ts
637
668
  const { northstar } = await client.northstars.get("northstar-id");
638
- await client.northstars.update("northstar-id", { enabled: true, priority: "high" });
669
+ await client.northstars.update("northstar-id", {
670
+ enabled: true,
671
+ priority: "high",
672
+ });
639
673
  await client.northstars.delete("northstar-id");
640
674
 
641
675
  // Get full regeneration history
@@ -651,14 +685,14 @@ const { feedback } = await client.northstars.submitFeedback("northstar-id", {
651
685
  await client.northstars.deleteFeedback("northstar-id");
652
686
  ```
653
687
 
654
- | Method | HTTP | Path | Description |
655
- |---|---|---|---|
656
- | `get(northstarId)` | GET | `/northstars/:id` | Get a northstar |
657
- | `update(northstarId, body)` | PATCH | `/northstars/:id` | Update name, description, examples, category, priority, or enabled state |
658
- | `delete(northstarId)` | DELETE | `/northstars/:id` | Delete a northstar |
659
- | `getHistory(northstarId)` | GET | `/northstars/:id/history` | Get the full regeneration chain, oldest first |
660
- | `submitFeedback(northstarId, body)` | POST | `/northstars/:id/feedback` | Rate a northstar's correctness (−2 to +2), optionally trigger regeneration |
661
- | `deleteFeedback(northstarId)` | DELETE | `/northstars/:id/feedback` | Remove your feedback on a northstar |
688
+ | Method | HTTP | Path | Description |
689
+ | ----------------------------------- | ------ | -------------------------- | -------------------------------------------------------------------------- |
690
+ | `get(northstarId)` | GET | `/northstars/:id` | Get a northstar |
691
+ | `update(northstarId, body)` | PATCH | `/northstars/:id` | Update name, description, examples, category, priority, or enabled state |
692
+ | `delete(northstarId)` | DELETE | `/northstars/:id` | Delete a northstar |
693
+ | `getHistory(northstarId)` | GET | `/northstars/:id/history` | Get the full regeneration chain, oldest first |
694
+ | `submitFeedback(northstarId, body)` | POST | `/northstars/:id/feedback` | Rate a northstar's correctness (−2 to +2), optionally trigger regeneration |
695
+ | `deleteFeedback(northstarId)` | DELETE | `/northstars/:id/feedback` | Remove your feedback on a northstar |
662
696
 
663
697
  ---
664
698
 
@@ -675,19 +709,21 @@ await client.customEvals.update("eval-id", {
675
709
  await client.customEvals.delete("eval-id");
676
710
 
677
711
  // Run an eval
678
- const { run_id } = await client.customEvals.run("eval-id", { version_id: "v-id" });
712
+ const { run_id } = await client.customEvals.run("eval-id", {
713
+ version_id: "v-id",
714
+ });
679
715
 
680
716
  // Poll results
681
717
  const { runs } = await client.customEvals.listRuns("eval-id");
682
718
  ```
683
719
 
684
- | Method | HTTP | Path | Description |
685
- |---|---|---|---|
686
- | `get(evalId)` | GET | `/custom-evals/:id` | Get a custom eval |
687
- | `update(evalId, body)` | PATCH | `/custom-evals/:id` | Update messages, expected outputs, variables, or northstar IDs |
688
- | `delete(evalId)` | DELETE | `/custom-evals/:id` | Delete a custom eval |
689
- | `run(evalId, body)` | POST | `/custom-evals/:id/run` | Execute the eval asynchronously, returns `run_id` |
690
- | `listRuns(evalId, query?)` | GET | `/custom-evals/:id/runs` | List runs with pass/fail and judge reasoning |
720
+ | Method | HTTP | Path | Description |
721
+ | -------------------------- | ------ | ------------------------ | -------------------------------------------------------------- |
722
+ | `get(evalId)` | GET | `/custom-evals/:id` | Get a custom eval |
723
+ | `update(evalId, body)` | PATCH | `/custom-evals/:id` | Update messages, expected outputs, variables, or northstar IDs |
724
+ | `delete(evalId)` | DELETE | `/custom-evals/:id` | Delete a custom eval |
725
+ | `run(evalId, body)` | POST | `/custom-evals/:id/run` | Execute the eval asynchronously, returns `run_id` |
726
+ | `listRuns(evalId, query?)` | GET | `/custom-evals/:id/runs` | List runs with pass/fail and judge reasoning |
691
727
 
692
728
  ---
693
729
 
@@ -699,8 +735,8 @@ Issues (quality flags) are raised when a conversation fails a northstar or quali
699
735
  await client.issues.update("issue-id", { status: "approved" });
700
736
  ```
701
737
 
702
- | Method | HTTP | Path | Description |
703
- |---|---|---|---|
738
+ | Method | HTTP | Path | Description |
739
+ | ----------------------- | ----- | ------------- | ----------------------------------------------------------------- |
704
740
  | `update(issueId, body)` | PATCH | `/issues/:id` | Update issue status (`open` / `approved` / `rejected` / `closed`) |
705
741
 
706
742
  ---
@@ -727,11 +763,11 @@ await client.auditRemarks.submitFeedback("audit-remark-id", {
727
763
  await client.auditRemarks.deleteFeedback("audit-remark-id");
728
764
  ```
729
765
 
730
- | Method | HTTP | Path | Description |
731
- |---|---|---|---|
732
- | `getFeedback(auditRemarkId)` | GET | `/audit-remarks/:id/feedback` | Get your feedback for this remark, or `null` |
733
- | `submitFeedback(auditRemarkId, body)` | POST | `/audit-remarks/:id/feedback` | Submit thumbs up/down; a thumbs-up adds the remark as a northstar example |
734
- | `deleteFeedback(auditRemarkId)` | DELETE | `/audit-remarks/:id/feedback` | Delete your feedback |
766
+ | Method | HTTP | Path | Description |
767
+ | ------------------------------------- | ------ | ----------------------------- | ------------------------------------------------------------------------- |
768
+ | `getFeedback(auditRemarkId)` | GET | `/audit-remarks/:id/feedback` | Get your feedback for this remark, or `null` |
769
+ | `submitFeedback(auditRemarkId, body)` | POST | `/audit-remarks/:id/feedback` | Submit thumbs up/down; a thumbs-up adds the remark as a northstar example |
770
+ | `deleteFeedback(auditRemarkId)` | DELETE | `/audit-remarks/:id/feedback` | Delete your feedback |
735
771
 
736
772
  ---
737
773
 
@@ -765,7 +801,9 @@ app.post("/api/chat-token", async (req, res) => {
765
801
  import { HappyRobotChatClient } from "@happyrobot-ai/sdk";
766
802
 
767
803
  // 1. Get a client token from your server
768
- const { token } = await fetch("/api/chat-token", { method: "POST" }).then(r => r.json());
804
+ const { token } = await fetch("/api/chat-token", { method: "POST" }).then((r) =>
805
+ r.json()
806
+ );
769
807
 
770
808
  // 2. Initialize the browser-side client
771
809
  const chat = new HappyRobotChatClient({ token });
@@ -798,7 +836,10 @@ console.log(ack.message.id); // server-assigned message ID
798
836
 
799
837
  // 6. Send messages with file attachments
800
838
  const artifact = await chat.uploadFile(fileBlob, "photo.png", "image/png");
801
- await connection.sendMessage({ content: "Here's the photo", artifacts: [artifact] });
839
+ await connection.sendMessage({
840
+ content: "Here's the photo",
841
+ artifacts: [artifact],
842
+ });
802
843
 
803
844
  // 7. Get history (page reload, reconnect)
804
845
  const { messages } = await chat.getHistory(session_id);
@@ -818,8 +859,15 @@ await connection.sendMessage({
818
859
  });
819
860
 
820
861
  // Option B: Manual 3-step flow for more control
821
- const upload = await chat.getPresignedUpload({ filename: "photo.png", mime_type: "image/png" });
822
- await fetch(upload.upload_url, { method: "PUT", body: fileBlob, headers: { "Content-Type": "image/png" } });
862
+ const upload = await chat.getPresignedUpload({
863
+ filename: "photo.png",
864
+ mime_type: "image/png",
865
+ });
866
+ await fetch(upload.upload_url, {
867
+ method: "PUT",
868
+ body: fileBlob,
869
+ headers: { "Content-Type": "image/png" },
870
+ });
823
871
  await chat.completeUpload({
824
872
  artifact_id: upload.artifact_id,
825
873
  s3_uri: upload.s3_uri,
@@ -829,56 +877,63 @@ await chat.completeUpload({
829
877
  });
830
878
  await connection.sendMessage({
831
879
  content: "Here's the photo",
832
- artifacts: [{ media_id: upload.artifact_id, mime_type: "image/png", filename: "photo.png", size_bytes: fileBlob.size }],
880
+ artifacts: [
881
+ {
882
+ media_id: upload.artifact_id,
883
+ mime_type: "image/png",
884
+ filename: "photo.png",
885
+ size_bytes: fileBlob.size,
886
+ },
887
+ ],
833
888
  });
834
889
  ```
835
890
 
836
891
  ### `HappyRobotClient` (server-side)
837
892
 
838
- | Method | Description |
839
- |---|---|
893
+ | Method | Description |
894
+ | ------------------------------------------------ | -------------------------------------------- |
840
895
  | `client.chat.createToken({ workflow_id, env? })` | Create a scoped client token (1 hour expiry) |
841
896
 
842
897
  ### `HappyRobotChatClient` (browser-side)
843
898
 
844
- | Method | Description |
845
- |---|---|
846
- | `chat.createSession()` | Create a new chat session |
847
- | `chat.connect(sessionId, handlers)` | Open bidirectional WebSocket — returns `ChatConnection` |
899
+ | Method | Description |
900
+ | ------------------------------------------------------ | --------------------------------------------------------- |
901
+ | `chat.createSession()` | Create a new chat session |
902
+ | `chat.connect(sessionId, handlers)` | Open bidirectional WebSocket — returns `ChatConnection` |
848
903
  | `chat.sendMessage(sessionId, { content, artifacts? })` | Send a user message via HTTP (fallback if WS unavailable) |
849
- | `chat.getHistory(sessionId)` | Get message history |
850
- | `chat.uploadFile(file, filename, mimeType)` | Upload a file (convenience method) |
851
- | `chat.getPresignedUpload({ filename, mime_type })` | Get presigned S3 upload URL |
852
- | `chat.completeUpload({ artifact_id, s3_uri, ... })` | Register uploaded artifact |
904
+ | `chat.getHistory(sessionId)` | Get message history |
905
+ | `chat.uploadFile(file, filename, mimeType)` | Upload a file (convenience method) |
906
+ | `chat.getPresignedUpload({ filename, mime_type })` | Get presigned S3 upload URL |
907
+ | `chat.completeUpload({ artifact_id, s3_uri, ... })` | Register uploaded artifact |
853
908
 
854
909
  ### `ChatConnection`
855
910
 
856
- | Method | Description |
857
- |---|---|
911
+ | Method | Description |
912
+ | ------------------------------------------------- | ----------------------------------------------------------------------------------- |
858
913
  | `connection.sendMessage({ content, artifacts? })` | Send a message via WebSocket. Returns a `Promise` that resolves with the server ack |
859
- | `connection.close()` | Close the WebSocket connection |
860
- | `connection.ws` | The underlying `WebSocket` instance |
914
+ | `connection.close()` | Close the WebSocket connection |
915
+ | `connection.ws` | The underlying `WebSocket` instance |
861
916
 
862
917
  ### WebSocket Events
863
918
 
864
919
  **Server → Client:**
865
920
 
866
- | Event | Fields | Description |
867
- |---|---|---|
868
- | `connected` | `session_id` | Connection established |
869
- | `response-start` | `content` | AI started generating a response |
870
- | `response-chunk` | `content` | Partial response text |
871
- | `response-end` | `content` | Complete response text |
872
- | `session-closed` | `session_id`, `status`, `reason`, `duration`, `timestamp` | Session ended |
873
- | `token-expired` | — | JWT expired — reconnect with a fresh token |
874
- | `message-ack` | `id`, `message` | Server confirmed the message was sent |
875
- | `message-error` | `id`, `error` | Server failed to send the message |
876
- | `heartbeat` | — | Keep-alive (every 15s) |
921
+ | Event | Fields | Description |
922
+ | ---------------- | --------------------------------------------------------- | ------------------------------------------ |
923
+ | `connected` | `session_id` | Connection established |
924
+ | `response-start` | `content` | AI started generating a response |
925
+ | `response-chunk` | `content` | Partial response text |
926
+ | `response-end` | `content` | Complete response text |
927
+ | `session-closed` | `session_id`, `status`, `reason`, `duration`, `timestamp` | Session ended |
928
+ | `token-expired` | — | JWT expired — reconnect with a fresh token |
929
+ | `message-ack` | `id`, `message` | Server confirmed the message was sent |
930
+ | `message-error` | `id`, `error` | Server failed to send the message |
931
+ | `heartbeat` | — | Keep-alive (every 15s) |
877
932
 
878
933
  **Client → Server:**
879
934
 
880
- | Event | Fields | Description |
881
- |---|---|---|
935
+ | Event | Fields | Description |
936
+ | --------- | ------------------------------ | ----------------------------------------------------- |
882
937
  | `message` | `content`, `artifacts?`, `id?` | Send a user message. `id` is echoed back in ack/error |
883
938
 
884
939
  ---
@@ -914,7 +969,9 @@ app.post("/api/voice-token", async (req, res) => {
914
969
  import { HappyRobotVoiceClient } from "@happyrobot-ai/sdk/voice";
915
970
 
916
971
  // 1. Get a voice token from your server
917
- const { url, token } = await fetch("/api/voice-token", { method: "POST" }).then(r => r.json());
972
+ const { url, token } = await fetch("/api/voice-token", { method: "POST" }).then(
973
+ (r) => r.json()
974
+ );
918
975
 
919
976
  // 2. Create the voice client and connect
920
977
  const voice = new HappyRobotVoiceClient({ url, token });
@@ -951,39 +1008,39 @@ await connection.disconnect();
951
1008
 
952
1009
  ### `HappyRobotClient` (server-side)
953
1010
 
954
- | Method | Description |
955
- |---|---|
1011
+ | Method | Description |
1012
+ | -------------------------------------------------------- | -------------------------------------- |
956
1013
  | `client.voice.createToken({ workflow_id, data?, env? })` | Create a LiveKit token for voice calls |
957
1014
 
958
1015
  ### `HappyRobotVoiceClient` (browser-side)
959
1016
 
960
- | Method | Description |
961
- |---|---|
962
- | `new HappyRobotVoiceClient({ url, token })` | Create client with LiveKit credentials |
963
- | `voice.connect(handlers?)` | Connect to room, enable microphone — returns `VoiceConnection` |
1017
+ | Method | Description |
1018
+ | ------------------------------------------- | -------------------------------------------------------------- |
1019
+ | `new HappyRobotVoiceClient({ url, token })` | Create client with LiveKit credentials |
1020
+ | `voice.connect(handlers?)` | Connect to room, enable microphone — returns `VoiceConnection` |
964
1021
 
965
1022
  ### `VoiceConnection`
966
1023
 
967
- | Method | Description |
968
- |---|---|
969
- | `connection.disconnect()` | End the call and disconnect from the room |
970
- | `connection.mute()` | Mute the local microphone |
971
- | `connection.unmute()` | Unmute the local microphone |
972
- | `connection.isMuted()` | Check mute state |
973
- | `connection.room` | Underlying LiveKit `Room` instance for advanced use cases |
1024
+ | Method | Description |
1025
+ | ------------------------- | --------------------------------------------------------- |
1026
+ | `connection.disconnect()` | End the call and disconnect from the room |
1027
+ | `connection.mute()` | Mute the local microphone |
1028
+ | `connection.unmute()` | Unmute the local microphone |
1029
+ | `connection.isMuted()` | Check mute state |
1030
+ | `connection.room` | Underlying LiveKit `Room` instance for advanced use cases |
974
1031
 
975
1032
  ### Room Events
976
1033
 
977
- | Handler | Description |
978
- |---|---|
979
- | `onConnected` | Connected to the LiveKit room |
980
- | `onDisconnected` | Disconnected from the room |
981
- | `onAgentConnected` | AI agent participant joined the room |
982
- | `onTrackSubscribed` | Remote audio track subscribed (auto-plays) |
983
- | `onTrackUnsubscribed` | Remote audio track unsubscribed |
984
- | `onReconnecting` | Connection temporarily lost — attempting to reconnect |
985
- | `onReconnected` | Successfully reconnected |
986
- | `onError` | An error occurred |
1034
+ | Handler | Description |
1035
+ | --------------------- | ----------------------------------------------------- |
1036
+ | `onConnected` | Connected to the LiveKit room |
1037
+ | `onDisconnected` | Disconnected from the room |
1038
+ | `onAgentConnected` | AI agent participant joined the room |
1039
+ | `onTrackSubscribed` | Remote audio track subscribed (auto-plays) |
1040
+ | `onTrackUnsubscribed` | Remote audio track unsubscribed |
1041
+ | `onReconnecting` | Connection temporarily lost — attempting to reconnect |
1042
+ | `onReconnected` | Successfully reconnected |
1043
+ | `onError` | An error occurred |
987
1044
 
988
1045
  ---
989
1046
 
@@ -1016,7 +1073,11 @@ for await (const workflow of client.workflows.listAll({ folder_id: "..." })) {
1016
1073
  ## Error Handling
1017
1074
 
1018
1075
  ```ts
1019
- import { ApiError, AuthenticationError, NotFoundError } from "@happyrobot-ai/sdk";
1076
+ import {
1077
+ ApiError,
1078
+ AuthenticationError,
1079
+ NotFoundError,
1080
+ } from "@happyrobot-ai/sdk";
1020
1081
 
1021
1082
  try {
1022
1083
  const wf = await client.workflows.get("nonexistent");