ccai-python 1.0.1__tar.gz → 1.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.
- {ccai_python-1.0.1 → ccai_python-1.1.0}/PKG-INFO +206 -11
- ccai_python-1.1.0/README.md +486 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/pyproject.toml +1 -1
- {ccai_python-1.0.1 → ccai_python-1.1.0}/setup.py +2 -2
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/__init__.py +24 -5
- ccai_python-1.1.0/src/ccai_python/brand_service.py +91 -0
- ccai_python-1.1.0/src/ccai_python/campaign_service.py +125 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/ccai.py +92 -25
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/contact_test.py +2 -2
- ccai_python-1.1.0/src/ccai_python/contact_validator_service.py +76 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/email_send.py +5 -5
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/email_service.py +127 -41
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/mms_send.py +7 -6
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/sms/mms.py +28 -12
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/sms/sms.py +49 -19
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/sms_send.py +7 -6
- ccai_python-1.1.0/src/ccai_python/webhook.py +171 -0
- ccai_python-1.1.0/src/ccai_python/webhook_handler_example.py +91 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/webhook_test.py +7 -6
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python.egg-info/PKG-INFO +206 -11
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python.egg-info/SOURCES.txt +6 -3
- {ccai_python-1.0.1 → ccai_python-1.1.0}/tests/test_ccai.py +33 -10
- ccai_python-1.1.0/tests/test_email.py +135 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/tests/test_mms.py +25 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/tests/test_sms.py +58 -3
- ccai_python-1.1.0/tests/test_webhook.py +178 -0
- ccai_python-1.0.1/README.md +0 -291
- ccai_python-1.0.1/src/ccai_python/examples/async_example.py +0 -248
- ccai_python-1.0.1/src/ccai_python/examples/basic_example.py +0 -79
- ccai_python-1.0.1/src/ccai_python/webhook.py +0 -110
- ccai_python-1.0.1/src/ccai_python/webhook_handler_example.py +0 -46
- {ccai_python-1.0.1 → ccai_python-1.1.0}/setup.cfg +0 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/contact_service.py +0 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python/sms/__init__.py +0 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python.egg-info/dependency_links.txt +0 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python.egg-info/requires.txt +0 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/src/ccai_python.egg-info/top_level.txt +0 -0
- {ccai_python-1.0.1 → ccai_python-1.1.0}/tests/test_contact.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ccai-python
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Python client for CloudContactAI API
|
|
5
5
|
Author: CloudContactAI LLC
|
|
6
6
|
License: MIT
|
|
@@ -21,7 +21,7 @@ Dynamic: requires-python
|
|
|
21
21
|
|
|
22
22
|
# CCAI Python Client
|
|
23
23
|
|
|
24
|
-
Version: 1.0
|
|
24
|
+
Version: 1.1.0
|
|
25
25
|
|
|
26
26
|
A Python client for interacting with the CloudContactAI API.
|
|
27
27
|
|
|
@@ -225,6 +225,42 @@ response = ccai.contact.set_do_not_text(
|
|
|
225
225
|
print(f"Contact {response.contact_id} do not text removed: {response.do_not_text}")
|
|
226
226
|
```
|
|
227
227
|
|
|
228
|
+
### Contact Validator
|
|
229
|
+
|
|
230
|
+
Validate email addresses and phone numbers.
|
|
231
|
+
|
|
232
|
+
> Bulk endpoints accept up to 50 contacts per request and are processed server-side in chunks.
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
from ccai_python import CCAI
|
|
236
|
+
|
|
237
|
+
ccai = CCAI(
|
|
238
|
+
client_id="YOUR-CLIENT-ID",
|
|
239
|
+
api_key="YOUR-API-KEY"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
# Validate a single email
|
|
243
|
+
email_result = ccai.contact_validator.validate_email("user@example.com")
|
|
244
|
+
print(email_result.status) # "valid" | "invalid" | "risky"
|
|
245
|
+
print(email_result.metadata.get("safe_to_send")) # True | False
|
|
246
|
+
|
|
247
|
+
# Validate multiple emails (up to 50, processed server-side in chunks)
|
|
248
|
+
bulk_emails = ccai.contact_validator.validate_emails(["user@example.com", "bad@invalid.xyz"])
|
|
249
|
+
print(bulk_emails.summary.model_dump()) # {"total": 2, "valid": 1, "invalid": 1, "risky": 0, "landline": 0}
|
|
250
|
+
|
|
251
|
+
# Validate a single phone number
|
|
252
|
+
phone_result = ccai.contact_validator.validate_phone("+15551234567", country_code="US")
|
|
253
|
+
print(phone_result.status) # "valid" | "invalid" | "landline"
|
|
254
|
+
print(phone_result.metadata.get("carrier_type")) # "mobile" | "landline" | "voip"
|
|
255
|
+
|
|
256
|
+
# Validate multiple phone numbers (up to 50, processed server-side in chunks)
|
|
257
|
+
bulk_phones = ccai.contact_validator.validate_phones([
|
|
258
|
+
{"phone": "+15551234567"},
|
|
259
|
+
{"phone": "+15559876543", "countryCode": "US"}
|
|
260
|
+
])
|
|
261
|
+
print(bulk_phones.summary.model_dump()) # {"total": 2, "valid": 1, "invalid": 0, "risky": 0, "landline": 1}
|
|
262
|
+
```
|
|
263
|
+
|
|
228
264
|
### Webhooks
|
|
229
265
|
|
|
230
266
|
```python
|
|
@@ -236,31 +272,49 @@ ccai = CCAI(
|
|
|
236
272
|
api_key="YOUR-API-KEY"
|
|
237
273
|
)
|
|
238
274
|
|
|
239
|
-
# Register a webhook
|
|
275
|
+
# Example 1: Register a webhook with auto-generated secret
|
|
276
|
+
# If secret is not provided, the server will auto-generate one
|
|
240
277
|
config = WebhookConfig(
|
|
241
278
|
url="https://your-domain.com/api/ccai-webhook",
|
|
242
|
-
events=[WebhookEventType.MESSAGE_SENT, WebhookEventType.MESSAGE_RECEIVED]
|
|
243
|
-
secret
|
|
279
|
+
events=[WebhookEventType.MESSAGE_SENT, WebhookEventType.MESSAGE_RECEIVED]
|
|
280
|
+
# secret not provided - server will auto-generate and return it
|
|
244
281
|
)
|
|
245
282
|
|
|
246
283
|
webhook = ccai.webhook.register(config)
|
|
247
284
|
print(f"Webhook registered with ID: {webhook.id}")
|
|
285
|
+
print(f"Auto-generated Secret: {webhook.secretKey}")
|
|
286
|
+
|
|
287
|
+
# Example 2: Register a webhook with a custom secret
|
|
288
|
+
config_custom = WebhookConfig(
|
|
289
|
+
url="https://your-domain.com/api/ccai-webhook-v2",
|
|
290
|
+
events=[WebhookEventType.MESSAGE_SENT, WebhookEventType.MESSAGE_RECEIVED],
|
|
291
|
+
secret="your-custom-secret-key"
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
webhook_custom = ccai.webhook.register(config_custom)
|
|
295
|
+
print(f"Webhook with custom secret registered: {webhook_custom.id}")
|
|
248
296
|
|
|
249
297
|
# List all webhooks
|
|
250
298
|
webhooks = ccai.webhook.list()
|
|
251
299
|
print(f"Found {len(webhooks)} webhooks")
|
|
252
300
|
|
|
253
301
|
# Update a webhook
|
|
254
|
-
|
|
255
|
-
"
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
print(f"Webhook updated: {updated_webhook}")
|
|
302
|
+
updated_webhook = ccai.webhook.update(webhook.id, {
|
|
303
|
+
"url": "https://your-domain.com/api/ccai-webhook-v3"
|
|
304
|
+
})
|
|
305
|
+
print(f"Webhook updated: {updated_webhook.url}")
|
|
259
306
|
|
|
260
307
|
# Delete a webhook
|
|
261
308
|
result = ccai.webhook.delete(webhook.id)
|
|
262
309
|
print(f"Webhook deleted: {result}")
|
|
263
310
|
|
|
311
|
+
# Verify webhook signature in your handler
|
|
312
|
+
def verify_and_handle_webhook(signature, client_id, event_hash, secret):
|
|
313
|
+
if ccai.webhook.verify_signature(signature, client_id, event_hash, secret):
|
|
314
|
+
print(f"Valid webhook signature verified")
|
|
315
|
+
else:
|
|
316
|
+
print("Invalid signature")
|
|
317
|
+
|
|
264
318
|
# Create a webhook handler for web frameworks
|
|
265
319
|
def handle_message_sent(event):
|
|
266
320
|
print(f"Message sent: {event.message} to {event.to}")
|
|
@@ -277,24 +331,165 @@ webhook_handler = ccai.webhook.create_handler(handlers)
|
|
|
277
331
|
|
|
278
332
|
# Use with Flask
|
|
279
333
|
from flask import Flask, request, jsonify
|
|
334
|
+
import json
|
|
280
335
|
|
|
281
336
|
app = Flask(__name__)
|
|
282
337
|
|
|
283
338
|
@app.route('/api/ccai-webhook', methods=['POST'])
|
|
284
339
|
def handle_webhook():
|
|
285
|
-
|
|
340
|
+
signature = request.headers.get('X-CCAI-Signature', '')
|
|
341
|
+
body = request.get_data(as_text=True)
|
|
342
|
+
secret = 'your-webhook-secret-key' # Use the secret from webhook registration
|
|
343
|
+
|
|
344
|
+
# Parse payload to get client_id and event_hash
|
|
345
|
+
payload = json.loads(body)
|
|
346
|
+
client_id = os.getenv('CCAI_CLIENT_ID')
|
|
347
|
+
event_hash = payload.get('eventHash', '')
|
|
348
|
+
|
|
349
|
+
# Verify signature
|
|
350
|
+
if not ccai.webhook.verify_signature(signature, client_id, event_hash, secret):
|
|
351
|
+
return jsonify({"error": "Invalid signature"}), 401
|
|
352
|
+
|
|
353
|
+
# Process webhook
|
|
286
354
|
result = webhook_handler(payload)
|
|
287
355
|
return jsonify(result)
|
|
288
356
|
```
|
|
289
357
|
|
|
358
|
+
### Brands
|
|
359
|
+
|
|
360
|
+
Register and manage brands for TCR (The Campaign Registry) business verification.
|
|
361
|
+
|
|
362
|
+
```python
|
|
363
|
+
from ccai_python import CCAI
|
|
364
|
+
|
|
365
|
+
ccai = CCAI(
|
|
366
|
+
client_id="YOUR-CLIENT-ID",
|
|
367
|
+
api_key="YOUR-API-KEY"
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
# Create a brand
|
|
371
|
+
brand = ccai.brands.create({
|
|
372
|
+
"legalCompanyName": "Collect.org Inc.",
|
|
373
|
+
"dba": "Collect",
|
|
374
|
+
"entityType": "NON_PROFIT",
|
|
375
|
+
"taxId": "123456789",
|
|
376
|
+
"taxIdCountry": "US",
|
|
377
|
+
"country": "US",
|
|
378
|
+
"verticalType": "NON_PROFIT",
|
|
379
|
+
"websiteUrl": "https://www.collect.org",
|
|
380
|
+
"street": "123 Main Street",
|
|
381
|
+
"city": "San Francisco",
|
|
382
|
+
"state": "CA",
|
|
383
|
+
"postalCode": "94105",
|
|
384
|
+
"contactFirstName": "Jane",
|
|
385
|
+
"contactLastName": "Doe",
|
|
386
|
+
"contactEmail": "jane@collect.org",
|
|
387
|
+
"contactPhone": "+14155551234",
|
|
388
|
+
})
|
|
389
|
+
print(f"Brand created with ID: {brand['id']}")
|
|
390
|
+
|
|
391
|
+
# Get a brand by ID
|
|
392
|
+
fetched = ccai.brands.get(brand["id"])
|
|
393
|
+
print(f"Website match score: {fetched.get('websiteMatchScore')}")
|
|
394
|
+
|
|
395
|
+
# List all brands for the account
|
|
396
|
+
brands = ccai.brands.list()
|
|
397
|
+
print(f"Found {len(brands)} brand(s)")
|
|
398
|
+
|
|
399
|
+
# Update a brand (partial update)
|
|
400
|
+
updated = ccai.brands.update(brand["id"], {
|
|
401
|
+
"street": "456 Oak Avenue",
|
|
402
|
+
"city": "Los Angeles",
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
# Delete a brand
|
|
406
|
+
ccai.brands.delete(brand["id"])
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
#### Entity Types
|
|
410
|
+
|
|
411
|
+
`PRIVATE_PROFIT`, `PUBLIC_PROFIT`, `NON_PROFIT`, `GOVERNMENT`, `SOLE_PROPRIETOR`
|
|
412
|
+
|
|
413
|
+
> Note: `PUBLIC_PROFIT` entities require `stockSymbol` and `stockExchange` fields.
|
|
414
|
+
|
|
415
|
+
#### Vertical Types
|
|
416
|
+
|
|
417
|
+
`AUTOMOTIVE`, `AGRICULTURE`, `BANKING`, `COMMUNICATION`, `CONSTRUCTION`, `EDUCATION`, `ENERGY`, `ENTERTAINMENT`, `GOVERNMENT`, `HEALTHCARE`, `HOSPITALITY`, `INSURANCE`, `LEGAL`, `MANUFACTURING`, `NON_PROFIT`, `PROFESSIONAL`, `REAL_ESTATE`, `RETAIL`, `TECHNOLOGY`, `TRANSPORTATION`
|
|
418
|
+
|
|
419
|
+
### Campaigns
|
|
420
|
+
|
|
421
|
+
Register and manage campaigns for TCR (The Campaign Registry) carrier vetting. Each campaign must be linked to a verified brand.
|
|
422
|
+
|
|
423
|
+
```python
|
|
424
|
+
from ccai_python import CCAI
|
|
425
|
+
|
|
426
|
+
ccai = CCAI(
|
|
427
|
+
client_id="YOUR-CLIENT-ID",
|
|
428
|
+
api_key="YOUR-API-KEY"
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
# Create a campaign
|
|
432
|
+
campaign = ccai.campaigns.create({
|
|
433
|
+
"brandId": 1,
|
|
434
|
+
"useCase": "MIXED",
|
|
435
|
+
"subUseCases": ["CUSTOMER_CARE", "TWO_FACTOR_AUTHENTICATION", "ACCOUNT_NOTIFICATION"],
|
|
436
|
+
"description": "Security codes and support messaging.",
|
|
437
|
+
"messageFlow": "Users opt-in via signup form at https://example.com/signup",
|
|
438
|
+
"hasEmbeddedLinks": True,
|
|
439
|
+
"hasEmbeddedPhone": False,
|
|
440
|
+
"isAgeGated": False,
|
|
441
|
+
"isDirectLending": False,
|
|
442
|
+
"optInKeywords": ["START"],
|
|
443
|
+
"optInMessage": "Welcome! Reply STOP to cancel.",
|
|
444
|
+
"optInProofUrl": "https://example.com/opt-in-proof.png",
|
|
445
|
+
"helpKeywords": ["HELP"],
|
|
446
|
+
"helpMessage": "For HELP email support@example.com.",
|
|
447
|
+
"optOutKeywords": ["STOP"],
|
|
448
|
+
"optOutMessage": "STOP received. You are unsubscribed.",
|
|
449
|
+
"sampleMessages": [
|
|
450
|
+
"Your code is 554321. Reply STOP to cancel.",
|
|
451
|
+
"Your ticket has been updated. Reply HELP for info."
|
|
452
|
+
]
|
|
453
|
+
})
|
|
454
|
+
print(f"Campaign created with ID: {campaign['id']}")
|
|
455
|
+
|
|
456
|
+
# Get a campaign by ID
|
|
457
|
+
fetched = ccai.campaigns.get(campaign["id"])
|
|
458
|
+
|
|
459
|
+
# List all campaigns for the account
|
|
460
|
+
campaigns = ccai.campaigns.list()
|
|
461
|
+
print(f"Found {len(campaigns)} campaign(s)")
|
|
462
|
+
|
|
463
|
+
# Update a campaign (partial update)
|
|
464
|
+
updated = ccai.campaigns.update(campaign["id"], {
|
|
465
|
+
"description": "Updated description."
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
# Delete a campaign
|
|
469
|
+
ccai.campaigns.delete(campaign["id"])
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
#### Use Cases
|
|
473
|
+
|
|
474
|
+
`TWO_FACTOR_AUTHENTICATION`, `ACCOUNT_NOTIFICATION`, `CUSTOMER_CARE`, `DELIVERY_NOTIFICATION`, `FRAUD_ALERT`, `HIGHER_EDUCATION`, `LOW_VOLUME_MIXED`, `MARKETING`, `MIXED`, `POLLING_VOTING`, `PUBLIC_SERVICE_ANNOUNCEMENT`, `SECURITY_ALERT`
|
|
475
|
+
|
|
476
|
+
> Note: `MIXED` and `LOW_VOLUME_MIXED` campaigns require 2–3 `subUseCases`.
|
|
477
|
+
|
|
478
|
+
#### Sub-Use Cases
|
|
479
|
+
|
|
480
|
+
`TWO_FACTOR_AUTHENTICATION`, `ACCOUNT_NOTIFICATION`, `CUSTOMER_CARE`, `DELIVERY_NOTIFICATION`, `FRAUD_ALERT`, `MARKETING`, `POLLING_VOTING`
|
|
481
|
+
|
|
290
482
|
## Features
|
|
291
483
|
|
|
292
484
|
- Send SMS messages to single or multiple recipients
|
|
293
485
|
- Send MMS messages with images
|
|
294
486
|
- Send Email campaigns with HTML content
|
|
295
487
|
- Schedule emails for future delivery
|
|
488
|
+
- Brand registration and management for TCR verification
|
|
489
|
+
- Campaign registration and management for TCR carrier vetting
|
|
296
490
|
- Webhook management (register, update, list, delete)
|
|
297
491
|
- Webhook event handling for web frameworks
|
|
492
|
+
- Validate email addresses (valid/invalid/risky) and phone numbers (valid/invalid/landline)
|
|
298
493
|
- Upload images to S3 with signed URLs
|
|
299
494
|
- Variable substitution in messages
|
|
300
495
|
- Progress tracking callbacks
|