From d8d44831c9267636ba0fb3eb57dcf9fbc26dbe2b Mon Sep 17 00:00:00 2001 From: DX-Bandwidth Date: Tue, 21 Jul 2026 14:44:11 +0000 Subject: [PATCH 1/2] Generate SDK with OpenAPI Generator Version --- bandwidth.yml | 40 +++++++++++++++++++++++++ bandwidth/models/answer_callback.py | 6 ++-- bandwidth/models/disconnect_callback.py | 10 +++++-- bandwidth/models/initiate_callback.py | 8 +++-- docs/AnswerCallback.md | 1 + docs/DisconnectCallback.md | 2 ++ docs/InitiateCallback.md | 2 ++ 7 files changed, 62 insertions(+), 7 deletions(-) diff --git a/bandwidth.yml b/bandwidth.yml index 52ceffd4..305a40b7 100644 --- a/bandwidth.yml +++ b/bandwidth.yml @@ -4568,6 +4568,8 @@ components: $ref: '#/components/schemas/tag1' machineDetectionResult: $ref: '#/components/schemas/machineDetectionResult' + sipCallId: + $ref: '#/components/schemas/sipCallId' bridgeCompleteCallback: type: object description: >- @@ -4832,6 +4834,10 @@ components: $ref: '#/components/schemas/errorId' tag: $ref: '#/components/schemas/tag1' + sipCallId: + $ref: '#/components/schemas/sipCallId' + sipResponseCode: + $ref: '#/components/schemas/sipResponseCode' dtmfCallback: type: object description: >- @@ -4948,6 +4954,10 @@ components: $ref: '#/components/schemas/stirShaken' uui: $ref: '#/components/schemas/uui' + sipCallId: + $ref: '#/components/schemas/sipCallId' + sipHeaders: + $ref: '#/components/schemas/sipHeaders' machineDetectionCompleteCallback: type: object description: >- @@ -5595,6 +5605,36 @@ components: value, including the encoding specifier, may not exceed 256 characters. example: bXktdXVp maxLength: 256 + sipCallId: + type: string + description: >- + (optional) The SIP Call-ID of the call's current SIP dialog with + Bandwidth's SBC. Used to correlate dialogs and trace calls. Present on + any call, inbound or outbound, once that dialog has been established; + may be absent very early in a call before the dialog exists. + example: c95ac8d6e1a31c52eb38f419893c151633ec68f8d@sbc.bandwidth.com + sipHeaders: + type: object + additionalProperties: + type: string + description: >- + (optional) Map of customer-supplied X-* headers from the original + INVITE. Keys are lowercase (SIP headers are case-insensitive). Present + only for inbound SIP URI calls with custom headers. Note - keys preserve + the original SIP header name in lowercase rather than Bandwidth's usual + camelCase JSON convention, since these are passthrough values from the + caller's SIP INVITE, not Bandwidth-defined fields. If the same header + name is sent more than once in the INVITE, only the last value is kept. + example: + x-custom-header: customer-value + x-session-id: sess-12345 + sipResponseCode: + type: integer + description: >- + (optional) The SIP status code returned by Bandwidth's SBC when it + rejected an outbound call's INVITE (e.g. 486 for busy, 603 for decline). + Present only when an outbound call was rejected by the SBC. + example: 486 codeRequest: type: object properties: diff --git a/bandwidth/models/answer_callback.py b/bandwidth/models/answer_callback.py index 77a2cff2..892929c0 100644 --- a/bandwidth/models/answer_callback.py +++ b/bandwidth/models/answer_callback.py @@ -44,8 +44,9 @@ class AnswerCallback(BaseModel): answer_time: Optional[datetime] = Field(default=None, description="Time the call was answered, in ISO 8601 format.", alias="answerTime") tag: Optional[StrictStr] = Field(default=None, description="(optional) The tag specified on call creation. If no tag was specified or it was previously cleared, this field will not be present.") machine_detection_result: Optional[MachineDetectionResult] = Field(default=None, alias="machineDetectionResult") + sip_call_id: Optional[StrictStr] = Field(default=None, description="(optional) The SIP Call-ID of the call's current SIP dialog with Bandwidth's SBC. Used to correlate dialogs and trace calls. Present on any call, inbound or outbound, once that dialog has been established; may be absent very early in a call before the dialog exists.", alias="sipCallId") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["eventType", "eventTime", "accountId", "applicationId", "from", "to", "direction", "callId", "callUrl", "enqueuedTime", "startTime", "answerTime", "tag", "machineDetectionResult"] + __properties: ClassVar[List[str]] = ["eventType", "eventTime", "accountId", "applicationId", "from", "to", "direction", "callId", "callUrl", "enqueuedTime", "startTime", "answerTime", "tag", "machineDetectionResult", "sipCallId"] model_config = ConfigDict( populate_by_name=True, @@ -141,7 +142,8 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "startTime": obj.get("startTime"), "answerTime": obj.get("answerTime"), "tag": obj.get("tag"), - "machineDetectionResult": MachineDetectionResult.from_dict(obj["machineDetectionResult"]) if obj.get("machineDetectionResult") is not None else None + "machineDetectionResult": MachineDetectionResult.from_dict(obj["machineDetectionResult"]) if obj.get("machineDetectionResult") is not None else None, + "sipCallId": obj.get("sipCallId") }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/bandwidth/models/disconnect_callback.py b/bandwidth/models/disconnect_callback.py index 1a2103ce..8a7778e6 100644 --- a/bandwidth/models/disconnect_callback.py +++ b/bandwidth/models/disconnect_callback.py @@ -19,7 +19,7 @@ import json from datetime import datetime -from pydantic import BaseModel, ConfigDict, Field, StrictStr +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional from bandwidth.models.call_direction_enum import CallDirectionEnum from typing import Optional, Set @@ -46,8 +46,10 @@ class DisconnectCallback(BaseModel): error_message: Optional[StrictStr] = Field(default=None, description="Text explaining the reason that caused the call to fail in case of errors.", alias="errorMessage") error_id: Optional[StrictStr] = Field(default=None, description="Bandwidth's internal id that references the error event.", alias="errorId") tag: Optional[StrictStr] = Field(default=None, description="(optional) The tag specified on call creation. If no tag was specified or it was previously cleared, this field will not be present.") + sip_call_id: Optional[StrictStr] = Field(default=None, description="(optional) The SIP Call-ID of the call's current SIP dialog with Bandwidth's SBC. Used to correlate dialogs and trace calls. Present on any call, inbound or outbound, once that dialog has been established; may be absent very early in a call before the dialog exists.", alias="sipCallId") + sip_response_code: Optional[StrictInt] = Field(default=None, description="(optional) The SIP status code returned by Bandwidth's SBC when it rejected an outbound call's INVITE (e.g. 486 for busy, 603 for decline). Present only when an outbound call was rejected by the SBC.", alias="sipResponseCode") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["eventType", "eventTime", "accountId", "applicationId", "from", "to", "callId", "direction", "callUrl", "enqueuedTime", "startTime", "answerTime", "endTime", "cause", "errorMessage", "errorId", "tag"] + __properties: ClassVar[List[str]] = ["eventType", "eventTime", "accountId", "applicationId", "from", "to", "callId", "direction", "callUrl", "enqueuedTime", "startTime", "answerTime", "endTime", "cause", "errorMessage", "errorId", "tag", "sipCallId", "sipResponseCode"] model_config = ConfigDict( populate_by_name=True, @@ -148,7 +150,9 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "cause": obj.get("cause"), "errorMessage": obj.get("errorMessage"), "errorId": obj.get("errorId"), - "tag": obj.get("tag") + "tag": obj.get("tag"), + "sipCallId": obj.get("sipCallId"), + "sipResponseCode": obj.get("sipResponseCode") }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/bandwidth/models/initiate_callback.py b/bandwidth/models/initiate_callback.py index 1feae7b5..eed596e4 100644 --- a/bandwidth/models/initiate_callback.py +++ b/bandwidth/models/initiate_callback.py @@ -45,8 +45,10 @@ class InitiateCallback(BaseModel): diversion: Optional[Diversion] = None stir_shaken: Optional[StirShaken] = Field(default=None, alias="stirShaken") uui: Optional[Annotated[str, Field(strict=True, max_length=256)]] = Field(default=None, description="The value of the `User-To-User` header to send within the initial `INVITE`. Must include the encoding parameter as specified in RFC 7433. Only `base64`, `jwt` and `hex` encoding are currently allowed. This value, including the encoding specifier, may not exceed 256 characters.") + sip_call_id: Optional[StrictStr] = Field(default=None, description="(optional) The SIP Call-ID of the call's current SIP dialog with Bandwidth's SBC. Used to correlate dialogs and trace calls. Present on any call, inbound or outbound, once that dialog has been established; may be absent very early in a call before the dialog exists.", alias="sipCallId") + sip_headers: Optional[Dict[str, StrictStr]] = Field(default=None, description="(optional) Map of customer-supplied X-* headers from the original INVITE. Keys are lowercase (SIP headers are case-insensitive). Present only for inbound SIP URI calls with custom headers. Note - keys preserve the original SIP header name in lowercase rather than Bandwidth's usual camelCase JSON convention, since these are passthrough values from the caller's SIP INVITE, not Bandwidth-defined fields. If the same header name is sent more than once in the INVITE, only the last value is kept.", alias="sipHeaders") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["eventType", "eventTime", "accountId", "applicationId", "from", "to", "direction", "callId", "callUrl", "startTime", "diversion", "stirShaken", "uui"] + __properties: ClassVar[List[str]] = ["eventType", "eventTime", "accountId", "applicationId", "from", "to", "direction", "callId", "callUrl", "startTime", "diversion", "stirShaken", "uui", "sipCallId", "sipHeaders"] model_config = ConfigDict( populate_by_name=True, @@ -124,7 +126,9 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "startTime": obj.get("startTime"), "diversion": Diversion.from_dict(obj["diversion"]) if obj.get("diversion") is not None else None, "stirShaken": StirShaken.from_dict(obj["stirShaken"]) if obj.get("stirShaken") is not None else None, - "uui": obj.get("uui") + "uui": obj.get("uui"), + "sipCallId": obj.get("sipCallId"), + "sipHeaders": obj.get("sipHeaders") }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/docs/AnswerCallback.md b/docs/AnswerCallback.md index 7b872670..4d28c160 100644 --- a/docs/AnswerCallback.md +++ b/docs/AnswerCallback.md @@ -20,6 +20,7 @@ Name | Type | Description | Notes **answer_time** | **datetime** | Time the call was answered, in ISO 8601 format. | [optional] **tag** | **str** | (optional) The tag specified on call creation. If no tag was specified or it was previously cleared, this field will not be present. | [optional] **machine_detection_result** | [**MachineDetectionResult**](MachineDetectionResult.md) | | [optional] +**sip_call_id** | **str** | (optional) The SIP Call-ID of the call's current SIP dialog with Bandwidth's SBC. Used to correlate dialogs and trace calls. Present on any call, inbound or outbound, once that dialog has been established; may be absent very early in a call before the dialog exists. | [optional] ## Example diff --git a/docs/DisconnectCallback.md b/docs/DisconnectCallback.md index 433c6dda..658fed07 100644 --- a/docs/DisconnectCallback.md +++ b/docs/DisconnectCallback.md @@ -23,6 +23,8 @@ Name | Type | Description | Notes **error_message** | **str** | Text explaining the reason that caused the call to fail in case of errors. | [optional] **error_id** | **str** | Bandwidth's internal id that references the error event. | [optional] **tag** | **str** | (optional) The tag specified on call creation. If no tag was specified or it was previously cleared, this field will not be present. | [optional] +**sip_call_id** | **str** | (optional) The SIP Call-ID of the call's current SIP dialog with Bandwidth's SBC. Used to correlate dialogs and trace calls. Present on any call, inbound or outbound, once that dialog has been established; may be absent very early in a call before the dialog exists. | [optional] +**sip_response_code** | **int** | (optional) The SIP status code returned by Bandwidth's SBC when it rejected an outbound call's INVITE (e.g. 486 for busy, 603 for decline). Present only when an outbound call was rejected by the SBC. | [optional] ## Example diff --git a/docs/InitiateCallback.md b/docs/InitiateCallback.md index 89e65331..ff6aa724 100644 --- a/docs/InitiateCallback.md +++ b/docs/InitiateCallback.md @@ -19,6 +19,8 @@ Name | Type | Description | Notes **diversion** | [**Diversion**](Diversion.md) | | [optional] **stir_shaken** | [**StirShaken**](StirShaken.md) | | [optional] **uui** | **str** | The value of the `User-To-User` header to send within the initial `INVITE`. Must include the encoding parameter as specified in RFC 7433. Only `base64`, `jwt` and `hex` encoding are currently allowed. This value, including the encoding specifier, may not exceed 256 characters. | [optional] +**sip_call_id** | **str** | (optional) The SIP Call-ID of the call's current SIP dialog with Bandwidth's SBC. Used to correlate dialogs and trace calls. Present on any call, inbound or outbound, once that dialog has been established; may be absent very early in a call before the dialog exists. | [optional] +**sip_headers** | **Dict[str, str]** | (optional) Map of customer-supplied X-* headers from the original INVITE. Keys are lowercase (SIP headers are case-insensitive). Present only for inbound SIP URI calls with custom headers. Note - keys preserve the original SIP header name in lowercase rather than Bandwidth's usual camelCase JSON convention, since these are passthrough values from the caller's SIP INVITE, not Bandwidth-defined fields. If the same header name is sent more than once in the INVITE, only the last value is kept. | [optional] ## Example From 6859198805ad137e016411d4088e56ddf931ad1d Mon Sep 17 00:00:00 2001 From: ckoegel Date: Wed, 22 Jul 2026 14:47:08 -0400 Subject: [PATCH 2/2] unit tests --- test/unit/models/test_answer_callback.py | 4 +++- test/unit/models/test_disconnect_callback.py | 6 +++++- test/unit/models/test_initiate_callback.py | 10 +++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/test/unit/models/test_answer_callback.py b/test/unit/models/test_answer_callback.py index 0688bbd8..ccf03021 100644 --- a/test/unit/models/test_answer_callback.py +++ b/test/unit/models/test_answer_callback.py @@ -50,7 +50,8 @@ def make_instance(self, include_optional) -> AnswerCallback: tag = 'exampleTag', machine_detection_result = MachineDetectionResult( value = 'answering-machine', - duration = 'PT4.9891287S', ) + duration = 'PT4.9891287S', ), + sip_call_id = 'sipCallIdExample' ) else: return AnswerCallback( @@ -77,6 +78,7 @@ def testAnswerCallback(self): assert isinstance(instance.machine_detection_result, MachineDetectionResult) assert instance.machine_detection_result.value == 'answering-machine' assert instance.machine_detection_result.duration == 'PT4.9891287S' + assert instance.sip_call_id == 'sipCallIdExample' if __name__ == '__main__': diff --git a/test/unit/models/test_disconnect_callback.py b/test/unit/models/test_disconnect_callback.py index 91e2c36d..23184234 100644 --- a/test/unit/models/test_disconnect_callback.py +++ b/test/unit/models/test_disconnect_callback.py @@ -50,7 +50,9 @@ def make_instance(self, include_optional) -> DisconnectCallback: cause = 'busy', error_message = 'Call c-2a913f94-6a486f3a-3cae-4034-bcc3-f0c9fa77ca2f is already bridged with another call', error_id = '4642074b-7b58-478b-96e4-3a60955c6765', - tag = 'exampleTag' + tag = 'exampleTag', + sip_call_id = 'sipCallIdExample', + sip_response_code = 200 ) else: return DisconnectCallback( @@ -78,6 +80,8 @@ def testDisconnectCallback(self): assert instance.error_message == 'Call c-2a913f94-6a486f3a-3cae-4034-bcc3-f0c9fa77ca2f is already bridged with another call' assert instance.error_id == '4642074b-7b58-478b-96e4-3a60955c6765' assert instance.tag == 'exampleTag' + assert instance.sip_call_id == 'sipCallIdExample' + assert instance.sip_response_code == 200 if __name__ == '__main__': unittest.main() diff --git a/test/unit/models/test_initiate_callback.py b/test/unit/models/test_initiate_callback.py index fef2b93d..7471ffaf 100644 --- a/test/unit/models/test_initiate_callback.py +++ b/test/unit/models/test_initiate_callback.py @@ -58,7 +58,11 @@ def make_instance(self, include_optional) -> InitiateCallback: verstat = 'Tn-Verification-Passed', attestation_indicator = 'A', originating_id = '99759086-1335-11ed-9bcf-5f7d464e91af', ), - uui='bXktdXVp' + uui='bXktdXVp', + sip_call_id = 'sipCallIdExample', + sip_headers = { + 'X-Example-Header': 'ExampleValue' + } ) else: return InitiateCallback( @@ -92,6 +96,10 @@ def testInitiateCallback(self): assert instance.stir_shaken.attestation_indicator == 'A' assert instance.stir_shaken.originating_id == '99759086-1335-11ed-9bcf-5f7d464e91af' assert instance.uui == 'bXktdXVp' + assert instance.sip_call_id == 'sipCallIdExample' + assert instance.sip_headers == { + 'X-Example-Header': 'ExampleValue' + } if __name__ == '__main__': unittest.main()