sendly 3.8.1__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.
@@ -0,0 +1,264 @@
1
+ """
2
+ Account Resource
3
+
4
+ Access account information, credit balance, and API keys.
5
+ """
6
+
7
+ from typing import Any, Dict, List, Optional
8
+
9
+ from ..types import Account, ApiKey, Credits, CreditTransaction
10
+ from ..utils.http import AsyncHttpClient, HttpClient
11
+
12
+
13
+ def _transform_response(data: Dict[str, Any], key_map: Dict[str, str]) -> Dict[str, Any]:
14
+ """Transform snake_case API response to camelCase for pydantic models."""
15
+ result = {}
16
+ for key, value in data.items():
17
+ new_key = key_map.get(key, key)
18
+ result[new_key] = value
19
+ return result
20
+
21
+
22
+ CREDITS_KEY_MAP = {
23
+ "reserved_balance": "reservedBalance",
24
+ "available_balance": "availableBalance",
25
+ }
26
+
27
+ TRANSACTION_KEY_MAP = {
28
+ "balance_after": "balanceAfter",
29
+ "message_id": "messageId",
30
+ "created_at": "createdAt",
31
+ }
32
+
33
+ API_KEY_MAP = {
34
+ "last_four": "lastFour",
35
+ "created_at": "createdAt",
36
+ "last_used_at": "lastUsedAt",
37
+ "expires_at": "expiresAt",
38
+ "is_revoked": "isRevoked",
39
+ }
40
+
41
+ ACCOUNT_KEY_MAP = {
42
+ "created_at": "createdAt",
43
+ }
44
+
45
+
46
+ class AccountResource:
47
+ """
48
+ Account API resource (synchronous)
49
+
50
+ Access account information, credit balance, and API keys.
51
+
52
+ Example:
53
+ >>> # Get credit balance
54
+ >>> credits = client.account.get_credits()
55
+ >>> print(f'Available: {credits.available_balance} credits')
56
+ >>>
57
+ >>> # Get transaction history
58
+ >>> transactions = client.account.get_credit_transactions()
59
+ >>>
60
+ >>> # List API keys
61
+ >>> keys = client.account.list_api_keys()
62
+ """
63
+
64
+ def __init__(self, http: HttpClient):
65
+ self._http = http
66
+
67
+ def get(self) -> Account:
68
+ """
69
+ Get account information.
70
+
71
+ Returns:
72
+ Account details
73
+ """
74
+ response = self._http.request("GET", "/account")
75
+ return Account(**_transform_response(response, ACCOUNT_KEY_MAP))
76
+
77
+ def get_credits(self) -> Credits:
78
+ """
79
+ Get credit balance.
80
+
81
+ Returns:
82
+ Current credit balance and reserved credits
83
+ """
84
+ response = self._http.request("GET", "/credits")
85
+ return Credits(**_transform_response(response, CREDITS_KEY_MAP))
86
+
87
+ def get_credit_transactions(
88
+ self, limit: Optional[int] = None, offset: Optional[int] = None
89
+ ) -> List[CreditTransaction]:
90
+ """
91
+ Get credit transaction history.
92
+
93
+ Args:
94
+ limit: Maximum number of transactions to return
95
+ offset: Number of transactions to skip
96
+
97
+ Returns:
98
+ Array of credit transactions
99
+ """
100
+ params = {}
101
+ if limit is not None:
102
+ params["limit"] = limit
103
+ if offset is not None:
104
+ params["offset"] = offset
105
+
106
+ response = self._http.request("GET", "/credits/transactions", params=params)
107
+ return [CreditTransaction(**_transform_response(t, TRANSACTION_KEY_MAP)) for t in response]
108
+
109
+ def list_api_keys(self) -> List[ApiKey]:
110
+ """
111
+ List API keys for the account.
112
+
113
+ Note: This returns key metadata, not the actual secret keys.
114
+
115
+ Returns:
116
+ Array of API keys
117
+ """
118
+ response = self._http.request("GET", "/keys")
119
+ return [ApiKey(**_transform_response(k, API_KEY_MAP)) for k in response]
120
+
121
+ def get_api_key(self, key_id: str) -> ApiKey:
122
+ """
123
+ Get a specific API key by ID.
124
+
125
+ Args:
126
+ key_id: API key ID
127
+
128
+ Returns:
129
+ API key details
130
+ """
131
+ response = self._http.request("GET", f"/keys/{key_id}")
132
+ return ApiKey(**_transform_response(response, API_KEY_MAP))
133
+
134
+ def get_api_key_usage(self, key_id: str) -> Dict[str, Any]:
135
+ """
136
+ Get usage statistics for an API key.
137
+
138
+ Args:
139
+ key_id: API key ID
140
+
141
+ Returns:
142
+ Usage statistics
143
+ """
144
+ response = self._http.request("GET", f"/keys/{key_id}/usage")
145
+ return response
146
+
147
+ def create_api_key(self, name: str, expires_at: Optional[str] = None) -> Dict[str, Any]:
148
+ """
149
+ Create a new API key.
150
+
151
+ Args:
152
+ name: Display name for the API key
153
+ expires_at: Optional expiration date (ISO 8601)
154
+
155
+ Returns:
156
+ Dict with 'apiKey' (ApiKey metadata) and 'key' (full secret key - only shown once)
157
+
158
+ Example:
159
+ >>> result = client.account.create_api_key('Production')
160
+ >>> print(f"Save this key: {result['key']}") # Only shown once!
161
+ """
162
+ if not name:
163
+ raise ValueError("API key name is required")
164
+
165
+ body: Dict[str, Any] = {"name": name}
166
+ if expires_at:
167
+ body["expiresAt"] = expires_at
168
+
169
+ response = self._http.request("POST", "/account/keys", body=body)
170
+ return response
171
+
172
+ def revoke_api_key(self, key_id: str) -> None:
173
+ """
174
+ Revoke an API key.
175
+
176
+ Args:
177
+ key_id: API key ID to revoke
178
+ """
179
+ if not key_id:
180
+ raise ValueError("API key ID is required")
181
+
182
+ self._http.request("DELETE", f"/account/keys/{key_id}")
183
+
184
+
185
+ class AsyncAccountResource:
186
+ """
187
+ Account API resource (asynchronous)
188
+
189
+ Async version of the account resource for use with asyncio.
190
+ """
191
+
192
+ def __init__(self, http: AsyncHttpClient):
193
+ self._http = http
194
+
195
+ async def get(self) -> Account:
196
+ """Get account information."""
197
+ response = await self._http.request("GET", "/account")
198
+ return Account(**_transform_response(response, ACCOUNT_KEY_MAP))
199
+
200
+ async def get_credits(self) -> Credits:
201
+ """Get credit balance."""
202
+ response = await self._http.request("GET", "/credits")
203
+ return Credits(**_transform_response(response, CREDITS_KEY_MAP))
204
+
205
+ async def get_credit_transactions(
206
+ self, limit: Optional[int] = None, offset: Optional[int] = None
207
+ ) -> List[CreditTransaction]:
208
+ """Get credit transaction history."""
209
+ params = {}
210
+ if limit is not None:
211
+ params["limit"] = limit
212
+ if offset is not None:
213
+ params["offset"] = offset
214
+
215
+ response = await self._http.request("GET", "/credits/transactions", params=params)
216
+ return [CreditTransaction(**_transform_response(t, TRANSACTION_KEY_MAP)) for t in response]
217
+
218
+ async def list_api_keys(self) -> List[ApiKey]:
219
+ """List API keys for the account."""
220
+ response = await self._http.request("GET", "/keys")
221
+ return [ApiKey(**_transform_response(k, API_KEY_MAP)) for k in response]
222
+
223
+ async def get_api_key(self, key_id: str) -> ApiKey:
224
+ """Get a specific API key by ID."""
225
+ response = await self._http.request("GET", f"/keys/{key_id}")
226
+ return ApiKey(**_transform_response(response, API_KEY_MAP))
227
+
228
+ async def get_api_key_usage(self, key_id: str) -> Dict[str, Any]:
229
+ """Get usage statistics for an API key."""
230
+ response = await self._http.request("GET", f"/keys/{key_id}/usage")
231
+ return response
232
+
233
+ async def create_api_key(self, name: str, expires_at: Optional[str] = None) -> Dict[str, Any]:
234
+ """
235
+ Create a new API key (async).
236
+
237
+ Args:
238
+ name: Display name for the API key
239
+ expires_at: Optional expiration date (ISO 8601)
240
+
241
+ Returns:
242
+ Dict with 'apiKey' (ApiKey metadata) and 'key' (full secret key - only shown once)
243
+ """
244
+ if not name:
245
+ raise ValueError("API key name is required")
246
+
247
+ body: Dict[str, Any] = {"name": name}
248
+ if expires_at:
249
+ body["expiresAt"] = expires_at
250
+
251
+ response = await self._http.request("POST", "/account/keys", body=body)
252
+ return response
253
+
254
+ async def revoke_api_key(self, key_id: str) -> None:
255
+ """
256
+ Revoke an API key (async).
257
+
258
+ Args:
259
+ key_id: API key ID to revoke
260
+ """
261
+ if not key_id:
262
+ raise ValueError("API key ID is required")
263
+
264
+ await self._http.request("DELETE", f"/account/keys/{key_id}")