-
Notifications
You must be signed in to change notification settings - Fork 2
VAPI-3163 Add <Refer> BXML verb support #190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # Bandwidth.Standard.Model.Bxml.Verbs.Refer | ||
|
|
||
| The `<Refer>` verb is used to hand off a call to a SIP endpoint via a SIP REFER. The call is transferred to the specified SIP URI, and an optional callback is sent when the transfer completes. | ||
|
|
||
| For more details, see the [Bandwidth BXML Refer documentation](https://dev.bandwidth.com/docs/voice/bxml/refer.html). | ||
|
|
||
| ## Properties | ||
|
|
||
| Name | Type | Description | Notes | ||
| ------------ | ------------- | ------------- | ------------- | ||
| **ReferCompleteUrl** | **string** | URL to receive the `referComplete` callback when the REFER is finished. | [optional] | ||
| **ReferCompleteMethod** | **string** | HTTP method to use for the `referComplete` callback. Must be `GET` or `POST`. | [optional] [default to `POST`] | ||
| **Tag** | **string** | Optional custom string to include in callbacks. Max 4096 characters. | [optional] | ||
| **SipUriElement** | [**Refer.SipUri**](#sipuri-nested-class) | The SIP URI destination for the REFER. Must start with `sip:`. | | ||
|
|
||
| ## SipUri Nested Class | ||
|
|
||
| The `<SipUri>` element specifies the destination SIP URI for the REFER. | ||
|
|
||
| Name | Type | Description | Notes | ||
| ------------ | ------------- | ------------- | ------------- | ||
| **Uri** | **string** | The SIP URI to refer the call to. Must start with `sip:`. | | ||
|
|
||
| ## Methods | ||
|
|
||
| Name | Description | ||
| ------------ | ------------- | ||
| `WithSipUri(string sipUri)` | Sets the SIP URI destination from a string. Returns the `Refer` instance for chaining. | ||
| `WithSipUri(SipUri sipUri)` | Sets the SIP URI destination from a `SipUri` object. Returns the `Refer` instance for chaining. | ||
| `WithReferCompleteUrl(string referCompleteUrl)` | Sets the `referCompleteUrl` attribute. Returns the `Refer` instance for chaining. | ||
| `WithReferCompleteMethod(string referCompleteMethod)` | Sets the `referCompleteMethod` attribute (`GET` or `POST`). Returns the `Refer` instance for chaining. | ||
| `WithTag(string tag)` | Sets the `tag` attribute. Returns the `Refer` instance for chaining. | ||
|
|
||
| ## Validation | ||
|
|
||
| - `SipUri.Uri` must start with `sip:` (case-insensitive). An `ArgumentException` is thrown if the value does not match. | ||
| - `ReferCompleteMethod` must be either `GET` or `POST`. An `ArgumentException` is thrown for any other value. | ||
|
|
||
| [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Bandwidth.Standard.Model.ReferCompleteCallback | ||
| The Refer Complete event is fired when the <Refer> verb finishes executing. This is sent to the referCompleteUrl specified on the <Refer> verb, and the BXML returned in it is executed on the call. | ||
|
|
||
| ## Properties | ||
|
|
||
| Name | Type | Description | Notes | ||
| ------------ | ------------- | ------------- | ------------- | ||
| **EventType** | **string** | The event type, value can be one of the following: answer, bridgeComplete, bridgeTargetComplete, conferenceCreated, conferenceRedirect, conferenceMemberJoin, conferenceMemberExit, conferenceCompleted, conferenceRecordingAvailable, disconnect, dtmf, gather, initiate, machineDetectionComplete, recordingComplete, recordingAvailable, redirect, transcriptionAvailable, transferAnswer, transferComplete, transferDisconnect. | [optional] | ||
| **EventTime** | **DateTime** | The approximate UTC date and time when the event was generated by the Bandwidth server, in ISO 8601 format. This may not be exactly the time of event execution. | [optional] | ||
| **AccountId** | **string** | The user account associated with the call. | [optional] | ||
| **ApplicationId** | **string** | The id of the application associated with the call. | [optional] | ||
| **From** | **string** | The provided identifier of the caller. Must be a phone number in E.164 format (e.g. +15555555555). | [optional] | ||
| **To** | **string** | The phone number that received the call, in E.164 format (e.g. +15555555555). | [optional] | ||
| **Direction** | **CallDirectionEnum** | | [optional] | ||
| **CallId** | **string** | The call id associated with the event. | [optional] | ||
| **CallUrl** | **string** | The URL of the call associated with the event. | [optional] | ||
| **EnqueuedTime** | **DateTime?** | (optional) If call queueing is enabled and this is an outbound call, time the call was queued, in ISO 8601 format. | [optional] | ||
| **StartTime** | **DateTime** | Time the call was started, in ISO 8601 format. | [optional] | ||
| **AnswerTime** | **DateTime?** | Time the call was answered, in ISO 8601 format. | [optional] | ||
| **Tag** | **string** | (optional) The tag specified on call creation. If no tag was specified or it was previously cleared, this field will not be present. | [optional] | ||
| **SipResponseCode** | **int?** | The SIP response code from the REFER request, indicating the outcome of the operation (e.g., 200 for success, 404 for not found). | [optional] | ||
| **Cause** | **string** | Reason the call failed - hangup, busy, timeout, cancel, rejected, callback-error, invalid-bxml, application-error, account-limit, node-capacity-exceeded, error, or unknown. | [optional] | ||
| **ErrorMessage** | **string** | Text explaining the reason that caused the call to fail in case of errors. | [optional] | ||
| **ErrorId** | **string** | Bandwidth's internal id that references the error event. | [optional] | ||
|
|
||
| [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| using System; | ||
| using System.IO; | ||
| using System.Xml.Serialization; | ||
| using Bandwidth.Standard.Model.Bxml; | ||
| using Bandwidth.Standard.Model.Bxml.Verbs; | ||
| using Xunit; | ||
|
|
||
| namespace Bandwidth.Standard.Test.Unit.Model.Bxml | ||
| { | ||
| public class TestRefer | ||
| { | ||
| [Fact] | ||
| public void ReferRoundTripTest() | ||
| { | ||
| var expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Response> <Refer referCompleteUrl=\"https://example.com/handleRefer\" referCompleteMethod=\"POST\" tag=\"refer-tag\"> <SipUri>sip:alice@atlanta.example.com</SipUri> </Refer></Response>"; | ||
|
|
||
| var refer = new Refer() | ||
| .WithSipUri("sip:alice@atlanta.example.com") | ||
| .WithReferCompleteUrl("https://example.com/handleRefer") | ||
| .WithReferCompleteMethod("POST") | ||
| .WithTag("refer-tag"); | ||
|
|
||
| var actual = new Response(refer).ToBXML(); | ||
| Assert.Equal(expected, actual.Replace("\n", "").Replace("\r", "")); | ||
|
|
||
| const string referOnlyXml = "<Refer referCompleteUrl=\"https://example.com/handleRefer\" referCompleteMethod=\"POST\" tag=\"refer-tag\"><SipUri>sip:alice@atlanta.example.com</SipUri></Refer>"; | ||
| var serializer = new XmlSerializer(typeof(Refer), ""); | ||
| Refer deserializedRefer; | ||
| using (var reader = new StringReader(referOnlyXml)) | ||
| { | ||
| deserializedRefer = (Refer)serializer.Deserialize(reader); | ||
| } | ||
|
|
||
| Assert.Equal("sip:alice@atlanta.example.com", deserializedRefer.SipUriElement.Uri); | ||
| var roundTrip = new Response(deserializedRefer).ToBXML(); | ||
| Assert.Equal(expected, roundTrip.Replace("\n", "").Replace("\r", "")); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ReferSipUriMustStartWithSipScheme() | ||
| { | ||
| var refer = new Refer(); | ||
| Assert.Throws<ArgumentException>(() => refer.WithSipUri("tel:+15551234567")); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ReferInvalidMethodThrows() | ||
| { | ||
| var refer = new Refer(); | ||
| Assert.Throws<ArgumentException>(() => refer.WithReferCompleteMethod("DELETE")); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ReferWithSipUriObjectOverload() | ||
| { | ||
| var sipUri = new Refer.SipUri { Uri = "sip:alice@atlanta.example.com" }; | ||
| var refer = new Refer().WithSipUri(sipUri); | ||
| Assert.Equal("sip:alice@atlanta.example.com", refer.SipUriElement.Uri); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ReferMinimalOnlySipUri() | ||
| { | ||
| var refer = new Refer().WithSipUri("sip:bob@biloxi.example.com"); | ||
| var bxml = new Response(refer).ToBXML(); | ||
| Assert.Contains("sip:bob@biloxi.example.com", bxml); | ||
| Assert.Contains("referCompleteMethod=\"POST\"", bxml); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [MINOR] No test for missing (required)
Also missing: a test for the |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[MINOR]
tagmax-length mismatch: this doc says 4096, spec says 256The published BXML reference states the
tagattribute max is 256 characters. Please align before merge.