docwal 1.0.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.
- docwal-1.0.0/CHANGELOG.md +38 -0
- docwal-1.0.0/LICENSE +21 -0
- docwal-1.0.0/MANIFEST.in +10 -0
- docwal-1.0.0/PKG-INFO +388 -0
- docwal-1.0.0/README.md +349 -0
- docwal-1.0.0/docwal/__init__.py +17 -0
- docwal-1.0.0/docwal/client.py +467 -0
- docwal-1.0.0/docwal/exceptions.py +37 -0
- docwal-1.0.0/docwal.egg-info/PKG-INFO +388 -0
- docwal-1.0.0/docwal.egg-info/SOURCES.txt +14 -0
- docwal-1.0.0/docwal.egg-info/dependency_links.txt +1 -0
- docwal-1.0.0/docwal.egg-info/requires.txt +1 -0
- docwal-1.0.0/docwal.egg-info/top_level.txt +1 -0
- docwal-1.0.0/requirements.txt +1 -0
- docwal-1.0.0/setup.cfg +4 -0
- docwal-1.0.0/setup.py +43 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the DocWal Python SDK will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2024-01-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial release of DocWal Python SDK
|
|
12
|
+
- Credentials resource with full CRUD operations
|
|
13
|
+
- Template management (create, list, update, delete)
|
|
14
|
+
- Team member management (invite, list, update roles, deactivate, remove)
|
|
15
|
+
- API key management (generate, regenerate, revoke, info)
|
|
16
|
+
- Batch credential issuance (JSON array and ZIP upload)
|
|
17
|
+
- File upload support for PDF documents
|
|
18
|
+
- Comprehensive error handling with custom exceptions
|
|
19
|
+
- Full documentation with examples
|
|
20
|
+
- Type hints throughout the codebase
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
- Issue single credentials with optional PDF attachments
|
|
24
|
+
- Batch issue up to 1000 credentials at once
|
|
25
|
+
- Batch upload with ZIP files (CSV/JSON + PDFs)
|
|
26
|
+
- List and filter credentials with pagination
|
|
27
|
+
- Revoke credentials with audit trail
|
|
28
|
+
- Resend claim links with configurable expiration
|
|
29
|
+
- Download credential files
|
|
30
|
+
- Manage credential templates with schema validation
|
|
31
|
+
- Team collaboration with role-based permissions
|
|
32
|
+
- Secure API key authentication
|
|
33
|
+
|
|
34
|
+
### Security
|
|
35
|
+
- API key-based authentication
|
|
36
|
+
- HTTPS-only communication
|
|
37
|
+
- Input validation for all requests
|
|
38
|
+
- Proper error handling without leaking sensitive data
|
docwal-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 DocWal
|
|
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.
|
docwal-1.0.0/MANIFEST.in
ADDED
docwal-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: docwal
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for DocWal API - Issue and manage verifiable digital credentials
|
|
5
|
+
Home-page: https://github.com/docwal/docwal-python
|
|
6
|
+
Author: DocWal
|
|
7
|
+
Author-email: support@docwal.com
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/docwal/docwal-python/issues
|
|
9
|
+
Project-URL: Documentation, https://docs.docwal.com
|
|
10
|
+
Project-URL: Source Code, https://github.com/docwal/docwal-python
|
|
11
|
+
Keywords: docwal credentials verifiable digital education blockchain
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Requires-Python: >=3.7
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: requests>=2.25.0
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: description-content-type
|
|
32
|
+
Dynamic: home-page
|
|
33
|
+
Dynamic: keywords
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
Dynamic: project-url
|
|
36
|
+
Dynamic: requires-dist
|
|
37
|
+
Dynamic: requires-python
|
|
38
|
+
Dynamic: summary
|
|
39
|
+
|
|
40
|
+
# DocWal Python SDK
|
|
41
|
+
|
|
42
|
+
Official Python SDK for DocWal API - Issue and manage verifiable digital credentials.
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install docwal
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from docwal import DocWalClient
|
|
54
|
+
|
|
55
|
+
# Initialize client with your API key
|
|
56
|
+
client = DocWalClient(api_key="docwal_live_xxxxx")
|
|
57
|
+
|
|
58
|
+
# Issue a credential
|
|
59
|
+
result = client.credentials.issue(
|
|
60
|
+
template_id="template-123",
|
|
61
|
+
individual_email="student@example.com",
|
|
62
|
+
credential_data={
|
|
63
|
+
"student_name": "John Doe",
|
|
64
|
+
"degree": "Bachelor of Science",
|
|
65
|
+
"major": "Computer Science",
|
|
66
|
+
"graduation_date": "2024-05-15",
|
|
67
|
+
"gpa": "3.8"
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
print(f"Credential issued! Doc ID: {result['doc_id']}")
|
|
72
|
+
print(f"Claim token: {result['claim_token']}")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Authentication
|
|
76
|
+
|
|
77
|
+
Get your API key from your DocWal dashboard:
|
|
78
|
+
1. Login to https://docwal.com
|
|
79
|
+
2. Navigate to Settings → API Keys
|
|
80
|
+
3. Click "Generate API Key"
|
|
81
|
+
4. Copy and store securely
|
|
82
|
+
|
|
83
|
+
**Requirements:**
|
|
84
|
+
- Pilot tier or above
|
|
85
|
+
- Owner or Admin role
|
|
86
|
+
|
|
87
|
+
## Environment Configuration
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
# Production (default)
|
|
91
|
+
client = DocWalClient(api_key="docwal_live_xxxxx")
|
|
92
|
+
|
|
93
|
+
# Staging
|
|
94
|
+
client = DocWalClient(
|
|
95
|
+
api_key="docwal_test_xxxxx",
|
|
96
|
+
base_url="https://sandbox.docwal.com/api"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Custom timeout
|
|
100
|
+
client = DocWalClient(
|
|
101
|
+
api_key="docwal_live_xxxxx",
|
|
102
|
+
timeout=60 # seconds
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Usage Examples
|
|
107
|
+
|
|
108
|
+
### Issue Single Credential
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
# Basic credential
|
|
112
|
+
result = client.credentials.issue(
|
|
113
|
+
template_id="template-123",
|
|
114
|
+
individual_email="student@example.com",
|
|
115
|
+
credential_data={
|
|
116
|
+
"student_name": "John Doe",
|
|
117
|
+
"degree": "Bachelor of Science",
|
|
118
|
+
"graduation_date": "2024-05-15"
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# With PDF attachment
|
|
123
|
+
with open("certificate.pdf", "rb") as f:
|
|
124
|
+
result = client.credentials.issue(
|
|
125
|
+
template_id="template-123",
|
|
126
|
+
individual_email="student@example.com",
|
|
127
|
+
credential_data={"student_name": "John Doe"},
|
|
128
|
+
document_file=f,
|
|
129
|
+
claim_token_expires_hours=168 # 7 days
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Batch Issue Credentials
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
credentials_list = [
|
|
137
|
+
{
|
|
138
|
+
"individual_email": "student1@example.com",
|
|
139
|
+
"credential_data": {
|
|
140
|
+
"student_name": "Alice Smith",
|
|
141
|
+
"degree": "Bachelor of Arts",
|
|
142
|
+
"graduation_date": "2024-05-15"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"individual_email": "student2@example.com",
|
|
147
|
+
"credential_data": {
|
|
148
|
+
"student_name": "Bob Johnson",
|
|
149
|
+
"degree": "Bachelor of Science",
|
|
150
|
+
"graduation_date": "2024-05-15"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
result = client.credentials.batch_issue(
|
|
156
|
+
template_id="template-123",
|
|
157
|
+
credentials=credentials_list,
|
|
158
|
+
send_notifications=True
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
print(f"Success: {result['success_count']}/{result['total_rows']}")
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Batch Upload with ZIP
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
# ZIP structure:
|
|
168
|
+
# batch_credentials.zip
|
|
169
|
+
# ├── credentials.csv
|
|
170
|
+
# └── documents/
|
|
171
|
+
# ├── student001.pdf
|
|
172
|
+
# ├── student002.pdf
|
|
173
|
+
# └── student003.pdf
|
|
174
|
+
|
|
175
|
+
with open("batch_credentials.zip", "rb") as f:
|
|
176
|
+
result = client.credentials.batch_upload(
|
|
177
|
+
template_id="template-123",
|
|
178
|
+
file=f,
|
|
179
|
+
send_notifications=True
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
print(f"Processed: {result['total_rows']}")
|
|
183
|
+
print(f"Success: {result['success_count']}")
|
|
184
|
+
print(f"Failed: {result['failure_count']}")
|
|
185
|
+
|
|
186
|
+
for item in result['results']:
|
|
187
|
+
if item['status'] == 'success':
|
|
188
|
+
print(f"Row {item['row']}: {item['doc_id']}")
|
|
189
|
+
else:
|
|
190
|
+
print(f"Row {item['row']}: {item['error']}")
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### List and Get Credentials
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
# List all credentials
|
|
197
|
+
credentials = client.credentials.list(limit=50, offset=0)
|
|
198
|
+
|
|
199
|
+
for cred in credentials:
|
|
200
|
+
print(f"{cred['doc_id']}: {cred['template_name']}")
|
|
201
|
+
|
|
202
|
+
# Get specific credential
|
|
203
|
+
credential = client.credentials.get("DOC123456")
|
|
204
|
+
print(f"Issued to: {credential['ownership']['individual_email']}")
|
|
205
|
+
print(f"Status: {'Claimed' if credential['ownership']['is_claimed'] else 'Pending'}")
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Revoke Credential
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
result = client.credentials.revoke(
|
|
212
|
+
doc_id="DOC123456",
|
|
213
|
+
reason="Student expelled for academic misconduct"
|
|
214
|
+
)
|
|
215
|
+
print(result['message'])
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Resend Claim Link
|
|
219
|
+
|
|
220
|
+
```python
|
|
221
|
+
result = client.credentials.resend_claim_link(
|
|
222
|
+
doc_id="DOC123456",
|
|
223
|
+
claim_token_expires_hours=168 # 7 days
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
print(f"Sent to: {result['recipient_email']}")
|
|
227
|
+
print(f"Expires: {result['claim_token_expires']}")
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Download Credential File
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
# Download PDF file
|
|
234
|
+
pdf_content = client.credentials.download("DOC123456")
|
|
235
|
+
|
|
236
|
+
with open("credential.pdf", "wb") as f:
|
|
237
|
+
f.write(pdf_content)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Template Management
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
# List templates
|
|
244
|
+
templates = client.templates.list()
|
|
245
|
+
|
|
246
|
+
# Get template
|
|
247
|
+
template = client.templates.get("template-123")
|
|
248
|
+
|
|
249
|
+
# Create template
|
|
250
|
+
template = client.templates.create(
|
|
251
|
+
name="Bachelor Degree Certificate",
|
|
252
|
+
description="Template for bachelor degree graduation certificates",
|
|
253
|
+
credential_type="certificate",
|
|
254
|
+
schema={
|
|
255
|
+
"student_name": {
|
|
256
|
+
"type": "string",
|
|
257
|
+
"required": True,
|
|
258
|
+
"label": "Student Name"
|
|
259
|
+
},
|
|
260
|
+
"degree": {
|
|
261
|
+
"type": "string",
|
|
262
|
+
"required": True,
|
|
263
|
+
"label": "Degree Program"
|
|
264
|
+
},
|
|
265
|
+
"graduation_date": {
|
|
266
|
+
"type": "date",
|
|
267
|
+
"required": True,
|
|
268
|
+
"label": "Graduation Date"
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
version="1.0"
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# Update template
|
|
275
|
+
client.templates.update(
|
|
276
|
+
"template-123",
|
|
277
|
+
description="Updated description"
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# Delete template (soft delete)
|
|
281
|
+
client.templates.delete("template-123")
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## API Key Management
|
|
285
|
+
|
|
286
|
+
```python
|
|
287
|
+
# Generate new API key (Owner/Admin only)
|
|
288
|
+
result = client.api_keys.generate()
|
|
289
|
+
print(f"New API key: {result['api_key']}")
|
|
290
|
+
print("⚠️ Store securely - shown only once!")
|
|
291
|
+
|
|
292
|
+
# Get API key info
|
|
293
|
+
info = client.api_keys.info()
|
|
294
|
+
print(f"Masked key: {info['api_key_masked']}")
|
|
295
|
+
print(f"Created: {info['created_at']}")
|
|
296
|
+
print(f"Last used: {info['last_used_at']}")
|
|
297
|
+
|
|
298
|
+
# Regenerate API key
|
|
299
|
+
result = client.api_keys.regenerate()
|
|
300
|
+
print(f"New API key: {result['api_key']}")
|
|
301
|
+
|
|
302
|
+
# Revoke API key
|
|
303
|
+
client.api_keys.revoke()
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Team Management
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
# List team members
|
|
310
|
+
team = client.team.list()
|
|
311
|
+
print(f"Active members: {team['stats']['active_members']}")
|
|
312
|
+
print(f"Pending invitations: {team['stats']['pending_invitations']}")
|
|
313
|
+
|
|
314
|
+
# Check email before inviting
|
|
315
|
+
check = client.team.check_email("newmember@university.edu")
|
|
316
|
+
if check['recommendation'] == 'add_directly':
|
|
317
|
+
print("User exists - can add directly")
|
|
318
|
+
elif check['recommendation'] == 'send_invitation':
|
|
319
|
+
print("User doesn't exist - must send invitation")
|
|
320
|
+
|
|
321
|
+
# Invite team member
|
|
322
|
+
result = client.team.invite(
|
|
323
|
+
email="newmember@university.edu",
|
|
324
|
+
role="issuer",
|
|
325
|
+
send_email=True
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
# Update member role
|
|
329
|
+
client.team.update_role(
|
|
330
|
+
member_id="member-123",
|
|
331
|
+
role="admin"
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
# Deactivate member
|
|
335
|
+
client.team.deactivate(
|
|
336
|
+
member_id="member-123",
|
|
337
|
+
reason="Employee on leave"
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
# Reactivate member
|
|
341
|
+
client.team.reactivate("member-123")
|
|
342
|
+
|
|
343
|
+
# Remove member permanently
|
|
344
|
+
client.team.remove("member-123")
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Error Handling
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
from docwal import DocWalClient, DocWalError, AuthenticationError, ValidationError
|
|
351
|
+
|
|
352
|
+
client = DocWalClient(api_key="docwal_live_xxxxx")
|
|
353
|
+
|
|
354
|
+
try:
|
|
355
|
+
result = client.credentials.issue(
|
|
356
|
+
template_id="invalid-template",
|
|
357
|
+
individual_email="student@example.com",
|
|
358
|
+
credential_data={}
|
|
359
|
+
)
|
|
360
|
+
except AuthenticationError as e:
|
|
361
|
+
print(f"Authentication failed: {e}")
|
|
362
|
+
print("Check your API key")
|
|
363
|
+
except ValidationError as e:
|
|
364
|
+
print(f"Validation error: {e}")
|
|
365
|
+
print("Check required fields")
|
|
366
|
+
except DocWalError as e:
|
|
367
|
+
print(f"API error: {e}")
|
|
368
|
+
print(f"Status code: {e.status_code}")
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Rate Limits
|
|
372
|
+
|
|
373
|
+
- **Pilot**: 500 requests/hour
|
|
374
|
+
- **Standard**: 1,000 requests/hour
|
|
375
|
+
- **Enterprise**: Unlimited
|
|
376
|
+
|
|
377
|
+
When rate limit is exceeded, `RateLimitError` is raised.
|
|
378
|
+
|
|
379
|
+
## Support
|
|
380
|
+
|
|
381
|
+
- **Email**: support@docwal.com
|
|
382
|
+
- **Documentation**: https://docs.docwal.com
|
|
383
|
+
- **API Reference**: https://docwal.com/api/docs
|
|
384
|
+
- **GitHub**: https://github.com/docwal/docwal-python
|
|
385
|
+
|
|
386
|
+
## License
|
|
387
|
+
|
|
388
|
+
MIT License - see LICENSE file for details.
|