vobiz-python 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vobiz/__init__.py +4 -0
- vobiz/base.py +237 -0
- vobiz/exceptions.py +34 -0
- vobiz/resources/__init__.py +12 -0
- vobiz/resources/accounts.py +59 -0
- vobiz/resources/applications.py +138 -0
- vobiz/resources/calls_vobiz.py +206 -0
- vobiz/resources/cdrs.py +46 -0
- vobiz/resources/credentials.py +104 -0
- vobiz/resources/endpoints.py +101 -0
- vobiz/resources/ip_access_control_lists.py +100 -0
- vobiz/resources/numbers.py +134 -0
- vobiz/resources/origination_uris.py +109 -0
- vobiz/resources/recordings.py +91 -0
- vobiz/resources/sip_trunks.py +99 -0
- vobiz/resources/subaccounts.py +101 -0
- vobiz/rest/__init__.py +2 -0
- vobiz/rest/client.py +277 -0
- vobiz/utils/__init__.py +72 -0
- vobiz/utils/interactive.py +50 -0
- vobiz/utils/jwt.py +97 -0
- vobiz/utils/location.py +6 -0
- vobiz/utils/signature_v3.py +111 -0
- vobiz/utils/template.py +50 -0
- vobiz/utils/validators.py +280 -0
- vobiz/version.py +2 -0
- vobiz/xml/ConferenceElement.py +485 -0
- vobiz/xml/DTMFElement.py +41 -0
- vobiz/xml/DialElement.py +371 -0
- vobiz/xml/MultiPartyCallElement.py +711 -0
- vobiz/xml/ResponseElement.py +414 -0
- vobiz/xml/VobizXMLElement.py +48 -0
- vobiz/xml/__init__.py +31 -0
- vobiz/xml/breakElement.py +62 -0
- vobiz/xml/contElement.py +190 -0
- vobiz/xml/emphasisElement.py +174 -0
- vobiz/xml/getDigitsElement.py +294 -0
- vobiz/xml/getInputElement.py +369 -0
- vobiz/xml/hangupElement.py +57 -0
- vobiz/xml/langElement.py +197 -0
- vobiz/xml/messageElement.py +115 -0
- vobiz/xml/numberElement.py +77 -0
- vobiz/xml/pElement.py +164 -0
- vobiz/xml/phonemeElement.py +62 -0
- vobiz/xml/playElement.py +41 -0
- vobiz/xml/preAnswerElement.py +148 -0
- vobiz/xml/prosodyElement.py +227 -0
- vobiz/xml/recordElement.py +337 -0
- vobiz/xml/redirectElement.py +42 -0
- vobiz/xml/sElement.py +154 -0
- vobiz/xml/sayAsElement.py +61 -0
- vobiz/xml/speakElement.py +249 -0
- vobiz/xml/streamElement.py +123 -0
- vobiz/xml/subElement.py +43 -0
- vobiz/xml/userElement.py +79 -0
- vobiz/xml/wElement.py +144 -0
- vobiz/xml/waitElement.py +93 -0
- vobiz/xml/xmlUtils.py +6 -0
- vobiz_python-0.1.0.dist-info/METADATA +640 -0
- vobiz_python-0.1.0.dist-info/RECORD +63 -0
- vobiz_python-0.1.0.dist-info/WHEEL +5 -0
- vobiz_python-0.1.0.dist-info/licenses/LICENSE.txt +19 -0
- vobiz_python-0.1.0.dist-info/top_level.txt +1 -0
vobiz/resources/cdrs.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
|
|
3
|
+
VOBIZ_API_V1 = "https://api.vobiz.ai/api/v1"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CDRs:
|
|
7
|
+
"""
|
|
8
|
+
Vobiz Call Detail Records (CDRs) resource.
|
|
9
|
+
|
|
10
|
+
Endpoint: https://api.vobiz.ai/api/v1/account/{account_id}/cdr
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, client):
|
|
14
|
+
self.client = client
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def _account_id(self) -> str:
|
|
18
|
+
return self.client.auth_id
|
|
19
|
+
|
|
20
|
+
def list(
|
|
21
|
+
self,
|
|
22
|
+
page: Optional[int] = None,
|
|
23
|
+
per_page: Optional[int] = None,
|
|
24
|
+
start_date: Optional[str] = None,
|
|
25
|
+
end_date: Optional[str] = None,
|
|
26
|
+
**filters: Any,
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
GET /api/v1/account/{account_id}/cdr
|
|
30
|
+
"""
|
|
31
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/cdr"
|
|
32
|
+
params: Dict[str, Any] = {}
|
|
33
|
+
if page is not None:
|
|
34
|
+
params["page"] = page
|
|
35
|
+
if per_page is not None:
|
|
36
|
+
params["per_page"] = per_page
|
|
37
|
+
if start_date is not None:
|
|
38
|
+
params["start_date"] = start_date
|
|
39
|
+
if end_date is not None:
|
|
40
|
+
params["end_date"] = end_date
|
|
41
|
+
params.update(filters)
|
|
42
|
+
|
|
43
|
+
resp = self.client.session.get(
|
|
44
|
+
url, params=params, timeout=self.client.timeout, proxies=self.client.proxies
|
|
45
|
+
)
|
|
46
|
+
return self.client.process_response("GET", resp)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
|
|
3
|
+
VOBIZ_API_V1 = "https://api.vobiz.ai/api/v1"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Credentials:
|
|
7
|
+
"""
|
|
8
|
+
Vobiz SIP Credentials resource.
|
|
9
|
+
|
|
10
|
+
All endpoints are scoped to the authenticated account.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, client):
|
|
14
|
+
self.client = client
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def _account_id(self) -> str:
|
|
18
|
+
# For Vobiz, we treat the RestClient auth_id as the account_id
|
|
19
|
+
return self.client.auth_id
|
|
20
|
+
|
|
21
|
+
def create(
|
|
22
|
+
self,
|
|
23
|
+
username: str,
|
|
24
|
+
password: str,
|
|
25
|
+
enabled: Optional[bool] = None,
|
|
26
|
+
description: Optional[str] = None,
|
|
27
|
+
**extra: Any,
|
|
28
|
+
):
|
|
29
|
+
"""
|
|
30
|
+
POST /api/v1/account/{account_id}/credentials
|
|
31
|
+
|
|
32
|
+
Create a new SIP credential (username/password) for the account.
|
|
33
|
+
"""
|
|
34
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/credentials"
|
|
35
|
+
body: Dict[str, Any] = {
|
|
36
|
+
"username": username,
|
|
37
|
+
"password": password,
|
|
38
|
+
}
|
|
39
|
+
if enabled is not None:
|
|
40
|
+
body["enabled"] = enabled
|
|
41
|
+
if description is not None:
|
|
42
|
+
body["description"] = description
|
|
43
|
+
body.update(extra)
|
|
44
|
+
|
|
45
|
+
resp = self.client.session.post(
|
|
46
|
+
url, json=body, timeout=self.client.timeout, proxies=self.client.proxies
|
|
47
|
+
)
|
|
48
|
+
return self.client.process_response("POST", resp)
|
|
49
|
+
|
|
50
|
+
def list(
|
|
51
|
+
self,
|
|
52
|
+
limit: Optional[int] = None,
|
|
53
|
+
offset: Optional[int] = None,
|
|
54
|
+
**filters: Any,
|
|
55
|
+
):
|
|
56
|
+
"""
|
|
57
|
+
GET /api/v1/account/{account_id}/trunks/credentials
|
|
58
|
+
|
|
59
|
+
Retrieve a paginated list of all credentials associated with the account.
|
|
60
|
+
"""
|
|
61
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/trunks/credentials"
|
|
62
|
+
params: Dict[str, Any] = {}
|
|
63
|
+
if limit is not None:
|
|
64
|
+
params["limit"] = limit
|
|
65
|
+
if offset is not None:
|
|
66
|
+
params["offset"] = offset
|
|
67
|
+
params.update(filters)
|
|
68
|
+
|
|
69
|
+
resp = self.client.session.get(
|
|
70
|
+
url, params=params, timeout=self.client.timeout, proxies=self.client.proxies
|
|
71
|
+
)
|
|
72
|
+
return self.client.process_response("GET", resp)
|
|
73
|
+
|
|
74
|
+
def get(self, credential_id: str):
|
|
75
|
+
"""
|
|
76
|
+
GET /api/v1/account/{account_id}/credentials/{credential_id}
|
|
77
|
+
"""
|
|
78
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/credentials/{credential_id}"
|
|
79
|
+
resp = self.client.session.get(
|
|
80
|
+
url, timeout=self.client.timeout, proxies=self.client.proxies
|
|
81
|
+
)
|
|
82
|
+
return self.client.process_response("GET", resp)
|
|
83
|
+
|
|
84
|
+
def update(self, credential_id: str, **params: Any):
|
|
85
|
+
"""
|
|
86
|
+
PUT /api/v1/account/{account_id}/credentials/{credential_id}
|
|
87
|
+
"""
|
|
88
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/credentials/{credential_id}"
|
|
89
|
+
body: Dict[str, Any] = dict(params)
|
|
90
|
+
resp = self.client.session.put(
|
|
91
|
+
url, json=body, timeout=self.client.timeout, proxies=self.client.proxies
|
|
92
|
+
)
|
|
93
|
+
return self.client.process_response("PUT", resp)
|
|
94
|
+
|
|
95
|
+
def delete(self, credential_id: str):
|
|
96
|
+
"""
|
|
97
|
+
DELETE /api/v1/account/{account_id}/credentials/{credential_id}
|
|
98
|
+
"""
|
|
99
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/credentials/{credential_id}"
|
|
100
|
+
resp = self.client.session.delete(
|
|
101
|
+
url, timeout=self.client.timeout, proxies=self.client.proxies
|
|
102
|
+
)
|
|
103
|
+
return self.client.process_response("DELETE", resp)
|
|
104
|
+
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Endpoints:
|
|
5
|
+
"""
|
|
6
|
+
Vobiz Endpoints (SIP endpoints / devices) resource.
|
|
7
|
+
|
|
8
|
+
Uses the `/v1/Account/{auth_id}/Endpoint/...` paths described in the
|
|
9
|
+
Vobiz endpoint documentation.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, client):
|
|
13
|
+
self.client = client
|
|
14
|
+
|
|
15
|
+
def create(
|
|
16
|
+
self,
|
|
17
|
+
username: str,
|
|
18
|
+
password: str,
|
|
19
|
+
alias: Optional[str] = None,
|
|
20
|
+
application: Optional[str] = None,
|
|
21
|
+
**extra: Any,
|
|
22
|
+
):
|
|
23
|
+
"""
|
|
24
|
+
POST /v1/Account/{auth_id}/Endpoint/
|
|
25
|
+
|
|
26
|
+
Create a new SIP endpoint.
|
|
27
|
+
"""
|
|
28
|
+
body: Dict[str, Any] = {
|
|
29
|
+
"username": username,
|
|
30
|
+
"password": password,
|
|
31
|
+
}
|
|
32
|
+
if alias is not None:
|
|
33
|
+
body["alias"] = alias
|
|
34
|
+
if application is not None:
|
|
35
|
+
body["application"] = application
|
|
36
|
+
body.update(extra)
|
|
37
|
+
|
|
38
|
+
return self.client.request(
|
|
39
|
+
"POST",
|
|
40
|
+
("Endpoint",),
|
|
41
|
+
data=body,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def list(
|
|
45
|
+
self,
|
|
46
|
+
limit: Optional[int] = None,
|
|
47
|
+
offset: Optional[int] = None,
|
|
48
|
+
**filters: Any,
|
|
49
|
+
):
|
|
50
|
+
"""
|
|
51
|
+
GET /v1/Account/{auth_id}/Endpoint/
|
|
52
|
+
|
|
53
|
+
Retrieve a paginated list of all SIP endpoints in the account.
|
|
54
|
+
"""
|
|
55
|
+
params: Dict[str, Any] = {}
|
|
56
|
+
if limit is not None:
|
|
57
|
+
params["limit"] = limit
|
|
58
|
+
if offset is not None:
|
|
59
|
+
params["offset"] = offset
|
|
60
|
+
params.update(filters)
|
|
61
|
+
|
|
62
|
+
return self.client.request(
|
|
63
|
+
"GET",
|
|
64
|
+
("Endpoint",),
|
|
65
|
+
data=params,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def get(self, endpoint_id: str):
|
|
69
|
+
"""
|
|
70
|
+
GET /v1/Account/{auth_id}/Endpoint/{endpoint_id}/
|
|
71
|
+
|
|
72
|
+
Retrieve details for a specific endpoint.
|
|
73
|
+
"""
|
|
74
|
+
return self.client.request(
|
|
75
|
+
"GET",
|
|
76
|
+
("Endpoint", endpoint_id),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def update(self, endpoint_id: str, **params: Any):
|
|
80
|
+
"""
|
|
81
|
+
POST /v1/Account/{auth_id}/Endpoint/{endpoint_id}/
|
|
82
|
+
|
|
83
|
+
Update an endpoint's password, alias, application, or permissions.
|
|
84
|
+
"""
|
|
85
|
+
body: Dict[str, Any] = dict(params)
|
|
86
|
+
return self.client.request(
|
|
87
|
+
"POST",
|
|
88
|
+
("Endpoint", endpoint_id),
|
|
89
|
+
data=body,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def delete(self, endpoint_id: str):
|
|
93
|
+
"""
|
|
94
|
+
DELETE /v1/Account/{auth_id}/Endpoint/{endpoint_id}/
|
|
95
|
+
|
|
96
|
+
Delete an endpoint. On success, the API returns 204 No Content.
|
|
97
|
+
"""
|
|
98
|
+
return self.client.request(
|
|
99
|
+
"DELETE",
|
|
100
|
+
("Endpoint", endpoint_id),
|
|
101
|
+
)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
|
|
3
|
+
VOBIZ_API_V1 = "https://api.vobiz.ai/api/v1"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class IpAccessControlLists:
|
|
7
|
+
"""
|
|
8
|
+
Vobiz IP Access Control Lists resource.
|
|
9
|
+
|
|
10
|
+
All endpoints are scoped to the authenticated account.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, client):
|
|
14
|
+
self.client = client
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def _account_id(self) -> str:
|
|
18
|
+
# For Vobiz, we treat the RestClient auth_id as the account_id
|
|
19
|
+
return self.client.auth_id
|
|
20
|
+
|
|
21
|
+
def create(
|
|
22
|
+
self,
|
|
23
|
+
ip_address: str,
|
|
24
|
+
description: Optional[str] = None,
|
|
25
|
+
enabled: Optional[bool] = None,
|
|
26
|
+
**extra: Any,
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
POST /api/v1/account/{account_id}/ip-acl
|
|
30
|
+
|
|
31
|
+
Create a new IP ACL entry.
|
|
32
|
+
"""
|
|
33
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/ip-acl"
|
|
34
|
+
body: Dict[str, Any] = {"ip_address": ip_address}
|
|
35
|
+
if description is not None:
|
|
36
|
+
body["description"] = description
|
|
37
|
+
if enabled is not None:
|
|
38
|
+
body["enabled"] = enabled
|
|
39
|
+
body.update(extra)
|
|
40
|
+
|
|
41
|
+
resp = self.client.session.post(
|
|
42
|
+
url, json=body, timeout=self.client.timeout, proxies=self.client.proxies
|
|
43
|
+
)
|
|
44
|
+
return self.client.process_response("POST", resp)
|
|
45
|
+
|
|
46
|
+
def list(
|
|
47
|
+
self,
|
|
48
|
+
limit: Optional[int] = None,
|
|
49
|
+
offset: Optional[int] = None,
|
|
50
|
+
**filters: Any,
|
|
51
|
+
):
|
|
52
|
+
"""
|
|
53
|
+
GET /api/v1/account/{account_id}/trunks/ip-acl
|
|
54
|
+
|
|
55
|
+
Retrieve a paginated list of all IP ACL entries.
|
|
56
|
+
"""
|
|
57
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/trunks/ip-acl"
|
|
58
|
+
params: Dict[str, Any] = {}
|
|
59
|
+
if limit is not None:
|
|
60
|
+
params["limit"] = limit
|
|
61
|
+
if offset is not None:
|
|
62
|
+
params["offset"] = offset
|
|
63
|
+
params.update(filters)
|
|
64
|
+
|
|
65
|
+
resp = self.client.session.get(
|
|
66
|
+
url, params=params, timeout=self.client.timeout, proxies=self.client.proxies
|
|
67
|
+
)
|
|
68
|
+
return self.client.process_response("GET", resp)
|
|
69
|
+
|
|
70
|
+
def get(self, acl_id: str):
|
|
71
|
+
"""
|
|
72
|
+
GET /api/v1/account/{account_id}/ip-acl/{ip_acl_id}
|
|
73
|
+
"""
|
|
74
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/ip-acl/{acl_id}"
|
|
75
|
+
resp = self.client.session.get(
|
|
76
|
+
url, timeout=self.client.timeout, proxies=self.client.proxies
|
|
77
|
+
)
|
|
78
|
+
return self.client.process_response("GET", resp)
|
|
79
|
+
|
|
80
|
+
def update(self, acl_id: str, **params: Any):
|
|
81
|
+
"""
|
|
82
|
+
PUT /api/v1/account/{account_id}/ip-acl/{ip_acl_id}
|
|
83
|
+
"""
|
|
84
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/ip-acl/{acl_id}"
|
|
85
|
+
body: Dict[str, Any] = dict(params)
|
|
86
|
+
resp = self.client.session.put(
|
|
87
|
+
url, json=body, timeout=self.client.timeout, proxies=self.client.proxies
|
|
88
|
+
)
|
|
89
|
+
return self.client.process_response("PUT", resp)
|
|
90
|
+
|
|
91
|
+
def delete(self, acl_id: str):
|
|
92
|
+
"""
|
|
93
|
+
DELETE /api/v1/account/{account_id}/ip-acl/{ip_acl_id}
|
|
94
|
+
"""
|
|
95
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/ip-acl/{acl_id}"
|
|
96
|
+
resp = self.client.session.delete(
|
|
97
|
+
url, timeout=self.client.timeout, proxies=self.client.proxies
|
|
98
|
+
)
|
|
99
|
+
return self.client.process_response("DELETE", resp)
|
|
100
|
+
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
|
|
3
|
+
VOBIZ_API_V1 = "https://api.vobiz.ai/api/v1"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PhoneNumbers:
|
|
7
|
+
"""
|
|
8
|
+
Vobiz Phone Numbers resource.
|
|
9
|
+
|
|
10
|
+
Implements inventory listing, purchase from inventory, and release,
|
|
11
|
+
as defined in the Vobiz phone number endpoints.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, client):
|
|
15
|
+
self.client = client
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def _account_id(self) -> str:
|
|
19
|
+
# For Vobiz, we treat the RestClient auth_id as the account_id
|
|
20
|
+
return self.client.auth_id
|
|
21
|
+
|
|
22
|
+
def list(
|
|
23
|
+
self,
|
|
24
|
+
page: Optional[int] = None,
|
|
25
|
+
per_page: Optional[int] = None,
|
|
26
|
+
include_subaccounts: Optional[bool] = None,
|
|
27
|
+
**filters: Any,
|
|
28
|
+
):
|
|
29
|
+
"""
|
|
30
|
+
GET /api/v1/account/{auth_id}/numbers
|
|
31
|
+
|
|
32
|
+
List all phone numbers purchased and assigned to this account.
|
|
33
|
+
include_subaccounts: if True, also returns numbers from sub-accounts (master accounts only).
|
|
34
|
+
"""
|
|
35
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/numbers"
|
|
36
|
+
params: Dict[str, Any] = {}
|
|
37
|
+
if page is not None:
|
|
38
|
+
params["page"] = page
|
|
39
|
+
if per_page is not None:
|
|
40
|
+
params["per_page"] = per_page
|
|
41
|
+
if include_subaccounts is not None:
|
|
42
|
+
params["include_subaccounts"] = include_subaccounts
|
|
43
|
+
params.update(filters)
|
|
44
|
+
|
|
45
|
+
resp = self.client.session.get(
|
|
46
|
+
url, params=params, timeout=self.client.timeout, proxies=self.client.proxies
|
|
47
|
+
)
|
|
48
|
+
return self.client.process_response("GET", resp)
|
|
49
|
+
|
|
50
|
+
def list_inventory( self,
|
|
51
|
+
country: Optional[str] = None,
|
|
52
|
+
page: Optional[int] = None,
|
|
53
|
+
per_page: Optional[int] = None,
|
|
54
|
+
**filters: Any,
|
|
55
|
+
):
|
|
56
|
+
"""
|
|
57
|
+
GET /api/v1/account/{auth_id}/inventory/numbers
|
|
58
|
+
|
|
59
|
+
Browse available phone numbers in inventory that are not assigned
|
|
60
|
+
to any account (auth_id IS NULL, status='active').
|
|
61
|
+
"""
|
|
62
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/inventory/numbers"
|
|
63
|
+
params: Dict[str, Any] = {}
|
|
64
|
+
if country is not None:
|
|
65
|
+
params["country"] = country
|
|
66
|
+
if page is not None:
|
|
67
|
+
params["page"] = page
|
|
68
|
+
if per_page is not None:
|
|
69
|
+
params["per_page"] = per_page
|
|
70
|
+
params.update(filters)
|
|
71
|
+
|
|
72
|
+
resp = self.client.session.get(
|
|
73
|
+
url, params=params, timeout=self.client.timeout, proxies=self.client.proxies
|
|
74
|
+
)
|
|
75
|
+
return self.client.process_response("GET", resp)
|
|
76
|
+
|
|
77
|
+
def purchase_from_inventory(
|
|
78
|
+
self,
|
|
79
|
+
e164: str,
|
|
80
|
+
currency: Optional[str] = None,
|
|
81
|
+
**extra: Any,
|
|
82
|
+
):
|
|
83
|
+
"""
|
|
84
|
+
POST /api/v1/account/{auth_id}/numbers/purchase-from-inventory
|
|
85
|
+
|
|
86
|
+
Purchase a phone number from inventory and assign it to the account.
|
|
87
|
+
"""
|
|
88
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/numbers/purchase-from-inventory"
|
|
89
|
+
body: Dict[str, Any] = {"e164": e164}
|
|
90
|
+
if currency is not None:
|
|
91
|
+
body["currency"] = currency
|
|
92
|
+
body.update(extra)
|
|
93
|
+
|
|
94
|
+
resp = self.client.session.post(
|
|
95
|
+
url, json=body, timeout=self.client.timeout, proxies=self.client.proxies
|
|
96
|
+
)
|
|
97
|
+
return self.client.process_response("POST", resp)
|
|
98
|
+
|
|
99
|
+
def release(self, e164_number: str):
|
|
100
|
+
"""
|
|
101
|
+
DELETE /api/v1/account/{auth_id}/numbers/{e164_number}
|
|
102
|
+
|
|
103
|
+
Release a phone number from the account back to inventory.
|
|
104
|
+
"""
|
|
105
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/numbers/{e164_number}"
|
|
106
|
+
resp = self.client.session.delete(
|
|
107
|
+
url, timeout=self.client.timeout, proxies=self.client.proxies
|
|
108
|
+
)
|
|
109
|
+
return self.client.process_response("DELETE", resp)
|
|
110
|
+
|
|
111
|
+
def assign_to_trunk(self, e164_number: str, trunk_group_id: str):
|
|
112
|
+
"""
|
|
113
|
+
POST /api/v1/account/{account_id}/numbers/{PHONE_NUMBER}/assign
|
|
114
|
+
|
|
115
|
+
Assign a phone number to a SIP trunk.
|
|
116
|
+
"""
|
|
117
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/numbers/{e164_number}/assign"
|
|
118
|
+
body: Dict[str, Any] = {"trunk_group_id": trunk_group_id}
|
|
119
|
+
resp = self.client.session.post(
|
|
120
|
+
url, json=body, timeout=self.client.timeout, proxies=self.client.proxies
|
|
121
|
+
)
|
|
122
|
+
return self.client.process_response("POST", resp)
|
|
123
|
+
|
|
124
|
+
def unassign_from_trunk(self, e164_number: str):
|
|
125
|
+
"""
|
|
126
|
+
DELETE /api/v1/account/{account_id}/numbers/{PHONE_NUMBER}/assign
|
|
127
|
+
|
|
128
|
+
Unassign a phone number from its SIP trunk.
|
|
129
|
+
"""
|
|
130
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/numbers/{e164_number}/assign"
|
|
131
|
+
resp = self.client.session.delete(
|
|
132
|
+
url, timeout=self.client.timeout, proxies=self.client.proxies
|
|
133
|
+
)
|
|
134
|
+
return self.client.process_response("DELETE", resp)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
|
|
3
|
+
VOBIZ_API_V1 = "https://api.vobiz.ai/api/v1"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class OriginationUris:
|
|
7
|
+
"""
|
|
8
|
+
Vobiz Origination URIs resource.
|
|
9
|
+
|
|
10
|
+
Implements create, list, update, and delete operations using the
|
|
11
|
+
`/api/v1/account/{account_id}/origination-uris` and
|
|
12
|
+
`/api/v1/account/{account_id}/trunks/origination-uris` endpoints.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, client):
|
|
16
|
+
self.client = client
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def _account_id(self) -> str:
|
|
20
|
+
# For Vobiz, we treat the RestClient auth_id as the account_id
|
|
21
|
+
return self.client.auth_id
|
|
22
|
+
|
|
23
|
+
def create(
|
|
24
|
+
self,
|
|
25
|
+
uri: str,
|
|
26
|
+
priority: Optional[int] = None,
|
|
27
|
+
weight: Optional[int] = None,
|
|
28
|
+
enabled: Optional[bool] = None,
|
|
29
|
+
**extra: Any,
|
|
30
|
+
):
|
|
31
|
+
"""
|
|
32
|
+
POST /api/v1/account/{account_id}/origination-uris
|
|
33
|
+
|
|
34
|
+
Create a new origination URI for outbound routing.
|
|
35
|
+
"""
|
|
36
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/origination-uris"
|
|
37
|
+
body: Dict[str, Any] = {"uri": uri}
|
|
38
|
+
if priority is not None:
|
|
39
|
+
body["priority"] = priority
|
|
40
|
+
if weight is not None:
|
|
41
|
+
body["weight"] = weight
|
|
42
|
+
if enabled is not None:
|
|
43
|
+
body["enabled"] = enabled
|
|
44
|
+
body.update(extra)
|
|
45
|
+
|
|
46
|
+
resp = self.client.session.post(
|
|
47
|
+
url, json=body, timeout=self.client.timeout, proxies=self.client.proxies
|
|
48
|
+
)
|
|
49
|
+
return self.client.process_response("POST", resp)
|
|
50
|
+
|
|
51
|
+
def list(
|
|
52
|
+
self,
|
|
53
|
+
trunk_id: Optional[str] = None,
|
|
54
|
+
limit: Optional[int] = None,
|
|
55
|
+
offset: Optional[int] = None,
|
|
56
|
+
**filters: Any,
|
|
57
|
+
):
|
|
58
|
+
"""
|
|
59
|
+
GET /api/v1/account/{account_id}/trunks/origination-uris
|
|
60
|
+
|
|
61
|
+
Retrieve a paginated list of origination URIs.
|
|
62
|
+
Optionally filter by trunk_id.
|
|
63
|
+
"""
|
|
64
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/trunks/origination-uris"
|
|
65
|
+
params: Dict[str, Any] = {}
|
|
66
|
+
if trunk_id is not None:
|
|
67
|
+
params["trunk_id"] = trunk_id
|
|
68
|
+
if limit is not None:
|
|
69
|
+
params["limit"] = limit
|
|
70
|
+
if offset is not None:
|
|
71
|
+
params["offset"] = offset
|
|
72
|
+
params.update(filters)
|
|
73
|
+
|
|
74
|
+
resp = self.client.session.get(
|
|
75
|
+
url, params=params, timeout=self.client.timeout, proxies=self.client.proxies
|
|
76
|
+
)
|
|
77
|
+
return self.client.process_response("GET", resp)
|
|
78
|
+
|
|
79
|
+
def get(self, uri_id: str):
|
|
80
|
+
"""
|
|
81
|
+
GET /api/v1/account/{account_id}/origination-uris/{uri_id}
|
|
82
|
+
"""
|
|
83
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/origination-uris/{uri_id}"
|
|
84
|
+
resp = self.client.session.get(
|
|
85
|
+
url, timeout=self.client.timeout, proxies=self.client.proxies
|
|
86
|
+
)
|
|
87
|
+
return self.client.process_response("GET", resp)
|
|
88
|
+
|
|
89
|
+
def update(self, uri_id: str, **params: Any):
|
|
90
|
+
"""
|
|
91
|
+
PUT /api/v1/account/{account_id}/origination-uris/{uri_id}
|
|
92
|
+
"""
|
|
93
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/origination-uris/{uri_id}"
|
|
94
|
+
body: Dict[str, Any] = dict(params)
|
|
95
|
+
resp = self.client.session.put(
|
|
96
|
+
url, json=body, timeout=self.client.timeout, proxies=self.client.proxies
|
|
97
|
+
)
|
|
98
|
+
return self.client.process_response("PUT", resp)
|
|
99
|
+
|
|
100
|
+
def delete(self, uri_id: str):
|
|
101
|
+
"""
|
|
102
|
+
DELETE /api/v1/account/{account_id}/origination-uris/{uri_id}
|
|
103
|
+
"""
|
|
104
|
+
url = f"{VOBIZ_API_V1}/account/{self._account_id}/origination-uris/{uri_id}"
|
|
105
|
+
resp = self.client.session.delete(
|
|
106
|
+
url, timeout=self.client.timeout, proxies=self.client.proxies
|
|
107
|
+
)
|
|
108
|
+
return self.client.process_response("DELETE", resp)
|
|
109
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Recordings:
|
|
5
|
+
"""
|
|
6
|
+
Vobiz Recordings resource.
|
|
7
|
+
|
|
8
|
+
Endpoint: https://api.vobiz.ai/api/v1/Account/{auth_id}/Recording/
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, client):
|
|
12
|
+
self.client = client
|
|
13
|
+
|
|
14
|
+
def list(
|
|
15
|
+
self,
|
|
16
|
+
limit: Optional[int] = None,
|
|
17
|
+
offset: Optional[int] = None,
|
|
18
|
+
call_uuid: Optional[str] = None,
|
|
19
|
+
recording_type: Optional[str] = None,
|
|
20
|
+
**filters: Any,
|
|
21
|
+
):
|
|
22
|
+
"""
|
|
23
|
+
GET /api/v1/Account/{auth_id}/Recording/
|
|
24
|
+
"""
|
|
25
|
+
params: Dict[str, Any] = {}
|
|
26
|
+
if limit is not None:
|
|
27
|
+
params["limit"] = limit
|
|
28
|
+
if offset is not None:
|
|
29
|
+
params["offset"] = offset
|
|
30
|
+
if call_uuid is not None:
|
|
31
|
+
params["call_uuid"] = call_uuid
|
|
32
|
+
if recording_type is not None:
|
|
33
|
+
params["recording_type"] = recording_type
|
|
34
|
+
params.update(filters)
|
|
35
|
+
|
|
36
|
+
return self.client.request("GET", ("Recording",), data=params)
|
|
37
|
+
|
|
38
|
+
def get(self, recording_id: str):
|
|
39
|
+
"""
|
|
40
|
+
GET /api/v1/Account/{auth_id}/Recording/{recording_id}/
|
|
41
|
+
"""
|
|
42
|
+
return self.client.request("GET", ("Recording", recording_id))
|
|
43
|
+
|
|
44
|
+
def delete(self, recording_id: str):
|
|
45
|
+
"""
|
|
46
|
+
DELETE /api/v1/Account/{auth_id}/Recording/{recording_id}/
|
|
47
|
+
"""
|
|
48
|
+
return self.client.request("DELETE", ("Recording", recording_id))
|
|
49
|
+
|
|
50
|
+
def export(self, recipient_emails: list, **filters: Any):
|
|
51
|
+
"""
|
|
52
|
+
POST /api/v1/Account/{auth_id}/export/recording/
|
|
53
|
+
|
|
54
|
+
Async export — recordings matching filters are packaged and emailed.
|
|
55
|
+
recipient_emails: list of email addresses to receive the download link.
|
|
56
|
+
|
|
57
|
+
Date range filters (use one or the other, not both):
|
|
58
|
+
from_date / to_date — e.g. "2025-01-01 00:00:00"
|
|
59
|
+
recording_storage_duration — exact days old
|
|
60
|
+
recording_storage_duration__gte / __lte — range of days old
|
|
61
|
+
|
|
62
|
+
Optional additional filters (only for ranges <= 30 days):
|
|
63
|
+
from_number, to_number, conference_name, recording_format ("mp3"/"wav")
|
|
64
|
+
"""
|
|
65
|
+
VOBIZ_API_V1 = "https://api.vobiz.ai/api/v1"
|
|
66
|
+
url = f"{VOBIZ_API_V1}/Account/{self.client.auth_id}/export/recording/"
|
|
67
|
+
body: Dict[str, Any] = {
|
|
68
|
+
"recipient": {"customer_account": recipient_emails}
|
|
69
|
+
}
|
|
70
|
+
body.update(filters)
|
|
71
|
+
resp = self.client.session.post(
|
|
72
|
+
url, json=body,
|
|
73
|
+
timeout=self.client.timeout,
|
|
74
|
+
proxies=self.client.proxies,
|
|
75
|
+
)
|
|
76
|
+
return self.client.process_response("POST", resp)
|
|
77
|
+
|
|
78
|
+
def bulk_delete(self, **filters: Any):
|
|
79
|
+
"""
|
|
80
|
+
DELETE /api/v1/Account/{auth_id}/Recording/BulkDelete/
|
|
81
|
+
|
|
82
|
+
Async bulk delete — permanently removes all recordings matching filters.
|
|
83
|
+
At least one filter is recommended to avoid deleting everything.
|
|
84
|
+
|
|
85
|
+
Filter params (as query string kwargs):
|
|
86
|
+
add_time__gte / add_time__lte — "YYYY-MM-DD HH:MM:SS"
|
|
87
|
+
conference_name, recording_format, from_number, to_number
|
|
88
|
+
"""
|
|
89
|
+
return self.client.request(
|
|
90
|
+
"DELETE", ("Recording", "BulkDelete"), data=filters
|
|
91
|
+
)
|