djep-sdk 1.1.1__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 (31) hide show
  1. djep_sdk-1.1.1/PKG-INFO +370 -0
  2. djep_sdk-1.1.1/README.md +340 -0
  3. djep_sdk-1.1.1/djep_sdk/__init__.py +82 -0
  4. djep_sdk-1.1.1/djep_sdk/exceptions/__init__.py +30 -0
  5. djep_sdk-1.1.1/djep_sdk/http_client.py +78 -0
  6. djep_sdk-1.1.1/djep_sdk/resources/__init__.py +24 -0
  7. djep_sdk-1.1.1/djep_sdk/resources/addons.py +6 -0
  8. djep_sdk-1.1.1/djep_sdk/resources/availability.py +14 -0
  9. djep_sdk-1.1.1/djep_sdk/resources/booking_helpers.py +23 -0
  10. djep_sdk-1.1.1/djep_sdk/resources/clients.py +25 -0
  11. djep_sdk-1.1.1/djep_sdk/resources/closed_dates.py +4 -0
  12. djep_sdk-1.1.1/djep_sdk/resources/contacts.py +6 -0
  13. djep_sdk-1.1.1/djep_sdk/resources/employees.py +6 -0
  14. djep_sdk-1.1.1/djep_sdk/resources/equipment.py +5 -0
  15. djep_sdk-1.1.1/djep_sdk/resources/event_planning.py +5 -0
  16. djep_sdk-1.1.1/djep_sdk/resources/events.py +82 -0
  17. djep_sdk-1.1.1/djep_sdk/resources/expenses.py +18 -0
  18. djep_sdk-1.1.1/djep_sdk/resources/music_requests.py +20 -0
  19. djep_sdk-1.1.1/djep_sdk/resources/packages.py +6 -0
  20. djep_sdk-1.1.1/djep_sdk/resources/payments.py +22 -0
  21. djep_sdk-1.1.1/djep_sdk/resources/settings.py +11 -0
  22. djep_sdk-1.1.1/djep_sdk/resources/submissions.py +17 -0
  23. djep_sdk-1.1.1/djep_sdk/resources/systems.py +5 -0
  24. djep_sdk-1.1.1/djep_sdk/resources/vendors.py +16 -0
  25. djep_sdk-1.1.1/djep_sdk/resources/venues.py +6 -0
  26. djep_sdk-1.1.1/djep_sdk.egg-info/PKG-INFO +370 -0
  27. djep_sdk-1.1.1/djep_sdk.egg-info/SOURCES.txt +29 -0
  28. djep_sdk-1.1.1/djep_sdk.egg-info/dependency_links.txt +1 -0
  29. djep_sdk-1.1.1/djep_sdk.egg-info/top_level.txt +1 -0
  30. djep_sdk-1.1.1/setup.cfg +4 -0
  31. djep_sdk-1.1.1/setup.py +28 -0
@@ -0,0 +1,370 @@
1
+ Metadata-Version: 2.4
2
+ Name: djep-sdk
3
+ Version: 1.1.1
4
+ Summary: Official Python SDK for the DJ Event Planner (DJEP) REST API
5
+ Home-page: https://github.com/djeventplannerhub/djep-python-sdk
6
+ Author: DJ Event Planner
7
+ Author-email: support@djeventplanner.com
8
+ Keywords: djep dj event planner api sdk
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.7
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.7
20
+ Description-Content-Type: text/markdown
21
+ Dynamic: author
22
+ Dynamic: author-email
23
+ Dynamic: classifier
24
+ Dynamic: description
25
+ Dynamic: description-content-type
26
+ Dynamic: home-page
27
+ Dynamic: keywords
28
+ Dynamic: requires-python
29
+ Dynamic: summary
30
+
31
+ # DJEP Python SDK
32
+
33
+ Official Python SDK for the [DJ Event Planner (DJEP)](https://www.djeventplanner.com) REST API.
34
+
35
+ ## Requirements
36
+
37
+ - Python 3.7 or later
38
+ - No external dependencies
39
+
40
+ ## Installation
41
+
42
+ ### Via pip
43
+
44
+ ```bash
45
+ pip install djep-sdk
46
+ ```
47
+
48
+ ### Manual Installation
49
+
50
+ Download the SDK and place the `djep_sdk` folder in your project:
51
+
52
+ ```python
53
+ from djep_sdk import Client
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ ```python
59
+ import os
60
+ from djep_sdk import Client
61
+
62
+ # Load your API key from environment variables (never hardcode keys)
63
+ djep = Client(api_key=os.environ['DJEP_API_KEY'], domain=os.environ['DJEP_DOMAIN'])
64
+
65
+ # Check API status
66
+ status = djep.status()
67
+ print(status['data']['version'])
68
+
69
+ # List upcoming events
70
+ events = djep.events.list(status='Booked', per_page=10)
71
+ for event in events['data']:
72
+ print(f"{event['event_type']} on {event['event_date']}")
73
+ ```
74
+
75
+ ## Authentication
76
+
77
+ Your API key is generated in DJEP under **Setup > Integrations > API Key**.
78
+
79
+ **Important:** Never hardcode your API key in source files. Use environment variables.
80
+
81
+ ```python
82
+ import os
83
+ from djep_sdk import Client
84
+
85
+ # Environment variable (recommended)
86
+ djep = Client(api_key=os.environ['DJEP_API_KEY'], domain=os.environ['DJEP_DOMAIN'])
87
+
88
+ # Or from a .env file (using python-dotenv)
89
+ from dotenv import load_dotenv
90
+ load_dotenv()
91
+ djep = Client(api_key=os.environ['DJEP_API_KEY'], domain=os.environ['DJEP_DOMAIN'])
92
+ ```
93
+
94
+ ## Usage
95
+
96
+ ### Events
97
+
98
+ ```python
99
+ # List events
100
+ events = djep.events.list(status='Booked', sort_by='event_date')
101
+
102
+ # Get a single event
103
+ event = djep.events.get(56789)
104
+
105
+ # Create an event (financials auto-calculated from package)
106
+ new_event = djep.events.create(
107
+ clientid=12345,
108
+ event_date='2026-09-15',
109
+ event_type='Wedding',
110
+ start_time='3:00 PM',
111
+ end_time='11:00 PM',
112
+ addons='501:2,502:1',
113
+ )
114
+ print(f"Total fee: {new_event['data']['financials']['total_fee']}")
115
+
116
+ # Update specific fields
117
+ djep.events.update(56789, {'status': 'Confirmed', 'guest_count': 200})
118
+
119
+ # Update and recalculate financials
120
+ djep.events.update(56789, {'pkg_idnumber': 14200}, recalculate=True)
121
+
122
+ # Delete an event (cascading)
123
+ djep.events.delete(56789)
124
+
125
+ # Event sub-data
126
+ payments = djep.events.payments(56789)
127
+ songs = djep.events.music_requests(56789)
128
+ planning = djep.events.planning(56789)
129
+ ```
130
+
131
+ ### Clients
132
+
133
+ ```python
134
+ clients = djep.clients.list(per_page=25)
135
+ client = djep.clients.get(12345)
136
+
137
+ new_client = djep.clients.create(
138
+ first_name='John',
139
+ last_name='Smith',
140
+ email='john@example.com',
141
+ )
142
+
143
+ djep.clients.update(12345, {'email': 'new@example.com'})
144
+ djep.clients.delete(12345)
145
+ ```
146
+
147
+ ### Venues, Employees, Packages, Addons, Contacts
148
+
149
+ ```python
150
+ # All follow the same pattern
151
+ venues = djep.venues.list()
152
+ venue = djep.venues.get(789)
153
+
154
+ employees = djep.employees.list()
155
+ packages = djep.packages.list()
156
+ addons = djep.addons.list()
157
+ contacts = djep.contacts.list()
158
+ ```
159
+
160
+ ### Vendors
161
+
162
+ ```python
163
+ vendors = djep.vendors.list()
164
+ vendor = djep.vendors.get(3456)
165
+
166
+ # Link a vendor to an event
167
+ djep.vendors.link_to_event(56789, 3456)
168
+ ```
169
+
170
+ ### Payments
171
+
172
+ ```python
173
+ # List all payments company-wide
174
+ payments = djep.payments.list(per_page=50)
175
+
176
+ # Add a payment to an event
177
+ result = djep.payments.add_to_event(56789, 500.00, 'Credit Card',
178
+ processing_fee=15,
179
+ comments='Final payment',
180
+ )
181
+ print(f"Balance due: {result['data']['balance_due']}")
182
+ ```
183
+
184
+ ### Music Requests
185
+
186
+ ```python
187
+ # Get requests for an event
188
+ songs = djep.music_requests.for_event(56789)
189
+
190
+ # Add a music request
191
+ djep.music_requests.add(56789, 'Queen', 'Bohemian Rhapsody', 'MPL')
192
+ djep.music_requests.add(56789, 'ABBA', 'Dancing Queen', 'DED', comments='For the bride')
193
+ ```
194
+
195
+ ### Booking Helpers
196
+
197
+ ```python
198
+ # List available helpers
199
+ helpers = djep.booking_helpers.list()
200
+
201
+ # Run by unique_id (recommended)
202
+ result = djep.booking_helpers.run(56789, unique_id='book_event_1')
203
+ print(result['data']['log'])
204
+
205
+ # Or by position index
206
+ result = djep.booking_helpers.run(56789, bhid=0)
207
+ ```
208
+
209
+ ### Availability
210
+
211
+ ```python
212
+ # Check a single date
213
+ avail = djep.availability.check('09/15/2026')
214
+ if avail['data']['available']:
215
+ print(f"{avail['data']['employees']['available']} employees available")
216
+
217
+ # Check a date range (max 90 days)
218
+ date_range = djep.availability.range('09/01/2026', '09/30/2026')
219
+ for date in date_range['data']['dates']:
220
+ status = 'Available' if date['available'] else 'Unavailable'
221
+ print(f"{date['date']}: {status}")
222
+ ```
223
+
224
+ ### Settings
225
+
226
+ ```python
227
+ rfi_settings = djep.settings.website_tools('request_info')
228
+ company = djep.settings.company()
229
+ fields = djep.settings.custom_fields()
230
+ ```
231
+
232
+ ### Expenses
233
+
234
+ ```python
235
+ expenses = djep.expenses.list(per_page=25)
236
+ categories = djep.expenses.categories()
237
+ payees = djep.expenses.payees()
238
+ methods = djep.expenses.payment_methods()
239
+ ```
240
+
241
+ ### Other Resources
242
+
243
+ ```python
244
+ rfi = djep.submissions.rfi()
245
+ quotes = djep.submissions.quotes()
246
+ contact_us = djep.submissions.contact_us()
247
+
248
+ closed_dates = djep.closed_dates.list()
249
+ equipment = djep.equipment.list()
250
+ systems = djep.systems.list()
251
+ ```
252
+
253
+ ### Create Submission (RFI)
254
+
255
+ Push leads from external sources into the DJ's submissions queue:
256
+
257
+ ```python
258
+ # Wedding Wire lead
259
+ submission = djep.submissions.create(
260
+ first_name='Sarah', last_name='Johnson',
261
+ email='sarah@example.com', telephone='555-0123',
262
+ event_date='2026-09-15', event_type='Wedding',
263
+ guest_count=200, source='Wedding Wire',
264
+ send_notification='true',
265
+ )
266
+ print(f"Submission ID: {submission['data']['req_idnumber']}")
267
+
268
+ # With custom questions and privacy consent
269
+ submission = djep.submissions.create(
270
+ first_name='Emma', last_name='Wilson',
271
+ email='emma@example.com',
272
+ event_date='2027-06-20', event_type='Wedding',
273
+ question_1='Yes, we need lighting', q1_mapto='custom_field1',
274
+ privacy_policy_signed='true', source='Custom Website',
275
+ send_notification='true',
276
+ )
277
+ ```
278
+
279
+ ### Convenience Endpoints
280
+
281
+ Quick actions without the `fields` parameter:
282
+
283
+ ```python
284
+ # Quick status change — returns old and new status
285
+ result = djep.events.update_status(56789, 'Booked')
286
+ print(f"{result['data']['old_status']} → {result['data']['new_status']}")
287
+
288
+ # Assign employee to position (1-15), with optional fee and role
289
+ djep.events.assign_employee(56789, 1, 48113, fee=500, role='Lead DJ')
290
+ djep.events.assign_employee(56789, 2, 48361, fee=350, role='MC')
291
+
292
+ # Unassign position 3
293
+ djep.events.assign_employee(56789, 3, 0)
294
+
295
+ # Update notes — pass any combination of note fields
296
+ djep.events.update_notes(56789,
297
+ comments='AI Summary: Client wants 80s and 90s hits',
298
+ next_action='Send playlist proposal',
299
+ next_action_date='08/15/2026',
300
+ )
301
+ ```
302
+
303
+ ## Auto-Pagination
304
+
305
+ For resources with pagination, use `all()` to automatically iterate through every page:
306
+
307
+ ```python
308
+ # Fetches all events across all pages
309
+ for event in djep.events.all(status='Booked'):
310
+ print(event['event_date'])
311
+
312
+ # Works with any paginated resource
313
+ for client in djep.clients.all():
314
+ print(f"{client['first_name']} {client['last_name']}")
315
+ ```
316
+
317
+ ## Error Handling
318
+
319
+ The SDK raises specific exceptions for different error types:
320
+
321
+ ```python
322
+ from djep_sdk import (
323
+ Client, DJEPError, AuthenticationError, NotFoundError,
324
+ ValidationError, ForbiddenError, RateLimitError,
325
+ )
326
+
327
+ try:
328
+ event = djep.events.get(99999)
329
+ except AuthenticationError as e:
330
+ print(f'Invalid API key: {e}')
331
+ except NotFoundError as e:
332
+ print(f'Not found: {e}')
333
+ except ForbiddenError as e:
334
+ print(f'Forbidden: {e}')
335
+ except ValidationError as e:
336
+ print(f'Validation error: {e}')
337
+ except RateLimitError as e:
338
+ print(f'Rate limited: {e}')
339
+ except DJEPError as e:
340
+ print(f'API error: {e}')
341
+ ```
342
+
343
+ ## Configuration Options
344
+
345
+ ```python
346
+ djep = Client(
347
+ api_key=os.environ['DJEP_API_KEY'],
348
+ domain=os.environ['DJEP_DOMAIN'],
349
+ timeout=60, # Request timeout in seconds (default: 30)
350
+ )
351
+ ```
352
+
353
+ ## Security
354
+
355
+ - **Never** commit API keys to version control
356
+ - Store keys in environment variables or `.env` files (excluded from Git)
357
+ - Use the most restrictive API key for your use case
358
+ - API keys provide full access to the associated account — treat them like passwords
359
+
360
+ ## API Documentation
361
+
362
+ Full API documentation is available at your DJEP instance:
363
+
364
+ ```
365
+ https://yourdomain.com/api/api.asp?action=docs
366
+ ```
367
+
368
+ ## License
369
+
370
+ MIT
@@ -0,0 +1,340 @@
1
+ # DJEP Python SDK
2
+
3
+ Official Python SDK for the [DJ Event Planner (DJEP)](https://www.djeventplanner.com) REST API.
4
+
5
+ ## Requirements
6
+
7
+ - Python 3.7 or later
8
+ - No external dependencies
9
+
10
+ ## Installation
11
+
12
+ ### Via pip
13
+
14
+ ```bash
15
+ pip install djep-sdk
16
+ ```
17
+
18
+ ### Manual Installation
19
+
20
+ Download the SDK and place the `djep_sdk` folder in your project:
21
+
22
+ ```python
23
+ from djep_sdk import Client
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```python
29
+ import os
30
+ from djep_sdk import Client
31
+
32
+ # Load your API key from environment variables (never hardcode keys)
33
+ djep = Client(api_key=os.environ['DJEP_API_KEY'], domain=os.environ['DJEP_DOMAIN'])
34
+
35
+ # Check API status
36
+ status = djep.status()
37
+ print(status['data']['version'])
38
+
39
+ # List upcoming events
40
+ events = djep.events.list(status='Booked', per_page=10)
41
+ for event in events['data']:
42
+ print(f"{event['event_type']} on {event['event_date']}")
43
+ ```
44
+
45
+ ## Authentication
46
+
47
+ Your API key is generated in DJEP under **Setup > Integrations > API Key**.
48
+
49
+ **Important:** Never hardcode your API key in source files. Use environment variables.
50
+
51
+ ```python
52
+ import os
53
+ from djep_sdk import Client
54
+
55
+ # Environment variable (recommended)
56
+ djep = Client(api_key=os.environ['DJEP_API_KEY'], domain=os.environ['DJEP_DOMAIN'])
57
+
58
+ # Or from a .env file (using python-dotenv)
59
+ from dotenv import load_dotenv
60
+ load_dotenv()
61
+ djep = Client(api_key=os.environ['DJEP_API_KEY'], domain=os.environ['DJEP_DOMAIN'])
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ ### Events
67
+
68
+ ```python
69
+ # List events
70
+ events = djep.events.list(status='Booked', sort_by='event_date')
71
+
72
+ # Get a single event
73
+ event = djep.events.get(56789)
74
+
75
+ # Create an event (financials auto-calculated from package)
76
+ new_event = djep.events.create(
77
+ clientid=12345,
78
+ event_date='2026-09-15',
79
+ event_type='Wedding',
80
+ start_time='3:00 PM',
81
+ end_time='11:00 PM',
82
+ addons='501:2,502:1',
83
+ )
84
+ print(f"Total fee: {new_event['data']['financials']['total_fee']}")
85
+
86
+ # Update specific fields
87
+ djep.events.update(56789, {'status': 'Confirmed', 'guest_count': 200})
88
+
89
+ # Update and recalculate financials
90
+ djep.events.update(56789, {'pkg_idnumber': 14200}, recalculate=True)
91
+
92
+ # Delete an event (cascading)
93
+ djep.events.delete(56789)
94
+
95
+ # Event sub-data
96
+ payments = djep.events.payments(56789)
97
+ songs = djep.events.music_requests(56789)
98
+ planning = djep.events.planning(56789)
99
+ ```
100
+
101
+ ### Clients
102
+
103
+ ```python
104
+ clients = djep.clients.list(per_page=25)
105
+ client = djep.clients.get(12345)
106
+
107
+ new_client = djep.clients.create(
108
+ first_name='John',
109
+ last_name='Smith',
110
+ email='john@example.com',
111
+ )
112
+
113
+ djep.clients.update(12345, {'email': 'new@example.com'})
114
+ djep.clients.delete(12345)
115
+ ```
116
+
117
+ ### Venues, Employees, Packages, Addons, Contacts
118
+
119
+ ```python
120
+ # All follow the same pattern
121
+ venues = djep.venues.list()
122
+ venue = djep.venues.get(789)
123
+
124
+ employees = djep.employees.list()
125
+ packages = djep.packages.list()
126
+ addons = djep.addons.list()
127
+ contacts = djep.contacts.list()
128
+ ```
129
+
130
+ ### Vendors
131
+
132
+ ```python
133
+ vendors = djep.vendors.list()
134
+ vendor = djep.vendors.get(3456)
135
+
136
+ # Link a vendor to an event
137
+ djep.vendors.link_to_event(56789, 3456)
138
+ ```
139
+
140
+ ### Payments
141
+
142
+ ```python
143
+ # List all payments company-wide
144
+ payments = djep.payments.list(per_page=50)
145
+
146
+ # Add a payment to an event
147
+ result = djep.payments.add_to_event(56789, 500.00, 'Credit Card',
148
+ processing_fee=15,
149
+ comments='Final payment',
150
+ )
151
+ print(f"Balance due: {result['data']['balance_due']}")
152
+ ```
153
+
154
+ ### Music Requests
155
+
156
+ ```python
157
+ # Get requests for an event
158
+ songs = djep.music_requests.for_event(56789)
159
+
160
+ # Add a music request
161
+ djep.music_requests.add(56789, 'Queen', 'Bohemian Rhapsody', 'MPL')
162
+ djep.music_requests.add(56789, 'ABBA', 'Dancing Queen', 'DED', comments='For the bride')
163
+ ```
164
+
165
+ ### Booking Helpers
166
+
167
+ ```python
168
+ # List available helpers
169
+ helpers = djep.booking_helpers.list()
170
+
171
+ # Run by unique_id (recommended)
172
+ result = djep.booking_helpers.run(56789, unique_id='book_event_1')
173
+ print(result['data']['log'])
174
+
175
+ # Or by position index
176
+ result = djep.booking_helpers.run(56789, bhid=0)
177
+ ```
178
+
179
+ ### Availability
180
+
181
+ ```python
182
+ # Check a single date
183
+ avail = djep.availability.check('09/15/2026')
184
+ if avail['data']['available']:
185
+ print(f"{avail['data']['employees']['available']} employees available")
186
+
187
+ # Check a date range (max 90 days)
188
+ date_range = djep.availability.range('09/01/2026', '09/30/2026')
189
+ for date in date_range['data']['dates']:
190
+ status = 'Available' if date['available'] else 'Unavailable'
191
+ print(f"{date['date']}: {status}")
192
+ ```
193
+
194
+ ### Settings
195
+
196
+ ```python
197
+ rfi_settings = djep.settings.website_tools('request_info')
198
+ company = djep.settings.company()
199
+ fields = djep.settings.custom_fields()
200
+ ```
201
+
202
+ ### Expenses
203
+
204
+ ```python
205
+ expenses = djep.expenses.list(per_page=25)
206
+ categories = djep.expenses.categories()
207
+ payees = djep.expenses.payees()
208
+ methods = djep.expenses.payment_methods()
209
+ ```
210
+
211
+ ### Other Resources
212
+
213
+ ```python
214
+ rfi = djep.submissions.rfi()
215
+ quotes = djep.submissions.quotes()
216
+ contact_us = djep.submissions.contact_us()
217
+
218
+ closed_dates = djep.closed_dates.list()
219
+ equipment = djep.equipment.list()
220
+ systems = djep.systems.list()
221
+ ```
222
+
223
+ ### Create Submission (RFI)
224
+
225
+ Push leads from external sources into the DJ's submissions queue:
226
+
227
+ ```python
228
+ # Wedding Wire lead
229
+ submission = djep.submissions.create(
230
+ first_name='Sarah', last_name='Johnson',
231
+ email='sarah@example.com', telephone='555-0123',
232
+ event_date='2026-09-15', event_type='Wedding',
233
+ guest_count=200, source='Wedding Wire',
234
+ send_notification='true',
235
+ )
236
+ print(f"Submission ID: {submission['data']['req_idnumber']}")
237
+
238
+ # With custom questions and privacy consent
239
+ submission = djep.submissions.create(
240
+ first_name='Emma', last_name='Wilson',
241
+ email='emma@example.com',
242
+ event_date='2027-06-20', event_type='Wedding',
243
+ question_1='Yes, we need lighting', q1_mapto='custom_field1',
244
+ privacy_policy_signed='true', source='Custom Website',
245
+ send_notification='true',
246
+ )
247
+ ```
248
+
249
+ ### Convenience Endpoints
250
+
251
+ Quick actions without the `fields` parameter:
252
+
253
+ ```python
254
+ # Quick status change — returns old and new status
255
+ result = djep.events.update_status(56789, 'Booked')
256
+ print(f"{result['data']['old_status']} → {result['data']['new_status']}")
257
+
258
+ # Assign employee to position (1-15), with optional fee and role
259
+ djep.events.assign_employee(56789, 1, 48113, fee=500, role='Lead DJ')
260
+ djep.events.assign_employee(56789, 2, 48361, fee=350, role='MC')
261
+
262
+ # Unassign position 3
263
+ djep.events.assign_employee(56789, 3, 0)
264
+
265
+ # Update notes — pass any combination of note fields
266
+ djep.events.update_notes(56789,
267
+ comments='AI Summary: Client wants 80s and 90s hits',
268
+ next_action='Send playlist proposal',
269
+ next_action_date='08/15/2026',
270
+ )
271
+ ```
272
+
273
+ ## Auto-Pagination
274
+
275
+ For resources with pagination, use `all()` to automatically iterate through every page:
276
+
277
+ ```python
278
+ # Fetches all events across all pages
279
+ for event in djep.events.all(status='Booked'):
280
+ print(event['event_date'])
281
+
282
+ # Works with any paginated resource
283
+ for client in djep.clients.all():
284
+ print(f"{client['first_name']} {client['last_name']}")
285
+ ```
286
+
287
+ ## Error Handling
288
+
289
+ The SDK raises specific exceptions for different error types:
290
+
291
+ ```python
292
+ from djep_sdk import (
293
+ Client, DJEPError, AuthenticationError, NotFoundError,
294
+ ValidationError, ForbiddenError, RateLimitError,
295
+ )
296
+
297
+ try:
298
+ event = djep.events.get(99999)
299
+ except AuthenticationError as e:
300
+ print(f'Invalid API key: {e}')
301
+ except NotFoundError as e:
302
+ print(f'Not found: {e}')
303
+ except ForbiddenError as e:
304
+ print(f'Forbidden: {e}')
305
+ except ValidationError as e:
306
+ print(f'Validation error: {e}')
307
+ except RateLimitError as e:
308
+ print(f'Rate limited: {e}')
309
+ except DJEPError as e:
310
+ print(f'API error: {e}')
311
+ ```
312
+
313
+ ## Configuration Options
314
+
315
+ ```python
316
+ djep = Client(
317
+ api_key=os.environ['DJEP_API_KEY'],
318
+ domain=os.environ['DJEP_DOMAIN'],
319
+ timeout=60, # Request timeout in seconds (default: 30)
320
+ )
321
+ ```
322
+
323
+ ## Security
324
+
325
+ - **Never** commit API keys to version control
326
+ - Store keys in environment variables or `.env` files (excluded from Git)
327
+ - Use the most restrictive API key for your use case
328
+ - API keys provide full access to the associated account — treat them like passwords
329
+
330
+ ## API Documentation
331
+
332
+ Full API documentation is available at your DJEP instance:
333
+
334
+ ```
335
+ https://yourdomain.com/api/api.asp?action=docs
336
+ ```
337
+
338
+ ## License
339
+
340
+ MIT