Skip to content
Merged
51 changes: 33 additions & 18 deletions specs/signalwire-rest/calling-api/calls/main.tsp
Original file line number Diff line number Diff line change
@@ -1,31 +1,46 @@
import "@typespec/http";
import "@typespec/openapi";
import "../../types";
import "./models/requests.tsp";
import "./models/responses.tsp";
import "./models/examples.tsp";

using TypeSpec.Http;
using TypeSpec.OpenAPI;
using Types.StatusCodes;

@route("/calls")
namespace CallingAPI.Calls {
@tag("Calls")
@friendlyName("Calls")
interface Calls {
@summary("Create a Call")
@doc("To create a new call, you send a `POST` request to the Call resource with a payload including a `dial` command and additional nested `params`.")
create(@body request: CallCreateRequest):
| {
@statusCode statusCode: 201;
@body call: CallResponse;
}
| StatusCode401
| StatusCode404
| CallCreate422Error
| StatusCode500;

@summary("Update a Call")
@doc("To update an existing call, you send a `PUT` request to the Call resource with a payload including a `command` and additional nested `params`.")
@summary("Send Call Commands")
@doc("""
Unified OpenRPC-style endpoint for executing call methods through command-based dispatch.
Send a request with the appropriate `command` field to invoke the desired call operation.
This endpoint provides a single interface for all call-related methods including creation, updates, termination, and AI conversation control.
""")
@opExample(
#{ parameters: dialCallExample },
#{
title: "Create new call",
description: "Initiate a new outbound call with the dial command",
}
)
@opExample(
#{ parameters: updateCallExample },
#{
title: "Update active call",
description: "Modify an existing call's parameters in real-time",
}
)
@opExample(
#{ parameters: hangupCallExample },
#{
title: "End call",
description: "Terminate an active call immediately",
}
)
@opExample(
#{ parameters: holdCallExample },
#{
Expand All @@ -47,16 +62,16 @@ namespace CallingAPI.Calls {
description: "Send a message to the AI conversation to modify behavior or add context",
}
)
//@opExample(#{parameters: #{request: #{command: "update", params: #{id: "3fa85f64-5717-4562-b3fc-2c963f66afa6", url: "https://example.com/swml", fallback_url: "https://example.com/fallback"}}}}, #{title: "Update active call", description: "Modify an active call's behavior using new SWML instructions"})
@put
update(@body request: CallUpdateRequest):
@post
@operationId("call-commands")
callCommand(@body request: CallRequest):
| {
@statusCode statusCode: 200;
@body call: CallResponse;
}
| StatusCode401
| StatusCode404
| CallUpdate422Error
| CallCreate422Error
| StatusCode500;
}
}
54 changes: 38 additions & 16 deletions specs/signalwire-rest/calling-api/calls/models/examples.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,63 @@
*/
const callId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";

// Hangup Call Examples
// Call command examples
const dialCallExample = #{
request: #{
command: "dial",
params: #{
from: "+15551234567",
to: "+15559876543",
url: "https://example.com/swml",
caller_id: "+15551234567",
status_url: "https://example.com/status_callback",
status_events: #["answered", "ended"],
},
},
};

const updateCallExample = #{
request: #{
command: "update",
params: #{
id: callId,
url: "https://example.com/swml",
fallback_url: "https://example.com/fallback",
},
},
};

const hangupCallExample = #{
request: #{
id: callId,
command: "calling.end",
id: callId,
params: #{ reason: "hangup" },
},
};

const holdCallExample = #{
request: #{ id: callId, command: "calling.ai_hold", params: #{} },
request: #{
command: "calling.ai_hold",
id: callId,
params: #{},
},
};

const unholdCallExample = #{
request: #{ id: callId, command: "calling.ai_unhold", params: #{} },
request: #{
command: "calling.ai_unhold",
id: callId,
params: #{},
},
};

const aiMessageExample = #{
request: #{
id: callId,
command: "calling.ai_message",
id: callId,
params: #{
role: "system",
message_text: "You are now in expert mode. Provide detailed technical responses and use industry terminology.",
},
},
};

const updateCallExample = #{
request: #{
command: "update",
params: #{
id: callId,
url: "https://example.com/swml",
fallback_url: "https://example.com/fallback",
},
},
};
54 changes: 29 additions & 25 deletions specs/signalwire-rest/calling-api/calls/models/requests.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ const uuidDescription = "The unique identifying ID of a existing call.";

const paramsDescription = "An object of parameters that will be utilized by the active command.";

alias CallCreateRequestAlias = CallCreateParamsURL | CallCreateParamsSWML;
alias CallCreateParamsAlias = CallCreateParamsURL | CallCreateParamsSWML;

alias CallUpdateParamsAlias = CallUpdateParamsURL | CallUpdateParamsSWML;

@summary("Hangup call")
model CallHangupRequest {
Expand Down Expand Up @@ -101,7 +103,7 @@ model CallCreateRequest {
command: "dial";

@doc(paramsDescription)
params: CallCreateRequestAlias;
params: CallCreateParamsAlias;
}

model CallCreateParamsBase {
Expand Down Expand Up @@ -189,34 +191,36 @@ model CallUpdateParamsURL is CallUpdateParamsBase {
}

@summary("Update call")
@oneOf
union UpdateCurrentCallRequest {
CallUpdateSWMLRequest,
CallUpdateURLRequest,
}

union CallUpdateRequest {
UpdateCurrentCallRequest,
CallHangupRequest,
CallHoldRequest,
CallUnholdRequest,
CallAIMessageRequest,
}

model CallUpdateRequestBase {
model CallUpdateCurrentCallRequest {
@doc(updateCommandDescription)
@example("update")
command: "update";
}

@summary("Update call (SWML)")
model CallUpdateSWMLRequest is CallUpdateRequestBase {
@doc(paramsDescription)
params: CallUpdateParamsSWML;
params: CallUpdateParamsAlias;
}

@summary("Update call (URL)")
model CallUpdateURLRequest is CallUpdateRequestBase {
@doc(paramsDescription)
params: CallUpdateParamsURL;
@discriminated(#{discriminatorPropertyName: "command", envelope: "none"})
@doc("""
Call request union for OpenRPC-style method dispatch. Use the `command` field to specify which call method to invoke:

- **`dial`** - Create and initiate a new outbound call to a destination. Returns immediately with call details while the call is being established in the background.

- **`update`** - Modify an active call's properties in real-time. Update call parameters such as routing, recording settings, or other call-specific configurations.

- **`calling.end`** - Terminate an active call immediately. Disconnects all parties and ends the call session. Cannot be reversed once executed.

- **`calling.ai_hold`** - Place an AI-powered call on hold. Pauses the AI conversation and typically plays hold music or a message to the caller. The AI agent becomes inactive until unhold.

- **`calling.ai_unhold`** - Resume an AI call from hold state. Reactivates the AI agent and continues the conversation from where it was paused.

- **`calling.ai_message`** - Inject a message into an active AI conversation. Allows you to dynamically add context, instructions, or system messages to guide the AI agent's behavior during the call.
""")
union CallRequest {
dial: CallCreateRequest,
update: CallUpdateCurrentCallRequest,
`calling.end`: CallHangupRequest,
`calling.ai_hold`: CallHoldRequest,
`calling.ai_unhold`: CallUnholdRequest,
`calling.ai_message`: CallAIMessageRequest,
}
Loading