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.
- freescout_api-0.1.0/LICENSE +21 -0
- freescout_api-0.1.0/PKG-INFO +393 -0
- freescout_api-0.1.0/README.md +362 -0
- freescout_api-0.1.0/pyproject.toml +66 -0
- freescout_api-0.1.0/setup.cfg +4 -0
- freescout_api-0.1.0/src/freescout/__init__.py +55 -0
- freescout_api-0.1.0/src/freescout/_transport.py +344 -0
- freescout_api-0.1.0/src/freescout/_version.py +3 -0
- freescout_api-0.1.0/src/freescout/client.py +168 -0
- freescout_api-0.1.0/src/freescout/enums.py +165 -0
- freescout_api-0.1.0/src/freescout/exceptions.py +100 -0
- freescout_api-0.1.0/src/freescout/models.py +451 -0
- freescout_api-0.1.0/src/freescout/resources/__init__.py +19 -0
- freescout_api-0.1.0/src/freescout/resources/base.py +18 -0
- freescout_api-0.1.0/src/freescout/resources/conversations.py +304 -0
- freescout_api-0.1.0/src/freescout/resources/customers.py +235 -0
- freescout_api-0.1.0/src/freescout/resources/mailboxes.py +74 -0
- freescout_api-0.1.0/src/freescout/resources/tags.py +40 -0
- freescout_api-0.1.0/src/freescout/resources/threads.py +84 -0
- freescout_api-0.1.0/src/freescout/resources/users.py +114 -0
- freescout_api-0.1.0/src/freescout/resources/webhooks.py +72 -0
- freescout_api-0.1.0/src/freescout_api.egg-info/PKG-INFO +393 -0
- freescout_api-0.1.0/src/freescout_api.egg-info/SOURCES.txt +33 -0
- freescout_api-0.1.0/src/freescout_api.egg-info/dependency_links.txt +1 -0
- freescout_api-0.1.0/src/freescout_api.egg-info/requires.txt +9 -0
- freescout_api-0.1.0/src/freescout_api.egg-info/top_level.txt +1 -0
- freescout_api-0.1.0/tests/test_client.py +116 -0
- freescout_api-0.1.0/tests/test_conversations.py +275 -0
- freescout_api-0.1.0/tests/test_customers.py +185 -0
- freescout_api-0.1.0/tests/test_exceptions.py +136 -0
- freescout_api-0.1.0/tests/test_mailboxes.py +160 -0
- freescout_api-0.1.0/tests/test_tags.py +83 -0
- freescout_api-0.1.0/tests/test_threads.py +126 -0
- freescout_api-0.1.0/tests/test_users.py +142 -0
- 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/)
|