python-zendesk-sdk 0.1.0__tar.gz → 0.1.2__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 (38) hide show
  1. python_zendesk_sdk-0.1.2/PKG-INFO +283 -0
  2. python_zendesk_sdk-0.1.2/README.md +246 -0
  3. python_zendesk_sdk-0.1.2/examples/basic_usage.py +62 -0
  4. python_zendesk_sdk-0.1.2/examples/enriched_tickets.py +86 -0
  5. python_zendesk_sdk-0.1.2/examples/error_handling.py +108 -0
  6. python_zendesk_sdk-0.1.2/examples/pagination_example.py +66 -0
  7. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/pyproject.toml +1 -1
  8. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/__init__.py +3 -1
  9. python_zendesk_sdk-0.1.2/src/zendesk_sdk/client.py +862 -0
  10. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/config.py +7 -28
  11. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/http_client.py +12 -2
  12. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/models/__init__.py +3 -0
  13. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/models/comment.py +1 -1
  14. python_zendesk_sdk-0.1.2/src/zendesk_sdk/models/enriched_ticket.py +57 -0
  15. python_zendesk_sdk-0.1.2/tests/test_client.py +1015 -0
  16. python_zendesk_sdk-0.1.2/tests/test_config.py +92 -0
  17. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/tests/test_http_client.py +0 -6
  18. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/tests/test_models.py +158 -0
  19. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/tests/test_package_import.py +1 -2
  20. python_zendesk_sdk-0.1.0/PKG-INFO +0 -218
  21. python_zendesk_sdk-0.1.0/README.md +0 -181
  22. python_zendesk_sdk-0.1.0/src/zendesk_sdk/client.py +0 -321
  23. python_zendesk_sdk-0.1.0/tests/test_client.py +0 -439
  24. python_zendesk_sdk-0.1.0/tests/test_config.py +0 -52
  25. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/.flake8 +0 -0
  26. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/.github/workflows/publish.yml +0 -0
  27. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/.gitignore +0 -0
  28. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/.python-version +0 -0
  29. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/LICENSE +0 -0
  30. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/exceptions.py +0 -0
  31. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/models/base.py +0 -0
  32. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/models/organization.py +0 -0
  33. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/models/ticket.py +0 -0
  34. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/models/user.py +0 -0
  35. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/src/zendesk_sdk/pagination.py +0 -0
  36. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/tests/__init__.py +0 -0
  37. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/tests/test_exceptions.py +0 -0
  38. {python_zendesk_sdk-0.1.0 → python_zendesk_sdk-0.1.2}/tests/test_pagination.py +0 -0
@@ -0,0 +1,283 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-zendesk-sdk
3
+ Version: 0.1.2
4
+ Summary: Modern Python SDK for Zendesk API
5
+ Project-URL: Homepage, https://github.com/bormog/python-zendesk-sdk
6
+ Project-URL: Repository, https://github.com/bormog/python-zendesk-sdk
7
+ Project-URL: Issues, https://github.com/bormog/python-zendesk-sdk/issues
8
+ Author: bormog
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: api,client,sdk,zendesk
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.8.1
25
+ Requires-Dist: httpx>=0.25.0
26
+ Requires-Dist: pydantic>=2.0.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: black>=23.0.0; extra == 'dev'
29
+ Requires-Dist: flake8>=6.0.0; extra == 'dev'
30
+ Requires-Dist: isort>=5.12.0; extra == 'dev'
31
+ Requires-Dist: mypy>=1.5.0; extra == 'dev'
32
+ Requires-Dist: pre-commit>=3.0.0; extra == 'dev'
33
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
34
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
35
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
36
+ Description-Content-Type: text/markdown
37
+
38
+ # Python Zendesk SDK
39
+
40
+ Modern Python SDK for Zendesk API with async support, full type safety, and comprehensive error handling.
41
+
42
+ ## Features
43
+
44
+ - **Async HTTP Client**: Built on httpx with retry logic, rate limiting, and exponential backoff
45
+ - **Type Safety**: Full Pydantic v2 models for Users, Organizations, Tickets, and Comments
46
+ - **Pagination**: Both offset-based and cursor-based pagination support
47
+ - **Search**: Zendesk search API support
48
+ - **Configuration**: Flexible configuration with environment variable support
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install python-zendesk-sdk
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ ```python
59
+ import asyncio
60
+ from zendesk_sdk import ZendeskClient, ZendeskConfig
61
+
62
+ async def main():
63
+ config = ZendeskConfig(
64
+ subdomain="your-subdomain",
65
+ email="your-email@example.com",
66
+ token="your-api-token",
67
+ )
68
+
69
+ async with ZendeskClient(config) as client:
70
+ # Get users with pagination
71
+ users_paginator = await client.get_users(per_page=10)
72
+ users = await users_paginator.get_page()
73
+
74
+ for user in users:
75
+ print(f"User: {user.name} ({user.email})")
76
+
77
+ # Get specific ticket
78
+ ticket = await client.get_ticket(ticket_id=12345)
79
+ print(f"Ticket: {ticket.subject}")
80
+
81
+ # Search tickets
82
+ results = await client.search_tickets("status:open priority:high")
83
+ for ticket in results:
84
+ print(f"High priority: {ticket.subject}")
85
+
86
+ asyncio.run(main())
87
+ ```
88
+
89
+ ## Configuration
90
+
91
+ ### Direct instantiation
92
+ ```python
93
+ config = ZendeskConfig(
94
+ subdomain="mycompany",
95
+ email="user@example.com",
96
+ token="api_token_here"
97
+ )
98
+ ```
99
+
100
+ ### Environment variables
101
+ ```bash
102
+ export ZENDESK_SUBDOMAIN=mycompany
103
+ export ZENDESK_EMAIL=user@example.com
104
+ export ZENDESK_TOKEN=api_token_here
105
+ ```
106
+
107
+ ```python
108
+ config = ZendeskConfig() # Will load from environment
109
+ ```
110
+
111
+ ## API Methods
112
+
113
+ ### Users
114
+ - `get_users()` - List users with pagination
115
+ - `get_user(user_id)` - Get user by ID
116
+ - `get_user_by_email(email)` - Get user by email
117
+
118
+ ### Organizations
119
+ - `get_organizations()` - List organizations with pagination
120
+ - `get_organization(organization_id)` - Get organization by ID
121
+
122
+ ### Tickets
123
+ - `get_tickets()` - List tickets with pagination
124
+ - `get_ticket(ticket_id)` - Get ticket by ID
125
+ - `get_user_tickets(user_id)` - Get tickets for a user
126
+ - `get_organization_tickets(organization_id)` - Get tickets for an organization
127
+
128
+ ### Enriched Tickets
129
+
130
+ Load tickets with all related data (comments + users) in minimum API requests:
131
+
132
+ - `get_enriched_ticket(ticket_id)` - Get ticket with comments and all users
133
+ - `search_enriched_tickets(query)` - Search tickets with all related data
134
+ - `get_organization_enriched_tickets(org_id)` - Get organization tickets with all data
135
+ - `get_user_enriched_tickets(user_id)` - Get user tickets with all data
136
+
137
+ ```python
138
+ # Get ticket with all related data
139
+ enriched = await client.get_enriched_ticket(12345)
140
+
141
+ print(f"Ticket: {enriched.ticket.subject}")
142
+ print(f"Requester: {enriched.requester.name}")
143
+ print(f"Assignee: {enriched.assignee.name if enriched.assignee else 'Unassigned'}")
144
+
145
+ for comment in enriched.comments:
146
+ author = enriched.get_comment_author(comment)
147
+ print(f"Comment by {author.name}: {comment.body[:50]}...")
148
+
149
+ # Search with all data loaded
150
+ results = await client.search_enriched_tickets("status:open")
151
+ for item in results:
152
+ print(f"{item.ticket.subject} - {len(item.comments)} comments")
153
+ ```
154
+
155
+ ### Comments
156
+ - `get_ticket_comments(ticket_id)` - Get comments for a ticket
157
+ - `add_ticket_comment(ticket_id, body, public=False)` - Add a comment (private by default)
158
+ - `make_comment_private(ticket_id, comment_id)` - Convert public comment to internal note
159
+ - `redact_comment_string(ticket_id, comment_id, text)` - Permanently redact text from comment
160
+
161
+ ### Tags
162
+ - `get_ticket_tags(ticket_id)` - Get all tags for a ticket
163
+ - `add_ticket_tags(ticket_id, tags)` - Add tags without removing existing ones
164
+ - `set_ticket_tags(ticket_id, tags)` - Replace all tags with a new set
165
+ - `remove_ticket_tags(ticket_id, tags)` - Remove specific tags
166
+
167
+ ```python
168
+ # Get current tags
169
+ tags = await client.get_ticket_tags(12345)
170
+ # ["billing", "urgent"]
171
+
172
+ # Add new tags (keeps existing)
173
+ tags = await client.add_ticket_tags(12345, ["vip"])
174
+ # ["billing", "urgent", "vip"]
175
+
176
+ # Replace all tags
177
+ tags = await client.set_ticket_tags(12345, ["support", "priority"])
178
+ # ["support", "priority"]
179
+
180
+ # Remove specific tags
181
+ tags = await client.remove_ticket_tags(12345, ["priority"])
182
+ # ["support"]
183
+ ```
184
+
185
+ ### Attachments
186
+ - `download_attachment(content_url)` - Download attachment content as bytes
187
+ - `upload_attachment(data, filename, content_type)` - Upload file and get token
188
+
189
+ ```python
190
+ # Download an attachment from a comment
191
+ comments = await client.get_ticket_comments(12345)
192
+ for comment in comments:
193
+ for attachment in comment.attachments or []:
194
+ content = await client.download_attachment(attachment.content_url)
195
+ with open(attachment.file_name, "wb") as f:
196
+ f.write(content)
197
+
198
+ # Upload a file and attach to a comment
199
+ with open("screenshot.png", "rb") as f:
200
+ token = await client.upload_attachment(
201
+ f.read(),
202
+ "screenshot.png",
203
+ "image/png"
204
+ )
205
+
206
+ await client.add_ticket_comment(
207
+ ticket_id=12345,
208
+ body="See attached screenshot",
209
+ uploads=[token]
210
+ )
211
+ ```
212
+
213
+ ### Search
214
+ - `search(query)` - General search
215
+ - `search_users(query)` - Search users
216
+ - `search_tickets(query)` - Search tickets
217
+ - `search_organizations(query)` - Search organizations
218
+
219
+ ## Error Handling
220
+
221
+ The SDK provides specific exception classes for different error types:
222
+
223
+ ```python
224
+ from zendesk_sdk.exceptions import (
225
+ ZendeskAuthException,
226
+ ZendeskHTTPException,
227
+ ZendeskRateLimitException,
228
+ ZendeskTimeoutException,
229
+ ZendeskValidationException,
230
+ )
231
+
232
+ async with ZendeskClient(config) as client:
233
+ try:
234
+ user = await client.get_user(user_id=12345)
235
+ except ZendeskAuthException as e:
236
+ # 401/403 - Authentication failed
237
+ print(f"Auth error: {e.message}")
238
+ except ZendeskRateLimitException as e:
239
+ # 429 - Rate limit exceeded
240
+ print(f"Rate limited, retry after: {e.retry_after}s")
241
+ except ZendeskHTTPException as e:
242
+ # Other HTTP errors (404, 500, etc.)
243
+ print(f"HTTP {e.status_code}: {e.message}")
244
+ except ZendeskTimeoutException as e:
245
+ # Request timeout
246
+ print(f"Timeout: {e.message}")
247
+ ```
248
+
249
+ ### Automatic Retry
250
+
251
+ The SDK automatically retries on:
252
+ - Rate limiting (429) - with respect to `Retry-After` header
253
+ - Server errors (5xx) - with exponential backoff
254
+ - Network errors and timeouts
255
+
256
+ Configure retry behavior:
257
+ ```python
258
+ config = ZendeskConfig(
259
+ subdomain="mycompany",
260
+ email="user@example.com",
261
+ token="api_token",
262
+ timeout=30.0, # Request timeout in seconds
263
+ max_retries=3, # Number of retry attempts
264
+ )
265
+ ```
266
+
267
+ ## Examples
268
+
269
+ See the `examples/` directory for complete usage examples:
270
+ - `basic_usage.py` - Basic configuration and API operations
271
+ - `pagination_example.py` - Working with paginated results
272
+ - `error_handling.py` - Error handling patterns
273
+ - `enriched_tickets.py` - Loading tickets with related data
274
+
275
+ ## Requirements
276
+
277
+ - Python 3.8+
278
+ - httpx
279
+ - pydantic >=2.0
280
+
281
+ ## License
282
+
283
+ MIT License
@@ -0,0 +1,246 @@
1
+ # Python Zendesk SDK
2
+
3
+ Modern Python SDK for Zendesk API with async support, full type safety, and comprehensive error handling.
4
+
5
+ ## Features
6
+
7
+ - **Async HTTP Client**: Built on httpx with retry logic, rate limiting, and exponential backoff
8
+ - **Type Safety**: Full Pydantic v2 models for Users, Organizations, Tickets, and Comments
9
+ - **Pagination**: Both offset-based and cursor-based pagination support
10
+ - **Search**: Zendesk search API support
11
+ - **Configuration**: Flexible configuration with environment variable support
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pip install python-zendesk-sdk
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```python
22
+ import asyncio
23
+ from zendesk_sdk import ZendeskClient, ZendeskConfig
24
+
25
+ async def main():
26
+ config = ZendeskConfig(
27
+ subdomain="your-subdomain",
28
+ email="your-email@example.com",
29
+ token="your-api-token",
30
+ )
31
+
32
+ async with ZendeskClient(config) as client:
33
+ # Get users with pagination
34
+ users_paginator = await client.get_users(per_page=10)
35
+ users = await users_paginator.get_page()
36
+
37
+ for user in users:
38
+ print(f"User: {user.name} ({user.email})")
39
+
40
+ # Get specific ticket
41
+ ticket = await client.get_ticket(ticket_id=12345)
42
+ print(f"Ticket: {ticket.subject}")
43
+
44
+ # Search tickets
45
+ results = await client.search_tickets("status:open priority:high")
46
+ for ticket in results:
47
+ print(f"High priority: {ticket.subject}")
48
+
49
+ asyncio.run(main())
50
+ ```
51
+
52
+ ## Configuration
53
+
54
+ ### Direct instantiation
55
+ ```python
56
+ config = ZendeskConfig(
57
+ subdomain="mycompany",
58
+ email="user@example.com",
59
+ token="api_token_here"
60
+ )
61
+ ```
62
+
63
+ ### Environment variables
64
+ ```bash
65
+ export ZENDESK_SUBDOMAIN=mycompany
66
+ export ZENDESK_EMAIL=user@example.com
67
+ export ZENDESK_TOKEN=api_token_here
68
+ ```
69
+
70
+ ```python
71
+ config = ZendeskConfig() # Will load from environment
72
+ ```
73
+
74
+ ## API Methods
75
+
76
+ ### Users
77
+ - `get_users()` - List users with pagination
78
+ - `get_user(user_id)` - Get user by ID
79
+ - `get_user_by_email(email)` - Get user by email
80
+
81
+ ### Organizations
82
+ - `get_organizations()` - List organizations with pagination
83
+ - `get_organization(organization_id)` - Get organization by ID
84
+
85
+ ### Tickets
86
+ - `get_tickets()` - List tickets with pagination
87
+ - `get_ticket(ticket_id)` - Get ticket by ID
88
+ - `get_user_tickets(user_id)` - Get tickets for a user
89
+ - `get_organization_tickets(organization_id)` - Get tickets for an organization
90
+
91
+ ### Enriched Tickets
92
+
93
+ Load tickets with all related data (comments + users) in minimum API requests:
94
+
95
+ - `get_enriched_ticket(ticket_id)` - Get ticket with comments and all users
96
+ - `search_enriched_tickets(query)` - Search tickets with all related data
97
+ - `get_organization_enriched_tickets(org_id)` - Get organization tickets with all data
98
+ - `get_user_enriched_tickets(user_id)` - Get user tickets with all data
99
+
100
+ ```python
101
+ # Get ticket with all related data
102
+ enriched = await client.get_enriched_ticket(12345)
103
+
104
+ print(f"Ticket: {enriched.ticket.subject}")
105
+ print(f"Requester: {enriched.requester.name}")
106
+ print(f"Assignee: {enriched.assignee.name if enriched.assignee else 'Unassigned'}")
107
+
108
+ for comment in enriched.comments:
109
+ author = enriched.get_comment_author(comment)
110
+ print(f"Comment by {author.name}: {comment.body[:50]}...")
111
+
112
+ # Search with all data loaded
113
+ results = await client.search_enriched_tickets("status:open")
114
+ for item in results:
115
+ print(f"{item.ticket.subject} - {len(item.comments)} comments")
116
+ ```
117
+
118
+ ### Comments
119
+ - `get_ticket_comments(ticket_id)` - Get comments for a ticket
120
+ - `add_ticket_comment(ticket_id, body, public=False)` - Add a comment (private by default)
121
+ - `make_comment_private(ticket_id, comment_id)` - Convert public comment to internal note
122
+ - `redact_comment_string(ticket_id, comment_id, text)` - Permanently redact text from comment
123
+
124
+ ### Tags
125
+ - `get_ticket_tags(ticket_id)` - Get all tags for a ticket
126
+ - `add_ticket_tags(ticket_id, tags)` - Add tags without removing existing ones
127
+ - `set_ticket_tags(ticket_id, tags)` - Replace all tags with a new set
128
+ - `remove_ticket_tags(ticket_id, tags)` - Remove specific tags
129
+
130
+ ```python
131
+ # Get current tags
132
+ tags = await client.get_ticket_tags(12345)
133
+ # ["billing", "urgent"]
134
+
135
+ # Add new tags (keeps existing)
136
+ tags = await client.add_ticket_tags(12345, ["vip"])
137
+ # ["billing", "urgent", "vip"]
138
+
139
+ # Replace all tags
140
+ tags = await client.set_ticket_tags(12345, ["support", "priority"])
141
+ # ["support", "priority"]
142
+
143
+ # Remove specific tags
144
+ tags = await client.remove_ticket_tags(12345, ["priority"])
145
+ # ["support"]
146
+ ```
147
+
148
+ ### Attachments
149
+ - `download_attachment(content_url)` - Download attachment content as bytes
150
+ - `upload_attachment(data, filename, content_type)` - Upload file and get token
151
+
152
+ ```python
153
+ # Download an attachment from a comment
154
+ comments = await client.get_ticket_comments(12345)
155
+ for comment in comments:
156
+ for attachment in comment.attachments or []:
157
+ content = await client.download_attachment(attachment.content_url)
158
+ with open(attachment.file_name, "wb") as f:
159
+ f.write(content)
160
+
161
+ # Upload a file and attach to a comment
162
+ with open("screenshot.png", "rb") as f:
163
+ token = await client.upload_attachment(
164
+ f.read(),
165
+ "screenshot.png",
166
+ "image/png"
167
+ )
168
+
169
+ await client.add_ticket_comment(
170
+ ticket_id=12345,
171
+ body="See attached screenshot",
172
+ uploads=[token]
173
+ )
174
+ ```
175
+
176
+ ### Search
177
+ - `search(query)` - General search
178
+ - `search_users(query)` - Search users
179
+ - `search_tickets(query)` - Search tickets
180
+ - `search_organizations(query)` - Search organizations
181
+
182
+ ## Error Handling
183
+
184
+ The SDK provides specific exception classes for different error types:
185
+
186
+ ```python
187
+ from zendesk_sdk.exceptions import (
188
+ ZendeskAuthException,
189
+ ZendeskHTTPException,
190
+ ZendeskRateLimitException,
191
+ ZendeskTimeoutException,
192
+ ZendeskValidationException,
193
+ )
194
+
195
+ async with ZendeskClient(config) as client:
196
+ try:
197
+ user = await client.get_user(user_id=12345)
198
+ except ZendeskAuthException as e:
199
+ # 401/403 - Authentication failed
200
+ print(f"Auth error: {e.message}")
201
+ except ZendeskRateLimitException as e:
202
+ # 429 - Rate limit exceeded
203
+ print(f"Rate limited, retry after: {e.retry_after}s")
204
+ except ZendeskHTTPException as e:
205
+ # Other HTTP errors (404, 500, etc.)
206
+ print(f"HTTP {e.status_code}: {e.message}")
207
+ except ZendeskTimeoutException as e:
208
+ # Request timeout
209
+ print(f"Timeout: {e.message}")
210
+ ```
211
+
212
+ ### Automatic Retry
213
+
214
+ The SDK automatically retries on:
215
+ - Rate limiting (429) - with respect to `Retry-After` header
216
+ - Server errors (5xx) - with exponential backoff
217
+ - Network errors and timeouts
218
+
219
+ Configure retry behavior:
220
+ ```python
221
+ config = ZendeskConfig(
222
+ subdomain="mycompany",
223
+ email="user@example.com",
224
+ token="api_token",
225
+ timeout=30.0, # Request timeout in seconds
226
+ max_retries=3, # Number of retry attempts
227
+ )
228
+ ```
229
+
230
+ ## Examples
231
+
232
+ See the `examples/` directory for complete usage examples:
233
+ - `basic_usage.py` - Basic configuration and API operations
234
+ - `pagination_example.py` - Working with paginated results
235
+ - `error_handling.py` - Error handling patterns
236
+ - `enriched_tickets.py` - Loading tickets with related data
237
+
238
+ ## Requirements
239
+
240
+ - Python 3.8+
241
+ - httpx
242
+ - pydantic >=2.0
243
+
244
+ ## License
245
+
246
+ MIT License
@@ -0,0 +1,62 @@
1
+ """Basic usage example for Zendesk SDK.
2
+
3
+ This example demonstrates:
4
+ - Configuration setup
5
+ - Basic API operations (get users, tickets, organizations)
6
+ - Search functionality
7
+ """
8
+
9
+ import asyncio
10
+
11
+ from zendesk_sdk import ZendeskClient, ZendeskConfig
12
+
13
+
14
+ async def main() -> None:
15
+ # Option 1: Direct configuration
16
+ config = ZendeskConfig(
17
+ subdomain="your-subdomain",
18
+ email="your-email@example.com",
19
+ token="your-api-token",
20
+ )
21
+
22
+ # Option 2: Configuration from environment variables
23
+ # Set these environment variables:
24
+ # ZENDESK_SUBDOMAIN=your-subdomain
25
+ # ZENDESK_EMAIL=your-email@example.com
26
+ # ZENDESK_TOKEN=your-api-token
27
+ # config = ZendeskConfig()
28
+
29
+ # Use async context manager for proper resource cleanup
30
+ async with ZendeskClient(config) as client:
31
+ # Get a single user
32
+ user = await client.get_user(user_id=12345)
33
+ print(f"User: {user.name} ({user.email})")
34
+
35
+ # Find user by email
36
+ user_by_email = await client.get_user_by_email("user@example.com")
37
+ if user_by_email:
38
+ print(f"Found user: {user_by_email.name}")
39
+
40
+ # Get a single ticket
41
+ ticket = await client.get_ticket(ticket_id=12345)
42
+ print(f"Ticket: {ticket.subject} (status: {ticket.status})")
43
+
44
+ # Get ticket comments
45
+ comments = await client.get_ticket_comments(ticket_id=12345)
46
+ print(f"Ticket has {len(comments)} comments")
47
+
48
+ # Get organization
49
+ org = await client.get_organization(org_id=123)
50
+ print(f"Organization: {org.name}")
51
+
52
+ # Search for tickets
53
+ open_tickets = await client.search_tickets("status:open")
54
+ print(f"Found {len(open_tickets)} open tickets")
55
+
56
+ # Search for users
57
+ users = await client.search_users("role:admin")
58
+ print(f"Found {len(users)} admin users")
59
+
60
+
61
+ if __name__ == "__main__":
62
+ asyncio.run(main())
@@ -0,0 +1,86 @@
1
+ """Enriched tickets example for Zendesk SDK.
2
+
3
+ This example demonstrates:
4
+ - Loading tickets with all related data (comments + users)
5
+ - Using EnrichedTicket for efficient data access
6
+ - Minimizing API requests with batch loading
7
+ """
8
+
9
+ import asyncio
10
+
11
+ from zendesk_sdk import ZendeskClient, ZendeskConfig
12
+
13
+
14
+ async def main() -> None:
15
+ config = ZendeskConfig(
16
+ subdomain="your-subdomain",
17
+ email="your-email@example.com",
18
+ token="your-api-token",
19
+ )
20
+
21
+ async with ZendeskClient(config) as client:
22
+ # Get a single ticket with all related data
23
+ # This makes 2 API calls: ticket + comments (with sideloaded users)
24
+ enriched = await client.get_enriched_ticket(ticket_id=12345)
25
+
26
+ print(f"Ticket: {enriched.ticket.subject}")
27
+ print(f"Status: {enriched.ticket.status}")
28
+
29
+ # Access requester directly
30
+ requester = enriched.requester
31
+ if requester:
32
+ print(f"Requester: {requester.name} ({requester.email})")
33
+
34
+ # Access assignee directly
35
+ assignee = enriched.assignee
36
+ if assignee:
37
+ print(f"Assignee: {assignee.name}")
38
+ else:
39
+ print("Ticket is unassigned")
40
+
41
+ # Process comments with author information
42
+ print(f"\nComments ({len(enriched.comments)}):")
43
+ for comment in enriched.comments:
44
+ author = enriched.get_comment_author(comment)
45
+ if author:
46
+ print(f" - {author.name}: {comment.body[:50]}...")
47
+ else:
48
+ print(f" - Unknown: {comment.body[:50]}...")
49
+
50
+ # Search for tickets and load all related data
51
+ # This efficiently batch-loads users using show_many endpoint
52
+ print("\n--- Searching tickets with enriched data ---")
53
+ results = await client.search_enriched_tickets(
54
+ query="status:open priority:high",
55
+ per_page=10,
56
+ )
57
+
58
+ for item in results:
59
+ print(f"\nTicket #{item.ticket.id}: {item.ticket.subject}")
60
+ print(f" Requester: {item.requester.name if item.requester else 'N/A'}")
61
+ print(f" Assignee: {item.assignee.name if item.assignee else 'Unassigned'}")
62
+ print(f" Comments: {len(item.comments)}")
63
+
64
+ # Get organization tickets with all related data
65
+ print("\n--- Organization tickets ---")
66
+ org_tickets = await client.get_organization_enriched_tickets(
67
+ org_id=123,
68
+ per_page=10,
69
+ )
70
+
71
+ for item in org_tickets:
72
+ print(f"Ticket #{item.ticket.id}: {item.ticket.subject}")
73
+
74
+ # Get user's tickets with all related data
75
+ print("\n--- User tickets ---")
76
+ user_tickets = await client.get_user_enriched_tickets(
77
+ user_id=456,
78
+ per_page=10,
79
+ )
80
+
81
+ for item in user_tickets:
82
+ print(f"Ticket #{item.ticket.id}: {item.ticket.subject}")
83
+
84
+
85
+ if __name__ == "__main__":
86
+ asyncio.run(main())