Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ docs/RecordingTranscriptions.md
docs/RecordingsApi.md
docs/RedirectCallback.md
docs/RedirectMethodEnum.md
docs/ReferCompleteCallback.md
docs/SipConnectionMetadata.md
docs/SipCredentials.md
docs/SmsMessageContent.md
Expand Down Expand Up @@ -403,6 +404,7 @@ src/Bandwidth.Standard/Model/RecordingTranscriptionMetadata.cs
src/Bandwidth.Standard/Model/RecordingTranscriptions.cs
src/Bandwidth.Standard/Model/RedirectCallback.cs
src/Bandwidth.Standard/Model/RedirectMethodEnum.cs
src/Bandwidth.Standard/Model/ReferCompleteCallback.cs
src/Bandwidth.Standard/Model/SipConnectionMetadata.cs
src/Bandwidth.Standard/Model/SipCredentials.cs
src/Bandwidth.Standard/Model/SmsMessageContent.cs
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,6 @@ namespace Example
}
}
}
```

<a id="documentation-for-api-endpoints"></a>
## Documentation for API Endpoints

Expand Down Expand Up @@ -330,6 +328,7 @@ Class | Method | HTTP request | Description
- [Model.RecordingTranscriptions](docs/RecordingTranscriptions.md)
- [Model.RedirectCallback](docs/RedirectCallback.md)
- [Model.RedirectMethodEnum](docs/RedirectMethodEnum.md)
- [Model.ReferCompleteCallback](docs/ReferCompleteCallback.md)
- [Model.SipConnectionMetadata](docs/SipConnectionMetadata.md)
- [Model.SipCredentials](docs/SipCredentials.md)
- [Model.SmsMessageContent](docs/SmsMessageContent.md)
Expand Down Expand Up @@ -374,6 +373,11 @@ Class | Method | HTTP request | Description
- [Model.WebhookSubscriptionsListBody](docs/WebhookSubscriptionsListBody.md)


<a id="documentation-for-bxml-verbs"></a>
## Documentation for BXML Verbs

- [Bxml.Verbs.Refer](docs/Refer.md)

<a id="documentation-for-authorization"></a>
## Documentation for Authorization

Expand Down
105 changes: 105 additions & 0 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13407,6 +13407,105 @@ components:
example: "+15555555555"
type: string
type: object
referCompleteCallback:
description: "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:
eventType:
description: "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."
example: bridgeComplete
type: string
eventTime:
description: "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."
example: 2022-06-17T22:19:40.375Z
format: date-time
type: string
accountId:
description: The user account associated with the call.
example: "9900000"
type: string
applicationId:
description: The id of the application associated with the call.
example: 04e88489-df02-4e34-a0ee-27a91849555f
type: string
from:
description: The provided identifier of the caller. Must be a phone number
in E.164 format (e.g. +15555555555).
example: "+15555555555"
type: string
to:
description: "The phone number that received the call, in E.164 format (e.g.\
\ +15555555555)."
example: "+15555555555"
type: string
direction:
$ref: '#/components/schemas/callDirectionEnum'
callId:
description: The call id associated with the event.
example: c-15ac29a2-1331029c-2cb0-4a07-b215-b22865662d85
type: string
callUrl:
description: The URL of the call associated with the event.
example: https://voice.bandwidth.com/api/v2/accounts/9900000/calls/c-15ac29a2-1331029c-2cb0-4a07-b215-b22865662d85
format: uri
type: string
enqueuedTime:
description: "(optional) If call queueing is enabled and this is an outbound\
\ call, time the call was queued, in ISO 8601 format."
example: 2022-06-17T22:20:00Z
format: date-time
nullable: true
type: string
startTime:
description: "Time the call was started, in ISO 8601 format."
example: 2022-06-17T22:19:40.375Z
format: date-time
type: string
answerTime:
description: "Time the call was answered, in ISO 8601 format."
example: 2022-06-17T22:20:00Z
format: date-time
nullable: true
type: string
tag:
description: "(optional) The tag specified on call creation. If no tag was\
\ specified or it was previously cleared, this field will not be present."
example: exampleTag
nullable: true
type: string
sipResponseCode:
description: "The SIP response code from the REFER request, indicating the\
\ outcome of the operation (e.g., 200 for success, 404 for not found)."
example: 200
nullable: true
type: integer
cause:
description: "Reason the call failed - hangup, busy, timeout, cancel, rejected,\
\ callback-error, invalid-bxml, application-error, account-limit, node-capacity-exceeded,\
\ error, or unknown."
example: busy
type: string
errorMessage:
description: Text explaining the reason that caused the call to fail in
case of errors.
example: Call c-2a913f94-6a486f3a-3cae-4034-bcc3-f0c9fa77ca2f is already
bridged with another call
nullable: true
type: string
errorId:
description: Bandwidth's internal id that references the error event.
example: 4642074b-7b58-478b-96e4-3a60955c6765
nullable: true
type: string
type: object
transcriptionAvailableCallback:
description: The Transcription Available event is sent when the recording transcription
is available to be downloaded.
Expand Down Expand Up @@ -13990,6 +14089,12 @@ components:
example: 4642074b-7b58-478b-96e4-3a60955c6765
nullable: true
type: string
sipResponseCode:
description: "The SIP response code from the REFER request, indicating the outcome\
\ of the operation (e.g., 200 for success, 404 for not found)."
example: 200
nullable: true
type: integer
machineDetectionResult:
description: "(optional) if machine detection was requested in sync mode, the\
\ result will be specified here. Possible values are the same as the async\
Expand Down
48 changes: 48 additions & 0 deletions bandwidth.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5047,6 +5047,47 @@ components:
$ref: '#/components/schemas/transferCallerId'
transferTo:
$ref: '#/components/schemas/transferTo'
referCompleteCallback:
type: object
description: >-
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:
eventType:
$ref: '#/components/schemas/eventType'
eventTime:
$ref: '#/components/schemas/eventTime'
accountId:
$ref: '#/components/schemas/accountId'
applicationId:
$ref: '#/components/schemas/applicationId1'
from:
$ref: '#/components/schemas/from'
to:
$ref: '#/components/schemas/to'
direction:
$ref: '#/components/schemas/callDirectionEnum'
callId:
$ref: '#/components/schemas/callId'
callUrl:
$ref: '#/components/schemas/callUrl'
enqueuedTime:
$ref: '#/components/schemas/enqueuedTime'
startTime:
$ref: '#/components/schemas/startTime'
answerTime:
$ref: '#/components/schemas/answerTime'
tag:
$ref: '#/components/schemas/tag1'
sipResponseCode:
$ref: '#/components/schemas/sipResponseCode'
cause:
$ref: '#/components/schemas/cause'
errorMessage:
$ref: '#/components/schemas/errorMessage'
errorId:
$ref: '#/components/schemas/errorId'
transcriptionAvailableCallback:
type: object
description: >-
Expand Down Expand Up @@ -5413,6 +5454,13 @@ components:
description: Bandwidth's internal id that references the error event.
example: 4642074b-7b58-478b-96e4-3a60955c6765
nullable: true
sipResponseCode:
type: integer
description: >-
The SIP response code from the REFER request, indicating the outcome
of the operation (e.g., 200 for success, 404 for not found).
example: 200
nullable: true
machineDetectionResult:
type: object
description: >-
Expand Down
40 changes: 40 additions & 0 deletions docs/Refer.md
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]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MINOR] tag max-length mismatch: this doc says 4096, spec says 256

The published BXML reference states the tag attribute max is 256 characters. Please align before merge.

**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)

27 changes: 27 additions & 0 deletions docs/ReferCompleteCallback.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&#39;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)

70 changes: 70 additions & 0 deletions src/Bandwidth.Standard.Test/Unit/Model/Bxml/TestRefer.cs
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);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MINOR] No test for missing (required) <SipUri> enforcement

<SipUri> is required per spec. What does new Response(new Refer()).ToBXML() produce today — invalid XML, silent omission, or an exception? Consider adding a test (and enforcement in ToBXML() or a guard in WithSipUri) to surface the constraint clearly.

Also missing: a test for the WithSipUri(SipUri) object-overload confirming sip: validation fires via that path.

}
}
Loading
Loading