Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
ad181bf
docs(server-sdks): add TypeScript ChatGateway and HandoffRouter refer…
hey-august Oct 22, 2026
d675a07
docs(server-sdks): add TypeScript capabilities, post-prompt, and SHA-…
hey-august Oct 22, 2026
a6f2199
docs(server-sdks): sync TypeScript AgentBase reference to 3.7.1
hey-august Oct 22, 2026
1deaaef
docs(server-sdks): sync TypeScript FunctionResult and SemanticGate re…
hey-august Oct 22, 2026
5d4b046
docs(server-sdks): correct TypeScript DataMap body and template scoping
hey-august Oct 22, 2026
868e71c
docs(server-sdks): sync TypeScript skills reference to 3.7.1
hey-august Oct 22, 2026
063ea8d
docs(server-sdks): sync TypeScript CLI reference and add sw-tsdocs
hey-august Oct 22, 2026
244026a
docs(server-sdks): sync TypeScript configuration, Bedrock, LiveWire, …
hey-august Oct 22, 2026
d61c9e4
chore(server-sdks): record TypeScript reference sync to v3.7.1
hey-august Oct 22, 2026
6de06a6
docs(calling): bump TypeScript SDK pin to 3.7.1 and fix guide samples
hey-august Oct 22, 2026
2e2c4c0
docs(rules): pin TypeScript SDK 3.7.1 and tie guide pins to the refer…
hey-august Oct 22, 2026
5c341a4
docs(calling): skip enter_queue validation per verb and fix record-ca…
hey-august Oct 23, 2026
af750e4
docs(server-sdks): correct TypeScript DataMap webhook method, chainin…
hey-august Oct 23, 2026
590dec7
docs(server-sdks): correct TypeScript skill instance keys and skill p…
hey-august Oct 23, 2026
77ee23d
docs(server-sdks): fix TypeScript Bedrock, FunctionResult, and Semant…
hey-august Oct 23, 2026
5599dd8
Merge branch 'main' into august-20261022-sync-ts
hey-august Oct 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .claude/rules/mdx-capability-guides.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,9 @@ Canonical names come from the glossary (`/docs/platform/glossary`); the ones thi

- **SDK examples first.** For every API operation covered by a supported SDK, lead the explanation with the SDK method and make its example the first visible option. In a shared `<CodeBlocks>`, order Python SDK, then TypeScript SDK, then the direct HTTP alternative (see "Direct HTTP" above). Apply this to setup, resource creation, authentication, call control, and follow-up tasks as well as the first call. In prose, say "the Server SDKs" and link to the landing page (`/docs/server-sdks`), before the underlying REST endpoint; never name a language or link a per-language reference page. Code block titles still name the language. If no supported SDK method exists for the documented version, explain the gap and use direct HTTP for that operation. A hosted-script-only step can show YAML and JSON directly because the reader pastes a document into the Dashboard.
- **Complete programs.** Every sample under `<Steps>` and `## Examples` runs as pasted: imports, client setup, the call, and the wait or disconnect. A block under a task section may show only the changed lines, with line highlights (`{6-8}`), when its paragraph names the sample it extends.
- **Header comments** on every complete sample. Python: `# Install: python -m pip install signalwire-sdk==3.4.1` then `# Save as <name>.py and run: python <name>.py`. TypeScript with no type annotations: `// Install: npm install @signalwire/sdk@2.0.5` then `// This sample also runs as JavaScript: save as <name>.mjs,` / `// then run: node <name>.mjs`. TypeScript that uses types: `// Save as <name>.mts and run: npx tsx <name>.mts`. Browser: `// Install: npm install @signalwire/js@4.0.0-rc.2 rxjs@7.8.2` plus the HTML elements the script expects, as comments.
- **Pinned versions** are literal and identical across every guide: `signalwire-sdk==3.4.1`, `@signalwire/sdk@2.0.5`, `@signalwire/js@4.0.0-rc.2 rxjs@7.8.2`. Bump them in every guide in one PR, never one page at a time.
- **Header comments** on every complete sample. Python: `# Install: python -m pip install signalwire-sdk==3.4.1` then `# Save as <name>.py and run: python <name>.py`. TypeScript with no type annotations: `// Install: npm install @signalwire/sdk@3.7.1` then `// This sample also runs as JavaScript: save as <name>.mjs,` / `// then run: node <name>.mjs`. TypeScript that uses types: `// Save as <name>.mts and run: npx tsx <name>.mts`. Browser: `// Install: npm install @signalwire/js@4.0.0-rc.2 rxjs@7.8.2` plus the HTML elements the script expects, as comments.
- **Pinned versions** are literal and identical across every guide: `signalwire-sdk==3.4.1`, `@signalwire/sdk@3.7.1`, `@signalwire/js@4.0.0-rc.2 rxjs@7.8.2`. Bump them in every guide in one PR, never one page at a time.
- **Pins match the reference.** Each pinned Server SDK version must be the release whose source the reference pages are synced to, as recorded for that SDK in `fern/products/server-sdks/sdk-source-sync.json` (`synced_commit` is that release's tag commit). Bumping a pin means syncing that SDK's reference to the same release, and syncing the reference to a new release means bumping the pin: do both in the same PR, or guide samples and reference pages disagree.
- **Placeholders**: `<YOUR_SPACE>`, `<YOUR_PROJECT_ID>`, `<YOUR_API_TOKEN>`, `<YOUR_CALLER_ID>`, `<YOUR_DESTINATION>`, `<YOUR_STATUS_WEBHOOK_URL>`, `<YOUR_CALL_ID>`; new ones follow the same `<YOUR_…>` shape. Explain them once, in a `| Value | Replace with |` table before the first code block.
- **Relay boilerplate**: `contexts=["default"]`, `timeout: 30` on the phone device, Python `async with client:` and `await call.wait_for_ended()`, TypeScript `await client.connect()` / `try … finally { await client.disconnect(); }` and `await call.waitForEnded()`. Hang up in an `on_completed`/`onCompleted` callback guarded by `call.state !== "ended"`.
- **Builder gaps**: when the SDK's SWML builder lacks a verb, say so in a comment and use `add_verb`/`addVerb` with validation off for that verb only. Don't silently hand-write JSON where the builder works.
Expand Down
4 changes: 2 additions & 2 deletions fern/products/platform/pages/ai/guides/semantic-gates.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,8 @@ default. Set the
URL to show your own image instead.

<Note>
The Python Server SDK accepts `visual_input` on a gate from version 3.7.1. The TypeScript Server SDK
doesn't accept it yet, so define video gates in SWML.
The Server SDKs accept `visual_input` on a gate from version 3.7.1: `visual_input` in Python and the
`visualInput` option in TypeScript.
</Note>

## Tune or turn off gates for a call
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ print(call["id"])
</CodeBlock>
<CodeBlock title="TypeScript — REST client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as send-fax.mjs,
// then run: node send-fax.mjs
import { RestClient, SwmlBuilder } from "@signalwire/sdk";
Expand All @@ -135,12 +135,10 @@ const client = new RestClient({

const swml = new SwmlBuilder()
.send_fax({ document: "<YOUR_FAX_DOCUMENT_URL>", header_info: "Bayview Taxi receipt" })
.build();
.render(); // JSON text; parse it to pass the document object to dial()

const call = await client.calling.dial({
from: "<YOUR_CALLER_ID>",
to: "<YOUR_DESTINATION>",
swml,
const call = await client.calling.dial("<YOUR_CALLER_ID>", "<YOUR_DESTINATION>", {
swml: JSON.parse(swml),
});
console.log(call.id);
```
Expand Down Expand Up @@ -215,7 +213,7 @@ print(script["id"])
</CodeBlock>
<CodeBlock title="TypeScript — REST client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as receive-fax-script.mjs,
// then run: node receive-fax-script.mjs
import { RestClient, SwmlBuilder } from "@signalwire/sdk";
Expand All @@ -228,7 +226,7 @@ const client = new RestClient({

const swml = new SwmlBuilder()
.receive_fax()
.build();
.render(); // The script's contents are SWML as JSON text

const script = await client.fabric.swmlScripts.create({
name: "Receive faxes",
Expand Down Expand Up @@ -377,7 +375,7 @@ asyncio.run(main())
</CodeBlock>
<CodeBlock title="TypeScript — Relay client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// Save as send-fax-relay.mts and run: npx tsx send-fax-relay.mts
import { RelayClient, FaxEvent } from "@signalwire/sdk";

Expand Down Expand Up @@ -468,7 +466,7 @@ client.run()
</CodeBlock>
<CodeBlock title="TypeScript — Relay client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// Save as receive-fax-relay.mts and run: npx tsx receive-fax-relay.mts
import { RelayClient, FaxEvent } from "@signalwire/sdk";

Expand Down
50 changes: 26 additions & 24 deletions fern/products/platform/pages/calling/voice/call-queues.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ print(queue["id"])
</CodeBlock>
<CodeBlock title="TypeScript — REST client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as create-queue.mjs,
// then run: node create-queue.mjs
import { RestClient } from "@signalwire/sdk";
Expand Down Expand Up @@ -193,7 +193,7 @@ service.serve()
</CodeBlock>
<CodeBlock title="TypeScript — SWML builder">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as dispatch-queue.mjs,
// then run: node dispatch-queue.mjs
import { SWMLService } from "@signalwire/sdk";
Expand All @@ -204,13 +204,13 @@ const service = new SWMLService({
port: 3000,
basicAuth: ["signalwire", "<YOUR_BASIC_AUTH_PASSWORD>"],
});
service
.getBuilder()
.say("Thanks for calling Bayview Taxi. A dispatcher will be with you shortly.")
.enter_queue({ queue_name: "dispatch", wait_time: 120 })
// Runs only if the caller leaves the queue without reaching an agent.
.say("All our dispatchers are busy. Please call back in a few minutes.")
.hangup();
const swml = service.getBuilder();
swml.say("Thanks for calling Bayview Taxi. A dispatcher will be with you shortly.");
// The SDK's SWML schema requires transfer_after_bridge on enter_queue, which the
// platform treats as optional, so skip validation for this verb only.
swml.addVerb("enter_queue", { queue_name: "dispatch", wait_time: 120 }, { skipValidation: true });
// Runs only if the caller leaves the queue without reaching an agent.
swml.say("All our dispatchers are busy. Please call back in a few minutes.").hangup();

await service.serve();
```
Expand Down Expand Up @@ -295,7 +295,7 @@ print(call["id"])
</CodeBlock>
<CodeBlock title="TypeScript — REST client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as call-agent.mjs,
// then run: node call-agent.mjs
import { RestClient, SwmlBuilder } from "@signalwire/sdk";
Expand All @@ -312,12 +312,10 @@ const swml = new SwmlBuilder()
// Runs only if no caller is waiting.
.say("No callers are waiting.")
.hangup()
.build();
.render(); // JSON text; parse it to pass the document object to dial()

const call = await client.calling.dial({
from: "<YOUR_CALLER_ID>",
to: "<YOUR_AGENT_NUMBER>",
swml,
const call = await client.calling.dial("<YOUR_CALLER_ID>", "<YOUR_AGENT_NUMBER>", {
swml: JSON.parse(swml),
});
console.log(call.id);
```
Expand Down Expand Up @@ -405,7 +403,7 @@ client.calling.end("<YOUR_CALL_ID>")
</CodeBlock>
<CodeBlock title="TypeScript — REST client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as remove-caller.mjs,
// then run: node remove-caller.mjs
import { RestClient } from "@signalwire/sdk";
Expand Down Expand Up @@ -442,7 +440,11 @@ setup and local testing.
</CodeBlock>
<CodeBlock title="TypeScript — SWML builder">
```typescript
.enter_queue({ queue_name: "dispatch", wait_time: 120, status_url: "<YOUR_STATUS_WEBHOOK_URL>" })
swml.addVerb(
"enter_queue",
{ queue_name: "dispatch", wait_time: 120, status_url: "<YOUR_STATUS_WEBHOOK_URL>" },
{ skipValidation: true },
);
```
</CodeBlock>
<CodeBlock title="YAML">
Expand Down Expand Up @@ -564,7 +566,7 @@ client.run()
</CodeBlock>
<CodeBlock title="TypeScript — Relay client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// Save as dispatch-queue-relay.mts and run: npx tsx dispatch-queue-relay.mts
import { RelayClient, QueueEvent } from "@signalwire/sdk";

Expand Down Expand Up @@ -683,7 +685,7 @@ asyncio.run(main())
</CodeBlock>
<CodeBlock title="TypeScript — Relay client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// Save as call-agent-relay.mts and run: npx tsx call-agent-relay.mts
import { RelayClient, ConnectEvent } from "@signalwire/sdk";

Expand Down Expand Up @@ -805,7 +807,7 @@ for queue in client.queues.list()["data"]:
</CodeBlock>
<CodeBlock title="TypeScript — REST client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as list-queues.mjs,
// then run: node list-queues.mjs
import { RestClient } from "@signalwire/sdk";
Expand All @@ -817,7 +819,7 @@ const client = new RestClient({
});

const queues = await client.queues.list();
for (const queue of queues.data) {
for (const queue of queues.data ?? []) {
console.log(
`${queue.friendly_name} (${queue.id}): ${queue.current_size} waiting, ` +
`average wait ${queue.average_wait_time} s`,
Expand Down Expand Up @@ -878,7 +880,7 @@ for member in sorted(members, key=lambda m: m["position"]):
</CodeBlock>
<CodeBlock title="TypeScript — REST client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as list-waiting.mjs,
// then run: node list-waiting.mjs
import { RestClient } from "@signalwire/sdk";
Expand All @@ -893,7 +895,7 @@ const members = [];
let params = {};
while (true) {
const page = await client.queues.listMembers("<YOUR_QUEUE_ID>", params);
members.push(...page.data);
members.push(...(page.data ?? []));
const nextUrl = page.links?.next;
if (!nextUrl) break;
params = Object.fromEntries(new URLSearchParams(nextUrl.split("?")[1]));
Expand Down Expand Up @@ -943,7 +945,7 @@ print(queue["friendly_name"])
</CodeBlock>
<CodeBlock title="TypeScript — REST client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as update-queue.mjs,
// then run: node update-queue.mjs
import { RestClient } from "@signalwire/sdk";
Expand Down
32 changes: 18 additions & 14 deletions fern/products/platform/pages/calling/voice/call-streaming.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ uvicorn.run(app, host="0.0.0.0", port=8080)
</CodeBlock>
<CodeBlock title="JavaScript — SWML builder">
```javascript
// Install: npm install @signalwire/sdk@2.0.5 @hono/node-server ws
// Install: npm install @signalwire/sdk@3.7.1 @hono/node-server ws
// Save as stream-app.mjs and run: node stream-app.mjs
import { serve } from "@hono/node-server";
import { SWMLService } from "@signalwire/sdk";
Expand All @@ -369,7 +369,8 @@ const service = new SWMLService({
basicAuth: ["signalwire", "<YOUR_BASIC_AUTH_PASSWORD>"],
});
const swml = service.getBuilder();
swml.addVerb("stream", { url: "<YOUR_AUDIO_STREAM_URL>" });
// The SDK's SWML schema has no stream verb, so skip validation for that verb only.
swml.addVerb("stream", { url: "<YOUR_AUDIO_STREAM_URL>" }, { skipValidation: true });
swml.say("Your call is being streamed. Say a few words.").sleep(20000).say("Goodbye.");

// SignalWire fetches the call's SWML from the server's root URL.
Expand Down Expand Up @@ -493,10 +494,14 @@ swml = SWMLBuilder(service)

```javascript title="JavaScript — SWML builder"
const swml = service.getBuilder();
swml
.say("You are connected to the echo server. Speak, and you will hear yourself.")
.connect({ to: "stream:<YOUR_AUDIO_STREAM_URL>", codec: "PCMU", realtime: true, name: "echo" })
.hangup();
swml.say("You are connected to the echo server. Speak, and you will hear yourself.");
// The SDK's SWML schema lacks connect's stream settings, so skip validation for this verb only.
swml.addVerb(
"connect",
{ to: "stream:<YOUR_AUDIO_STREAM_URL>", codec: "PCMU", realtime: true, name: "echo" },
{ skipValidation: true },
);
swml.hangup();
```

```yaml title="YAML"
Expand Down Expand Up @@ -560,9 +565,9 @@ swml.say("The stream has stopped. Goodbye.")
```

```javascript title="JavaScript — SWML builder" {1,3}
swml.addVerb("stream", { url: "<YOUR_AUDIO_STREAM_URL>", control_id: "my-stream" });
swml.addVerb("stream", { url: "<YOUR_AUDIO_STREAM_URL>", control_id: "my-stream" }, { skipValidation: true });
swml.say("Your call is being streamed. Say a few words.").sleep(20000);
swml.addVerb("stop_stream", { control_id: "my-stream" });
swml.addVerb("stop_stream", { control_id: "my-stream" }, { skipValidation: true });
swml.say("The stream has stopped. Goodbye.");
```

Expand Down Expand Up @@ -703,7 +708,7 @@ asyncio.run(main())
</CodeBlock>
<CodeBlock title="TypeScript — Relay client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as stream-call-relay.mjs,
// then run: node stream-call-relay.mjs
import { RelayClient } from "@signalwire/sdk";
Expand Down Expand Up @@ -822,7 +827,7 @@ asyncio.run(main())
</CodeBlock>
<CodeBlock title="TypeScript — Relay client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as echo-call-relay.mjs,
// then run: node echo-call-relay.mjs
import { RelayClient } from "@signalwire/sdk";
Expand Down Expand Up @@ -983,7 +988,7 @@ print("Stream stopped")
</CodeBlock>
<CodeBlock title="TypeScript — REST client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as stream-rest.mjs,
// then run: node stream-rest.mjs
import { RestClient } from "@signalwire/sdk";
Expand All @@ -994,12 +999,11 @@ const client = new RestClient({
host: "<YOUR_SPACE>.signalwire.com",
});

await client.calling.stream("<YOUR_CALL_ID>", {
url: "<YOUR_AUDIO_STREAM_URL>",
await client.calling.stream("<YOUR_CALL_ID>", "<YOUR_AUDIO_STREAM_URL>", {
control_id: "rest-stream",
});
await new Promise((resolve) => setTimeout(resolve, 10_000));
await client.calling.streamStop("<YOUR_CALL_ID>", { control_id: "rest-stream" });
await client.calling.streamStop("<YOUR_CALL_ID>", "rest-stream");
console.log("Stream stopped");
```
</CodeBlock>
Expand Down
19 changes: 10 additions & 9 deletions fern/products/platform/pages/calling/voice/forward-calls.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ service.serve()
</CodeBlock>
<CodeBlock title="TypeScript — SWML builder">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as forward-calls.mjs,
// then run: node forward-calls.mjs
import { SWMLService } from "@signalwire/sdk";
Expand Down Expand Up @@ -311,9 +311,8 @@ client.run()
</CodeBlock>
<CodeBlock title="TypeScript — Relay client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// This sample also runs as JavaScript: save as forward-relay.mjs,
// then run: node forward-relay.mjs
// Install: npm install @signalwire/sdk@3.7.1
// Save as forward-relay.mts and run: npx tsx forward-relay.mts
import { RelayClient } from "@signalwire/sdk";

const client = new RelayClient({
Expand All @@ -323,7 +322,9 @@ const client = new RelayClient({
});

client.onCall(async (call) => {
const caller = call.device.params?.from_number;
// An inbound phone call's device carries the caller's number in params.from_number.
const { params } = call.device as { params?: { from_number?: string } };
const caller = params?.from_number;

call.on("calling.call.connect", async (event) => {
const state = event.params.connect_state;
Expand All @@ -350,7 +351,7 @@ client.onCall(async (call) => {
timeout: 20,
},
}]],
{ ringback: [{ type: "ringtone", name: "us" }] },
{ ringback: [{ type: "ringtone", params: { name: "us" } }] },
);
await call.waitForEnded();
});
Expand Down Expand Up @@ -441,7 +442,7 @@ print("Forwarding")
</CodeBlock>
<CodeBlock title="TypeScript — REST client">
```typescript
// Install: npm install @signalwire/sdk@2.0.5
// Install: npm install @signalwire/sdk@3.7.1
// This sample also runs as JavaScript: save as forward-rest.mjs,
// then run: node forward-rest.mjs
import { RestClient, SwmlBuilder } from "@signalwire/sdk";
Expand All @@ -455,8 +456,8 @@ const client = new RestClient({
const swml = new SwmlBuilder()
.connect({ to: "<YOUR_DESTINATION>", from: "${call.from}", timeout: 20 })
.say("Sorry, nobody at Bayview Taxi can take your call right now. Please call back later.")
.build();
await client.calling.transfer("<YOUR_CALL_ID>", { dest: swml });
.render(); // JSON text; parse it to pass the document object to transfer()
await client.calling.transfer("<YOUR_CALL_ID>", JSON.parse(swml));
console.log("Forwarding");
```
</CodeBlock>
Expand Down
Loading
Loading