freescout-api 0.1.0__tar.gz

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.
Files changed (35) hide show
  1. freescout_api-0.1.0/LICENSE +21 -0
  2. freescout_api-0.1.0/PKG-INFO +393 -0
  3. freescout_api-0.1.0/README.md +362 -0
  4. freescout_api-0.1.0/pyproject.toml +66 -0
  5. freescout_api-0.1.0/setup.cfg +4 -0
  6. freescout_api-0.1.0/src/freescout/__init__.py +55 -0
  7. freescout_api-0.1.0/src/freescout/_transport.py +344 -0
  8. freescout_api-0.1.0/src/freescout/_version.py +3 -0
  9. freescout_api-0.1.0/src/freescout/client.py +168 -0
  10. freescout_api-0.1.0/src/freescout/enums.py +165 -0
  11. freescout_api-0.1.0/src/freescout/exceptions.py +100 -0
  12. freescout_api-0.1.0/src/freescout/models.py +451 -0
  13. freescout_api-0.1.0/src/freescout/resources/__init__.py +19 -0
  14. freescout_api-0.1.0/src/freescout/resources/base.py +18 -0
  15. freescout_api-0.1.0/src/freescout/resources/conversations.py +304 -0
  16. freescout_api-0.1.0/src/freescout/resources/customers.py +235 -0
  17. freescout_api-0.1.0/src/freescout/resources/mailboxes.py +74 -0
  18. freescout_api-0.1.0/src/freescout/resources/tags.py +40 -0
  19. freescout_api-0.1.0/src/freescout/resources/threads.py +84 -0
  20. freescout_api-0.1.0/src/freescout/resources/users.py +114 -0
  21. freescout_api-0.1.0/src/freescout/resources/webhooks.py +72 -0
  22. freescout_api-0.1.0/src/freescout_api.egg-info/PKG-INFO +393 -0
  23. freescout_api-0.1.0/src/freescout_api.egg-info/SOURCES.txt +33 -0
  24. freescout_api-0.1.0/src/freescout_api.egg-info/dependency_links.txt +1 -0
  25. freescout_api-0.1.0/src/freescout_api.egg-info/requires.txt +9 -0
  26. freescout_api-0.1.0/src/freescout_api.egg-info/top_level.txt +1 -0
  27. freescout_api-0.1.0/tests/test_client.py +116 -0
  28. freescout_api-0.1.0/tests/test_conversations.py +275 -0
  29. freescout_api-0.1.0/tests/test_customers.py +185 -0
  30. freescout_api-0.1.0/tests/test_exceptions.py +136 -0
  31. freescout_api-0.1.0/tests/test_mailboxes.py +160 -0
  32. freescout_api-0.1.0/tests/test_tags.py +83 -0
  33. freescout_api-0.1.0/tests/test_threads.py +126 -0
  34. freescout_api-0.1.0/tests/test_users.py +142 -0
  35. freescout_api-0.1.0/tests/test_webhooks.py +104 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jacobb84
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,393 @@
1
+ Metadata-Version: 2.4
2
+ Name: freescout-api
3
+ Version: 0.1.0
4
+ Summary: Python client library for the FreeScout API
5
+ Author: Jacob Bell
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/jacobb84/freescout-api
8
+ Project-URL: Documentation, https://github.com/jacobb84/freescout-api#readme
9
+ Project-URL: Repository, https://github.com/jacobb84/freescout-api
10
+ Project-URL: Issues, https://github.com/jacobb84/freescout-api/issues
11
+ Keywords: freescout,api,helpdesk,support,client
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.12
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: requests>=2.31.0
23
+ Requires-Dist: pydantic>=2.0.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
26
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
27
+ Requires-Dist: responses>=0.23.0; extra == "dev"
28
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
29
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
30
+ Dynamic: license-file
31
+
32
+ # FreeScout API Python Client
33
+
34
+ A Python client library for the [FreeScout](https://freescout.net/) helpdesk API.
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ pip install freescout-api
40
+ ```
41
+
42
+ ## Quick Start
43
+
44
+ ```python
45
+ from freescout import FreeScoutClient
46
+
47
+ # Initialize the client using environment variables
48
+ # Set FREESCOUT_URL and FREESCOUT_API_KEY in your environment
49
+ client = FreeScoutClient()
50
+
51
+ # Or provide credentials directly
52
+ client = FreeScoutClient(
53
+ base_url="https://support.example.com",
54
+ api_key="your-api-key"
55
+ )
56
+
57
+ # List conversations
58
+ conversations = client.conversations.list(mailbox_id=1)
59
+ for conv in conversations.conversations:
60
+ print(f"{conv.id}: {conv.subject}")
61
+
62
+ # Get a specific conversation with threads
63
+ conversation = client.conversations.get(123, embed="threads")
64
+ print(conversation.subject)
65
+ for thread in conversation.embedded.threads:
66
+ print(f" - {thread.body}")
67
+ ```
68
+
69
+ ## Configuration
70
+
71
+ The client can be configured using environment variables or constructor arguments:
72
+
73
+ | Environment Variable | Constructor Argument | Description |
74
+ |---------------------|---------------------|-------------|
75
+ | `FREESCOUT_URL` | `base_url` | Base URL of your FreeScout instance |
76
+ | `FREESCOUT_API_KEY` | `api_key` | API key from Manage » API & Webhooks |
77
+
78
+ Additional constructor options:
79
+ - `timeout`: Request timeout in seconds (default: 30)
80
+ - `max_retries`: Maximum retry attempts for failed requests (default: 3)
81
+
82
+ ## Resources
83
+
84
+ ### Conversations
85
+
86
+ ```python
87
+ from freescout import ConversationStatus, ConversationType, ThreadType
88
+
89
+ # List conversations with filters
90
+ conversations = client.conversations.list(
91
+ mailbox_id=1,
92
+ status=ConversationStatus.ACTIVE,
93
+ assigned_to=5,
94
+ page=1,
95
+ page_size=50,
96
+ )
97
+
98
+ # Get a single conversation
99
+ conversation = client.conversations.get(123, embed="threads")
100
+
101
+ # Create a conversation
102
+ conv_id = client.conversations.create(
103
+ mailbox_id=1,
104
+ subject="New Support Request",
105
+ customer={"email": "customer@example.com"},
106
+ threads=[
107
+ {
108
+ "type": "customer",
109
+ "text": "I need help with my order.",
110
+ }
111
+ ],
112
+ type=ConversationType.EMAIL,
113
+ status=ConversationStatus.ACTIVE,
114
+ )
115
+
116
+ # Update a conversation
117
+ client.conversations.update(
118
+ 123,
119
+ status=ConversationStatus.CLOSED,
120
+ assign_to=5,
121
+ )
122
+
123
+ # Delete a conversation
124
+ client.conversations.delete(123)
125
+
126
+ # Update custom fields
127
+ client.conversations.update_custom_fields(
128
+ 123,
129
+ custom_fields=[{"id": 37, "value": "High Priority"}],
130
+ )
131
+
132
+ # Update tags
133
+ client.conversations.update_tags(123, tags=["urgent", "billing"])
134
+
135
+ # List timelogs
136
+ timelogs = client.conversations.list_timelogs(123)
137
+ ```
138
+
139
+ ### Threads
140
+
141
+ ```python
142
+ from freescout import ThreadType, ConversationStatus
143
+
144
+ # Add a reply from an agent
145
+ thread_id = client.threads.create(
146
+ conversation_id=123,
147
+ type=ThreadType.MESSAGE,
148
+ text="Thank you for contacting us. We'll look into this.",
149
+ user=5, # User ID of the agent
150
+ status=ConversationStatus.PENDING, # Optionally change conversation status
151
+ )
152
+
153
+ # Add a customer reply
154
+ thread_id = client.threads.create(
155
+ conversation_id=123,
156
+ type=ThreadType.CUSTOMER,
157
+ text="Thanks for your help!",
158
+ customer={"email": "customer@example.com"},
159
+ )
160
+
161
+ # Add an internal note
162
+ thread_id = client.threads.create(
163
+ conversation_id=123,
164
+ type=ThreadType.NOTE,
165
+ text="Customer is a VIP - handle with care.",
166
+ user=5,
167
+ )
168
+
169
+ # Add a reply with attachments
170
+ thread_id = client.threads.create(
171
+ conversation_id=123,
172
+ type=ThreadType.MESSAGE,
173
+ text="Please see the attached document.",
174
+ user=5,
175
+ attachments=[
176
+ {
177
+ "fileName": "invoice.pdf",
178
+ "mimeType": "application/pdf",
179
+ "data": "base64_encoded_content", # Base64 encoded file
180
+ },
181
+ {
182
+ "fileName": "image.png",
183
+ "mimeType": "image/png",
184
+ "fileUrl": "https://example.com/image.png", # Or provide a URL
185
+ },
186
+ ],
187
+ )
188
+ ```
189
+
190
+ ### Customers
191
+
192
+ ```python
193
+ # List customers
194
+ customers = client.customers.list(
195
+ email="john@example.com",
196
+ first_name="John",
197
+ )
198
+
199
+ # Get a customer
200
+ customer = client.customers.get(75)
201
+
202
+ # Create a customer
203
+ customer_id = client.customers.create(
204
+ first_name="John",
205
+ last_name="Doe",
206
+ emails=[{"value": "john@example.com", "type": "work"}],
207
+ phones=[{"value": "+1234567890", "type": "mobile"}],
208
+ company="ACME Corp",
209
+ address={
210
+ "city": "New York",
211
+ "state": "NY",
212
+ "zip": "10001",
213
+ "country": "US",
214
+ "address": "123 Main St",
215
+ },
216
+ )
217
+
218
+ # Update a customer
219
+ client.customers.update(
220
+ 75,
221
+ first_name="Jonathan",
222
+ company="New Company Inc",
223
+ )
224
+
225
+ # Update customer custom fields
226
+ client.customers.update_fields(
227
+ 75,
228
+ customer_fields=[{"id": 11, "value": "Premium"}],
229
+ )
230
+ ```
231
+
232
+ ### Users
233
+
234
+ ```python
235
+ # List users
236
+ users = client.users.list()
237
+
238
+ # Get a user
239
+ user = client.users.get(1)
240
+
241
+ # Create a user
242
+ user_id = client.users.create(
243
+ first_name="Jane",
244
+ last_name="Smith",
245
+ email="jane@example.com",
246
+ password="secure_password",
247
+ job_title="Support Agent",
248
+ timezone="America/New_York",
249
+ )
250
+
251
+ # Delete a user
252
+ client.users.delete(17)
253
+ ```
254
+
255
+ ### Mailboxes
256
+
257
+ ```python
258
+ # List all mailboxes
259
+ mailboxes = client.mailboxes.list()
260
+
261
+ # List mailboxes for a specific user
262
+ mailboxes = client.mailboxes.list(user_id=5)
263
+
264
+ # List custom fields for a mailbox
265
+ custom_fields = client.mailboxes.list_custom_fields(1)
266
+
267
+ # List folders for a mailbox
268
+ folders = client.mailboxes.list_folders(1)
269
+ ```
270
+
271
+ ### Tags
272
+
273
+ ```python
274
+ # List all tags
275
+ tags = client.tags.list()
276
+
277
+ # List tags for a specific conversation
278
+ tags = client.tags.list(conversation_id=123)
279
+ ```
280
+
281
+ ### Webhooks
282
+
283
+ ```python
284
+ from freescout import WebhookEvent
285
+
286
+ # List webhooks
287
+ webhooks = client.webhooks.list()
288
+
289
+ # Create a webhook
290
+ webhook_id = client.webhooks.create(
291
+ url="https://example.com/webhook",
292
+ events=[
293
+ WebhookEvent.CONVO_CREATED,
294
+ WebhookEvent.CONVO_CUSTOMER_REPLY,
295
+ ],
296
+ mailboxes=[1, 2], # Optional: limit to specific mailboxes
297
+ )
298
+
299
+ # Delete a webhook
300
+ client.webhooks.delete(17)
301
+ ```
302
+
303
+ ## Enums
304
+
305
+ The library provides StrEnums for type-safe parameter values:
306
+
307
+ ```python
308
+ from freescout import (
309
+ ConversationType, # email, phone, chat
310
+ ConversationStatus, # active, pending, closed, spam
311
+ ConversationState, # draft, published, deleted
312
+ ThreadType, # customer, message, note
313
+ ThreadState, # draft, published
314
+ SortOrder, # asc, desc
315
+ SortField, # createdAt, updatedAt
316
+ CustomerSortField, # createdAt, updatedAt, firstName, lastName
317
+ EmailType, # home, work, other
318
+ PhoneType, # home, work, mobile, fax, pager, other
319
+ SocialProfileType, # twitter, facebook, linkedin, etc.
320
+ PhotoType, # gravatar, unknown, upload
321
+ FolderType, # unassigned, mine, starred, drafts, etc.
322
+ WebhookEvent, # convo.created, convo.assigned, etc.
323
+ )
324
+ ```
325
+
326
+ ## Error Handling
327
+
328
+ The library raises specific exceptions for different error types:
329
+
330
+ ```python
331
+ from freescout.exceptions import (
332
+ FreeScoutError, # Base exception
333
+ AuthenticationError, # 401 Unauthorized
334
+ ForbiddenError, # 403 Forbidden
335
+ NotFoundError, # 404 Not Found
336
+ ValidationError, # 400 Bad Request
337
+ ConflictError, # 409 Conflict
338
+ RateLimitError, # 429 Too Many Requests
339
+ ServerError, # 5xx errors
340
+ )
341
+
342
+ try:
343
+ conversation = client.conversations.get(999)
344
+ except NotFoundError as e:
345
+ print(f"Conversation not found: {e}")
346
+ except AuthenticationError as e:
347
+ print(f"Invalid API key: {e}")
348
+ except ValidationError as e:
349
+ print(f"Validation failed: {e}")
350
+ for error in e.errors:
351
+ print(f" - {error['path']}: {error['message']}")
352
+ ```
353
+
354
+ ## Development
355
+
356
+ ### Setup
357
+
358
+ ```bash
359
+ # Clone the repository
360
+ git clone https://github.com/yourusername/freescout-api.git
361
+ cd freescout-api
362
+
363
+ # Create a virtual environment
364
+ python -m venv .venv
365
+ .venv\Scripts\activate # Windows
366
+ # source .venv/bin/activate # Linux/Mac
367
+
368
+ # Install development dependencies
369
+ pip install -e ".[dev]"
370
+ ```
371
+
372
+ ### Running Tests
373
+
374
+ ```bash
375
+ pytest
376
+ pytest --cov=freescout # With coverage
377
+ ```
378
+
379
+ ### Code Quality
380
+
381
+ ```bash
382
+ ruff check src tests
383
+ mypy src
384
+ ```
385
+
386
+ ## License
387
+
388
+ MIT License - see [LICENSE](LICENSE) for details.
389
+
390
+ ## Links
391
+
392
+ - [FreeScout](https://freescout.net/)
393
+ - [FreeScout API Documentation](https://api-docs.freescout.net/)