carrier-python 0.1.15__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.
- carrier/__init__.py +52 -0
- carrier/adapters.py +121 -0
- carrier/catalog.py +108 -0
- carrier/cli.py +70 -0
- carrier/client.py +63 -0
- carrier/data/cli.json +3032 -0
- carrier/data/operations.json +3042 -0
- carrier/errors.py +51 -0
- carrier/http.py +135 -0
- carrier/idempotency.py +46 -0
- carrier/mcp.py +237 -0
- carrier/models.py +213 -0
- carrier/operation_ids.py +188 -0
- carrier/operations.py +192 -0
- carrier/py.typed +0 -0
- carrier/records.py +117 -0
- carrier/resources.py +201 -0
- carrier/signature.py +57 -0
- carrier/version.py +3 -0
- carrier_python-0.1.15.dist-info/METADATA +87 -0
- carrier_python-0.1.15.dist-info/RECORD +23 -0
- carrier_python-0.1.15.dist-info/WHEEL +5 -0
- carrier_python-0.1.15.dist-info/top_level.txt +1 -0
carrier/operation_ids.py
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Operation ids from the public OpenAPI document.
|
|
2
|
+
|
|
3
|
+
Generated by sdks/generate.py. Do not edit by hand.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Literal
|
|
7
|
+
|
|
8
|
+
OperationId = Literal[
|
|
9
|
+
"list_reseller_accounts",
|
|
10
|
+
"get_reseller_info",
|
|
11
|
+
"esim_status_per_account",
|
|
12
|
+
"list_sponsors",
|
|
13
|
+
"list_steering_lists",
|
|
14
|
+
"get_subscriber",
|
|
15
|
+
"list_subscribers",
|
|
16
|
+
"create_subscriber",
|
|
17
|
+
"get_sim_provider_status",
|
|
18
|
+
"change_sim_status",
|
|
19
|
+
"get_subscriber_location",
|
|
20
|
+
"hlr_get_bitrate",
|
|
21
|
+
"hlr_set_bitrate",
|
|
22
|
+
"list_subscriber_packages",
|
|
23
|
+
"assign_package",
|
|
24
|
+
"clean_all_packages",
|
|
25
|
+
"list_package_templates",
|
|
26
|
+
"create_package_template",
|
|
27
|
+
"list_location_zones",
|
|
28
|
+
"create_location_zone",
|
|
29
|
+
"list_detailed_location_zones",
|
|
30
|
+
"list_destination_prefixes",
|
|
31
|
+
"subscriber_usage",
|
|
32
|
+
"subscriber_network_events",
|
|
33
|
+
"subscriber_active_period",
|
|
34
|
+
"get_tariff",
|
|
35
|
+
"list_network_profiles",
|
|
36
|
+
"modify_subscriber_balance",
|
|
37
|
+
"modify_subscriber_status",
|
|
38
|
+
"modify_subscriber_contact_info",
|
|
39
|
+
"set_subscriber_traffic_restrictions",
|
|
40
|
+
"modify_subscriber_steering_list",
|
|
41
|
+
"move_subscriber_range_to_account",
|
|
42
|
+
"assign_recurring_package",
|
|
43
|
+
"modify_package_limits",
|
|
44
|
+
"modify_package_expiry",
|
|
45
|
+
"modify_package_status",
|
|
46
|
+
"stop_resume_recurring_package",
|
|
47
|
+
"modify_account_balance",
|
|
48
|
+
"delete_subscriber_package",
|
|
49
|
+
"modify_template_core",
|
|
50
|
+
"modify_template_recurring",
|
|
51
|
+
"modify_template_throttling",
|
|
52
|
+
"send_sms",
|
|
53
|
+
"fleet_health",
|
|
54
|
+
"churn_risk",
|
|
55
|
+
"audit_network_coverage",
|
|
56
|
+
"diagnose_subscriber",
|
|
57
|
+
"detect_usage_anomalies",
|
|
58
|
+
"optimize_package",
|
|
59
|
+
"marketing_intelligence",
|
|
60
|
+
"high_cost_subscribers",
|
|
61
|
+
"high_cost_subscribers_method_guard",
|
|
62
|
+
"detect_country_entry",
|
|
63
|
+
"list_intelligence_schedules",
|
|
64
|
+
"create_intelligence_schedule",
|
|
65
|
+
"delete_intelligence_schedule",
|
|
66
|
+
"run_intelligence_schedule",
|
|
67
|
+
"get_intelligence_schedule_report",
|
|
68
|
+
"get_intelligence_share",
|
|
69
|
+
"operator_billing_connect_begin",
|
|
70
|
+
"operator_billing_connect_oauth_begin",
|
|
71
|
+
"operator_billing_connect_oauth_complete",
|
|
72
|
+
"operator_billing_connect_status",
|
|
73
|
+
"operator_billing_connect_dashboard_link",
|
|
74
|
+
"operator_billing_list_payouts",
|
|
75
|
+
"operator_billing_create_manual_payout",
|
|
76
|
+
"operator_billing_get_payout_schedule",
|
|
77
|
+
"operator_billing_update_payout_schedule",
|
|
78
|
+
"operator_billing_list_fees",
|
|
79
|
+
"operator_billing_list_charges",
|
|
80
|
+
"operator_billing_get_balance",
|
|
81
|
+
"operator_billing_list_refunds",
|
|
82
|
+
"operator_billing_create_refund",
|
|
83
|
+
"operator_billing_list_disputes",
|
|
84
|
+
"operator_billing_submit_dispute_evidence",
|
|
85
|
+
"operator_billing_list_fraud_reviews",
|
|
86
|
+
"operator_billing_approve_fraud_review",
|
|
87
|
+
"operator_billing_decline_fraud_review",
|
|
88
|
+
"operator_billing_list_value_lists",
|
|
89
|
+
"operator_billing_add_value_list_item",
|
|
90
|
+
"affiliates_me_get",
|
|
91
|
+
"affiliates_me_create",
|
|
92
|
+
"affiliates_me_commissions_list",
|
|
93
|
+
"affiliates_link",
|
|
94
|
+
"operator_identity_status",
|
|
95
|
+
"operator_identity_create_session",
|
|
96
|
+
"operator_identity_update_session",
|
|
97
|
+
"operator_list_promotions",
|
|
98
|
+
"operator_create_promotion",
|
|
99
|
+
"signup_start",
|
|
100
|
+
"signup_verify",
|
|
101
|
+
"create_api_key",
|
|
102
|
+
"get_onboarding_state",
|
|
103
|
+
"onboarding_save_org",
|
|
104
|
+
"onboarding_connect_ocs_token",
|
|
105
|
+
"onboarding_start_managed_account",
|
|
106
|
+
"onboarding_save_plan",
|
|
107
|
+
"onboarding_skip_plan",
|
|
108
|
+
"onboarding_test_esim",
|
|
109
|
+
"onboarding_complete",
|
|
110
|
+
"operator_billing_stripe_webhook",
|
|
111
|
+
"receive_bridge4ip_webhook",
|
|
112
|
+
"affect_subscriber_phone_number",
|
|
113
|
+
"modify_subscriber_mobile_plan",
|
|
114
|
+
"modify_subscriber_voip_plan",
|
|
115
|
+
"push_steering_to_subscriber",
|
|
116
|
+
"modify_subscriber_package_active_period",
|
|
117
|
+
"get_subscriber_location_by_cell_id",
|
|
118
|
+
"reset_subscriber_gz_counter",
|
|
119
|
+
"list_destination_lists",
|
|
120
|
+
"list_subscriber_voip_tariff",
|
|
121
|
+
"list_voip_tariff_rule",
|
|
122
|
+
"change_network_profile_of_location_zone",
|
|
123
|
+
"get_network_default",
|
|
124
|
+
"set_network_default",
|
|
125
|
+
"plan_network_default",
|
|
126
|
+
"carrier_webhook_config",
|
|
127
|
+
"ai_chat",
|
|
128
|
+
"ai_insights",
|
|
129
|
+
"ai_quota",
|
|
130
|
+
"list_invoice_periods",
|
|
131
|
+
"get_billing_config",
|
|
132
|
+
"update_billing_config",
|
|
133
|
+
"stripe_connect_begin",
|
|
134
|
+
"stripe_connect_status",
|
|
135
|
+
"list_invoices",
|
|
136
|
+
"create_invoice",
|
|
137
|
+
"get_invoice",
|
|
138
|
+
"update_invoice",
|
|
139
|
+
"void_invoice",
|
|
140
|
+
"get_invoice_document",
|
|
141
|
+
"list_connectivity_plans",
|
|
142
|
+
"list_connectivity_products",
|
|
143
|
+
"create_connectivity_product",
|
|
144
|
+
"get_connectivity_product",
|
|
145
|
+
"list_connectivity_intents",
|
|
146
|
+
"create_connectivity_intent",
|
|
147
|
+
"get_connectivity_intent",
|
|
148
|
+
"confirm_connectivity_intent",
|
|
149
|
+
"create_connectivity_webhook_endpoint",
|
|
150
|
+
"list_connectivity_webhook_endpoints",
|
|
151
|
+
"delete_connectivity_webhook_endpoint",
|
|
152
|
+
"list_connectivity_events",
|
|
153
|
+
"get_connectivity_event",
|
|
154
|
+
"create_connectivity_usage_record",
|
|
155
|
+
"list_connectivity_usage_records",
|
|
156
|
+
"retry_connectivity_event",
|
|
157
|
+
"issue_esim_from_inventory",
|
|
158
|
+
"rollback_esim_issuance",
|
|
159
|
+
"subscriber_country_history",
|
|
160
|
+
"get_subscriber_notes",
|
|
161
|
+
"add_subscriber_note",
|
|
162
|
+
"put_subscriber_notes",
|
|
163
|
+
"observe_connectivity_event",
|
|
164
|
+
"ingest_connectivity_usage",
|
|
165
|
+
"ingest_cdr_events",
|
|
166
|
+
"aggregate_cdr",
|
|
167
|
+
"list_storefront_templates",
|
|
168
|
+
"list_storefront_buyer_orders",
|
|
169
|
+
"get_storefront_order_usage",
|
|
170
|
+
"get_storefront_order_top_up_options",
|
|
171
|
+
"cancel_storefront_top_up_checkout",
|
|
172
|
+
"cancel_storefront_order",
|
|
173
|
+
"get_storefront_order",
|
|
174
|
+
"rollback_storefront_order",
|
|
175
|
+
"get_hosted_storefront",
|
|
176
|
+
"get_hosted_storefront_plan_readiness",
|
|
177
|
+
"list_storefronts",
|
|
178
|
+
"create_storefront",
|
|
179
|
+
"list_storefront_orders",
|
|
180
|
+
"get_storefront",
|
|
181
|
+
"update_storefront",
|
|
182
|
+
"upsert_storefront_plan",
|
|
183
|
+
"update_storefront_plan",
|
|
184
|
+
"publish_storefront",
|
|
185
|
+
"plan_storefront_publish",
|
|
186
|
+
"unpublish_storefront",
|
|
187
|
+
"health_check",
|
|
188
|
+
]
|
carrier/operations.py
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""Generic caller for every operation id in the public OpenAPI document."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from urllib.parse import quote
|
|
8
|
+
|
|
9
|
+
from carrier.catalog import HEADER_FIELDS, Operation, operation
|
|
10
|
+
from carrier.errors import CarrierError
|
|
11
|
+
from carrier.http import Http
|
|
12
|
+
from carrier.idempotency import is_issuance, require_id, require_idempotency_key, require_issuance_key
|
|
13
|
+
|
|
14
|
+
_PATH_PARAM = re.compile(r"\{([^{}]+)\}")
|
|
15
|
+
_IDEMPOTENCY_HEADERS = {"Idempotency-Key", "X-Idempotency-Key"}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def call_operation(
|
|
19
|
+
http: Http,
|
|
20
|
+
operation_id: str,
|
|
21
|
+
*,
|
|
22
|
+
path: Mapping[str, object] | None = None,
|
|
23
|
+
query: Mapping[str, object] | None = None,
|
|
24
|
+
headers: Mapping[str, object] | None = None,
|
|
25
|
+
body: object | None = None,
|
|
26
|
+
idempotency_key: str | None = None,
|
|
27
|
+
) -> object:
|
|
28
|
+
"""Call one operation by its OpenAPI operationId."""
|
|
29
|
+
spec = operation(operation_id)
|
|
30
|
+
path_values = _named(path, "path")
|
|
31
|
+
query_values = _named(query, "query")
|
|
32
|
+
header_values = _named(headers, "header")
|
|
33
|
+
_reject_unknown("path", path_values, spec["pathParams"])
|
|
34
|
+
_reject_unknown("query", query_values, spec["queryParams"])
|
|
35
|
+
_reject_unknown("header", header_values, spec["headerParams"])
|
|
36
|
+
_require_present("Path", path_values, spec["pathParams"])
|
|
37
|
+
_apply_idempotency(spec, header_values, idempotency_key)
|
|
38
|
+
_require_headers(header_values, spec)
|
|
39
|
+
for name in list(header_values):
|
|
40
|
+
if name in _IDEMPOTENCY_HEADERS:
|
|
41
|
+
if is_issuance(spec["method"], spec["path"]):
|
|
42
|
+
header_values[name] = require_issuance_key(header_values[name])
|
|
43
|
+
else:
|
|
44
|
+
header_values[name] = require_idempotency_key(str(header_values[name]))
|
|
45
|
+
if spec["bodyRequired"] and body is None:
|
|
46
|
+
raise CarrierError(400, "missing_body", "This operation requires a JSON body.")
|
|
47
|
+
if body is not None and not spec["body"]:
|
|
48
|
+
raise CarrierError(400, "invalid_body", "This operation does not take a JSON body.")
|
|
49
|
+
idempotency = header_values.pop("Idempotency-Key", None)
|
|
50
|
+
encoded_query = {key: _query_value(value) for key, value in query_values.items()}
|
|
51
|
+
return http.request(
|
|
52
|
+
spec["method"],
|
|
53
|
+
_fill_path(spec["path"], path_values),
|
|
54
|
+
body=body,
|
|
55
|
+
query=encoded_query or None,
|
|
56
|
+
headers={key: str(value) for key, value in header_values.items()} or None,
|
|
57
|
+
idempotency_key=str(idempotency) if idempotency is not None else None,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def input_schema(spec: Operation) -> dict[str, object]:
|
|
62
|
+
"""JSON schema for the arguments accepted by one operation."""
|
|
63
|
+
properties: dict[str, object] = {}
|
|
64
|
+
required: list[str] = []
|
|
65
|
+
for param in spec["pathParams"]:
|
|
66
|
+
properties[param["name"]] = {"type": "string", "description": f"Path {param['name']}"}
|
|
67
|
+
if param["required"]:
|
|
68
|
+
required.append(param["name"])
|
|
69
|
+
for param in spec["queryParams"]:
|
|
70
|
+
properties[param["name"]] = {"type": "string", "description": f"Query {param['name']}"}
|
|
71
|
+
if param["required"]:
|
|
72
|
+
required.append(param["name"])
|
|
73
|
+
for param in spec["headerParams"]:
|
|
74
|
+
field = HEADER_FIELDS.get(param["name"], param["name"])
|
|
75
|
+
schema: dict[str, object] = {"type": "string", "description": param["name"]}
|
|
76
|
+
if is_issuance(spec["method"], spec["path"]) and field == "idempotency_key":
|
|
77
|
+
schema.update({"minLength": 1, "maxLength": 200, "pattern": "^[A-Za-z0-9][A-Za-z0-9_.:-]{0,199}$"})
|
|
78
|
+
properties[field] = schema
|
|
79
|
+
if param["required"]:
|
|
80
|
+
required.append(field)
|
|
81
|
+
if spec["body"]:
|
|
82
|
+
properties["body"] = {"type": "object", "additionalProperties": True, "description": "JSON request body"}
|
|
83
|
+
if spec["bodyRequired"]:
|
|
84
|
+
required.append("body")
|
|
85
|
+
return {
|
|
86
|
+
"type": "object",
|
|
87
|
+
"properties": properties,
|
|
88
|
+
"required": required,
|
|
89
|
+
"additionalProperties": False,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def arguments_to_call(spec: Operation, arguments: Mapping[str, object]) -> dict[str, object]:
|
|
94
|
+
"""Split a flat tool argument object into call_operation keyword arguments."""
|
|
95
|
+
path: dict[str, object] = {}
|
|
96
|
+
query: dict[str, object] = {}
|
|
97
|
+
headers: dict[str, object] = {}
|
|
98
|
+
body = arguments.get("body") if "body" in arguments else None
|
|
99
|
+
known = {param["name"] for param in spec["pathParams"]}
|
|
100
|
+
known.update(param["name"] for param in spec["queryParams"])
|
|
101
|
+
header_names = {HEADER_FIELDS.get(param["name"], param["name"]): param["name"] for param in spec["headerParams"]}
|
|
102
|
+
known.update(header_names)
|
|
103
|
+
if spec["body"]:
|
|
104
|
+
known.add("body")
|
|
105
|
+
unknown = [key for key in arguments if key not in known]
|
|
106
|
+
if unknown:
|
|
107
|
+
raise CarrierError(400, "unknown_parameter", f"Unknown argument {unknown[0]}.")
|
|
108
|
+
for param in spec["pathParams"]:
|
|
109
|
+
if param["name"] in arguments:
|
|
110
|
+
path[param["name"]] = arguments[param["name"]]
|
|
111
|
+
for param in spec["queryParams"]:
|
|
112
|
+
if param["name"] in arguments:
|
|
113
|
+
query[param["name"]] = arguments[param["name"]]
|
|
114
|
+
for field, header in header_names.items():
|
|
115
|
+
if field in arguments and field != "idempotency_key":
|
|
116
|
+
headers[header] = arguments[field]
|
|
117
|
+
call: dict[str, object] = {"path": path, "query": query, "headers": headers}
|
|
118
|
+
if "body" in arguments:
|
|
119
|
+
call["body"] = body
|
|
120
|
+
if "idempotency_key" in arguments:
|
|
121
|
+
call["idempotency_key"] = arguments["idempotency_key"]
|
|
122
|
+
return call
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _named(values: Mapping[str, object] | None, label: str) -> dict[str, object]:
|
|
126
|
+
if values is None:
|
|
127
|
+
return {}
|
|
128
|
+
named: dict[str, object] = {}
|
|
129
|
+
for key, value in values.items():
|
|
130
|
+
if not isinstance(key, str) or key.strip() == "":
|
|
131
|
+
raise CarrierError(400, "invalid_parameter", f"{label} parameter names must be strings.")
|
|
132
|
+
named[key] = value
|
|
133
|
+
return named
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _reject_unknown(label: str, values: Mapping[str, object], params: list[dict[str, object]]) -> None:
|
|
137
|
+
allowed = {str(param["name"]) for param in params}
|
|
138
|
+
for name in values:
|
|
139
|
+
if name not in allowed:
|
|
140
|
+
raise CarrierError(400, "unknown_parameter", f"Unknown {label} parameter {name}.")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _require_present(label: str, values: Mapping[str, object], params: list[dict[str, object]]) -> None:
|
|
144
|
+
for param in params:
|
|
145
|
+
if param["required"] and param["name"] not in values:
|
|
146
|
+
raise CarrierError(400, "missing_parameter", f"{label} parameter {param['name']} is required.")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _apply_idempotency(spec: Operation, headers: dict[str, object], idempotency_key: str | None) -> None:
|
|
150
|
+
if idempotency_key is None:
|
|
151
|
+
return
|
|
152
|
+
names = {param["name"] for param in spec["headerParams"]}
|
|
153
|
+
if "Idempotency-Key" in names:
|
|
154
|
+
headers["Idempotency-Key"] = idempotency_key
|
|
155
|
+
return
|
|
156
|
+
if "X-Idempotency-Key" in names:
|
|
157
|
+
headers["X-Idempotency-Key"] = idempotency_key
|
|
158
|
+
return
|
|
159
|
+
raise CarrierError(400, "unknown_parameter", "This operation does not take an idempotency key.")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _require_headers(values: Mapping[str, object], spec: Operation) -> None:
|
|
163
|
+
for param in spec["headerParams"]:
|
|
164
|
+
if not param["required"] or param["name"] in values:
|
|
165
|
+
continue
|
|
166
|
+
if param["name"] == "X-Idempotency-Key" and "Idempotency-Key" in values:
|
|
167
|
+
continue
|
|
168
|
+
field = HEADER_FIELDS.get(param["name"], param["name"])
|
|
169
|
+
raise CarrierError(400, "missing_parameter", f"{field} is required.")
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _fill_path(template: str, values: Mapping[str, object]) -> str:
|
|
173
|
+
def replace(match: re.Match[str]) -> str:
|
|
174
|
+
name = match.group(1)
|
|
175
|
+
if name not in values:
|
|
176
|
+
raise CarrierError(400, "missing_parameter", f"Path parameter {name} is required.")
|
|
177
|
+
return quote(require_id(str(values[name]), name), safe="")
|
|
178
|
+
|
|
179
|
+
filled = _PATH_PARAM.sub(replace, template)
|
|
180
|
+
if "{" in filled or "}" in filled:
|
|
181
|
+
raise CarrierError(400, "invalid_path", "Operation path could not be filled.")
|
|
182
|
+
return filled
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _query_value(value: object) -> str:
|
|
186
|
+
if isinstance(value, bool):
|
|
187
|
+
return "true" if value else "false"
|
|
188
|
+
if isinstance(value, str):
|
|
189
|
+
return value
|
|
190
|
+
if isinstance(value, int):
|
|
191
|
+
return str(value)
|
|
192
|
+
raise CarrierError(400, "invalid_parameter", "Query values must be strings, integers, or booleans.")
|
carrier/py.typed
ADDED
|
File without changes
|
carrier/records.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Webhook, event, and usage objects."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from carrier.models import _bool, _int, _invalid, _number, _str
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class WebhookEndpoint:
|
|
9
|
+
"""A registered HTTPS endpoint. The signing secret is not included."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, id: str, object: str, url: str, status: str, created: int) -> None:
|
|
12
|
+
self.id = id
|
|
13
|
+
self.object = object
|
|
14
|
+
self.url = url
|
|
15
|
+
self.status = status
|
|
16
|
+
self.created = created
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def from_dict(cls, data: dict[str, Any]) -> "WebhookEndpoint":
|
|
20
|
+
return cls(
|
|
21
|
+
id=_str(data, "id"),
|
|
22
|
+
object=_str(data, "object"),
|
|
23
|
+
url=_str(data, "url"),
|
|
24
|
+
status=_str(data, "status"),
|
|
25
|
+
created=_int(data, "created"),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class WebhookEndpointCreated(WebhookEndpoint):
|
|
30
|
+
"""Create response. `secret` is returned once."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, id: str, object: str, url: str, status: str, created: int, secret: str) -> None:
|
|
33
|
+
super().__init__(id, object, url, status, created)
|
|
34
|
+
self.secret = secret
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_dict(cls, data: dict[str, Any]) -> "WebhookEndpointCreated":
|
|
38
|
+
base = WebhookEndpoint.from_dict(data)
|
|
39
|
+
return cls(base.id, base.object, base.url, base.status, base.created, _str(data, "secret"))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class DeletedWebhookEndpoint:
|
|
43
|
+
"""Result of removing a webhook endpoint."""
|
|
44
|
+
|
|
45
|
+
def __init__(self, id: str, object: str, deleted: bool) -> None:
|
|
46
|
+
self.id = id
|
|
47
|
+
self.object = object
|
|
48
|
+
self.deleted = deleted
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def from_dict(cls, data: dict[str, Any]) -> "DeletedWebhookEndpoint":
|
|
52
|
+
return cls(id=_str(data, "id"), object=_str(data, "object"), deleted=_bool(data, "deleted"))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ConnectivityEvent:
|
|
56
|
+
"""A connectivity event delivered to webhook endpoints."""
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
id: str,
|
|
61
|
+
object: str,
|
|
62
|
+
type: str,
|
|
63
|
+
livemode: bool,
|
|
64
|
+
created: int,
|
|
65
|
+
data: dict[str, Any],
|
|
66
|
+
) -> None:
|
|
67
|
+
self.id = id
|
|
68
|
+
self.object = object
|
|
69
|
+
self.type = type
|
|
70
|
+
self.livemode = livemode
|
|
71
|
+
self.created = created
|
|
72
|
+
self.data = data
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def from_dict(cls, data: dict[str, Any]) -> "ConnectivityEvent":
|
|
76
|
+
payload = data.get("data")
|
|
77
|
+
if not isinstance(payload, dict):
|
|
78
|
+
raise _invalid("data")
|
|
79
|
+
return cls(
|
|
80
|
+
id=_str(data, "id"),
|
|
81
|
+
object=_str(data, "object"),
|
|
82
|
+
type=_str(data, "type"),
|
|
83
|
+
livemode=_bool(data, "livemode"),
|
|
84
|
+
created=_int(data, "created"),
|
|
85
|
+
data=payload,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ConnectivityUsageRecord:
|
|
90
|
+
"""A usage line recorded against one intent."""
|
|
91
|
+
|
|
92
|
+
def __init__(
|
|
93
|
+
self,
|
|
94
|
+
id: str,
|
|
95
|
+
object: str,
|
|
96
|
+
intent: str,
|
|
97
|
+
quantity_mb: float,
|
|
98
|
+
livemode: bool,
|
|
99
|
+
created: int,
|
|
100
|
+
) -> None:
|
|
101
|
+
self.id = id
|
|
102
|
+
self.object = object
|
|
103
|
+
self.intent = intent
|
|
104
|
+
self.quantity_mb = quantity_mb
|
|
105
|
+
self.livemode = livemode
|
|
106
|
+
self.created = created
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def from_dict(cls, data: dict[str, Any]) -> "ConnectivityUsageRecord":
|
|
110
|
+
return cls(
|
|
111
|
+
id=_str(data, "id"),
|
|
112
|
+
object=_str(data, "object"),
|
|
113
|
+
intent=_str(data, "intent"),
|
|
114
|
+
quantity_mb=_number(data, "quantity_mb"),
|
|
115
|
+
livemode=_bool(data, "livemode"),
|
|
116
|
+
created=_int(data, "created"),
|
|
117
|
+
)
|