autotouch-cli 0.2.13__tar.gz → 0.2.17__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 (63) hide show
  1. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/PKG-INFO +28 -1
  2. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/autotouch_cli.egg-info/PKG-INFO +28 -1
  3. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/autotouch_cli.egg-info/SOURCES.txt +1 -0
  4. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/docs/research-table/reference/autotouch-cli-pypi.md +27 -0
  5. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/pyproject.toml +1 -1
  6. autotouch_cli-0.2.17/scripts/migrations/20260303_add_webhook_subscription_collections.py +124 -0
  7. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/smart_table_cli.py +300 -0
  8. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/autotouch_cli.egg-info/dependency_links.txt +0 -0
  9. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/autotouch_cli.egg-info/entry_points.txt +0 -0
  10. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/autotouch_cli.egg-info/requires.txt +0 -0
  11. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/autotouch_cli.egg-info/top_level.txt +0 -0
  12. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/__init__.py +0 -0
  13. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/add_column_unique_index.py +0 -0
  14. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/attach_csv_import_leads_to_research_table.py +0 -0
  15. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/bundle_sequences_backend.py +0 -0
  16. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/check_agent_traces.py +0 -0
  17. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/check_column_mode.py +0 -0
  18. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/exit_terminal_leads_from_sequences.py +0 -0
  19. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/fetch_lead.py +0 -0
  20. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/fix_lead_titles_from_csv.py +0 -0
  21. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250106_add_column_position.py +0 -0
  22. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250108_fix_legacy_column_fields.py +0 -0
  23. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250109_add_user_fields_to_tables.py +0 -0
  24. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250117_add_call_logs_webhook_indexes.py +0 -0
  25. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250117_rename_call_logs_collection.py +0 -0
  26. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250119_create_leads_unique_email_index.py +0 -0
  27. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250123_add_filter_indexes.py +0 -0
  28. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250123_add_llm_responses_collection.py +0 -0
  29. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250128_migrate_user_ids_to_objectid.py +0 -0
  30. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250208_backfill_task_research_values.py +0 -0
  31. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250604_add_origin_indexes.py +0 -0
  32. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250608_cleanup_agent_metadata.py +0 -0
  33. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250608_rename_agent_metadata_to_metadata.py +0 -0
  34. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250922_add_activity_indexes.py +0 -0
  35. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250926_migrate_single_to_arrays.py +0 -0
  36. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250928_add_missing_timestamp_fields.py +0 -0
  37. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250929_add_task_join_indexes.py +0 -0
  38. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250929_add_task_join_indexes_safe.py +0 -0
  39. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20250929_create_shared_phone_cache.py +0 -0
  40. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20251007_add_rows_position_id_index.py +0 -0
  41. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20251109_add_ttl_for_llm_and_preview_traces.py +0 -0
  42. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20260113_normalize_table_filter_operators.py +0 -0
  43. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20260113_set_user_permissions_user_admin.py +0 -0
  44. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/20260204_sync_lead_owner_from_tasks.py +0 -0
  45. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/migrate_org_user_credits.py +0 -0
  46. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/set_default_lead_status.py +0 -0
  47. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/migrations/update_lead_owner_from_tasks.py +0 -0
  48. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/reassign_sequence_owner.py +0 -0
  49. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/run_sidecar_orchestrator_demo.py +0 -0
  50. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/test_crm_company_policy.py +0 -0
  51. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/test_sequences_instantly_e2e.py +0 -0
  52. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/test_sequences_personal_e2e.py +0 -0
  53. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/test_task_error_logger.py +0 -0
  54. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/scripts/verify_azurite_voicemail.py +0 -0
  55. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/setup.cfg +0 -0
  56. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/tests/test_contactout_custom.py +0 -0
  57. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/tests/test_contactout_integration.py +0 -0
  58. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/tests/test_contactout_multi_titles.py +0 -0
  59. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/tests/test_contactout_pipeline.py +0 -0
  60. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/tests/test_contactout_simple.py +0 -0
  61. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/tests/test_contactout_v2_bulk.py +0 -0
  62. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/tests/test_lead_required_fields.py +0 -0
  63. {autotouch_cli-0.2.13 → autotouch_cli-0.2.17}/tests/test_phone_provider_pipeline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autotouch-cli
3
- Version: 0.2.13
3
+ Version: 0.2.17
4
4
  Summary: Autotouch Smart Table CLI
5
5
  Requires-Python: >=3.9
6
6
  Description-Content-Type: text/markdown
@@ -187,6 +187,33 @@ Important:
187
187
  - These workflow routes support `actorUserId` query parameter.
188
188
  - External sequence validation rules (manual vs automated vs AI draft constraints) are documented in the workflow reference above.
189
189
 
190
+ ## Outbound webhook subscriptions
191
+
192
+ Use webhook subscriptions to receive customer-facing event notifications.
193
+
194
+ ```bash
195
+ autotouch webhooks subscriptions list
196
+
197
+ autotouch webhooks subscriptions create \
198
+ --url https://example.com/webhooks/smart-table \
199
+ --events bulk_job.* lead.status_changed sequence_enrollment.created task.created
200
+
201
+ autotouch webhooks subscriptions test \
202
+ --subscription-id <SUBSCRIPTION_ID> \
203
+ --event-type lead.created \
204
+ --data-json '{"ping":"ok"}'
205
+ autotouch webhooks deliveries list --subscription-id <SUBSCRIPTION_ID>
206
+ autotouch webhooks deliveries attempts --delivery-id <DELIVERY_ID>
207
+ ```
208
+
209
+ Developer key scopes:
210
+ - `webhooks:read`
211
+ - `webhooks:write`
212
+
213
+ Retention note:
214
+ - Webhook event cache and delivery-attempt logs default to 7 days
215
+ (`WEBHOOK_EVENTS_TTL_DAYS`, `WEBHOOK_DELIVERY_ATTEMPTS_TTL_DAYS`).
216
+
190
217
  ## Create basic/manual fields (text, number, date, etc.)
191
218
 
192
219
  Use `kind=manual` for non-enrichment columns.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autotouch-cli
3
- Version: 0.2.13
3
+ Version: 0.2.17
4
4
  Summary: Autotouch Smart Table CLI
5
5
  Requires-Python: >=3.9
6
6
  Description-Content-Type: text/markdown
@@ -187,6 +187,33 @@ Important:
187
187
  - These workflow routes support `actorUserId` query parameter.
188
188
  - External sequence validation rules (manual vs automated vs AI draft constraints) are documented in the workflow reference above.
189
189
 
190
+ ## Outbound webhook subscriptions
191
+
192
+ Use webhook subscriptions to receive customer-facing event notifications.
193
+
194
+ ```bash
195
+ autotouch webhooks subscriptions list
196
+
197
+ autotouch webhooks subscriptions create \
198
+ --url https://example.com/webhooks/smart-table \
199
+ --events bulk_job.* lead.status_changed sequence_enrollment.created task.created
200
+
201
+ autotouch webhooks subscriptions test \
202
+ --subscription-id <SUBSCRIPTION_ID> \
203
+ --event-type lead.created \
204
+ --data-json '{"ping":"ok"}'
205
+ autotouch webhooks deliveries list --subscription-id <SUBSCRIPTION_ID>
206
+ autotouch webhooks deliveries attempts --delivery-id <DELIVERY_ID>
207
+ ```
208
+
209
+ Developer key scopes:
210
+ - `webhooks:read`
211
+ - `webhooks:write`
212
+
213
+ Retention note:
214
+ - Webhook event cache and delivery-attempt logs default to 7 days
215
+ (`WEBHOOK_EVENTS_TTL_DAYS`, `WEBHOOK_DELIVERY_ATTEMPTS_TTL_DAYS`).
216
+
190
217
  ## Create basic/manual fields (text, number, date, etc.)
191
218
 
192
219
  Use `kind=manual` for non-enrichment columns.
@@ -47,6 +47,7 @@ scripts/migrations/20251109_add_ttl_for_llm_and_preview_traces.py
47
47
  scripts/migrations/20260113_normalize_table_filter_operators.py
48
48
  scripts/migrations/20260113_set_user_permissions_user_admin.py
49
49
  scripts/migrations/20260204_sync_lead_owner_from_tasks.py
50
+ scripts/migrations/20260303_add_webhook_subscription_collections.py
50
51
  scripts/migrations/migrate_org_user_credits.py
51
52
  scripts/migrations/set_default_lead_status.py
52
53
  scripts/migrations/update_lead_owner_from_tasks.py
@@ -178,6 +178,33 @@ Important:
178
178
  - These workflow routes support `actorUserId` query parameter.
179
179
  - External sequence validation rules (manual vs automated vs AI draft constraints) are documented in the workflow reference above.
180
180
 
181
+ ## Outbound webhook subscriptions
182
+
183
+ Use webhook subscriptions to receive customer-facing event notifications.
184
+
185
+ ```bash
186
+ autotouch webhooks subscriptions list
187
+
188
+ autotouch webhooks subscriptions create \
189
+ --url https://example.com/webhooks/smart-table \
190
+ --events bulk_job.* lead.status_changed sequence_enrollment.created task.created
191
+
192
+ autotouch webhooks subscriptions test \
193
+ --subscription-id <SUBSCRIPTION_ID> \
194
+ --event-type lead.created \
195
+ --data-json '{"ping":"ok"}'
196
+ autotouch webhooks deliveries list --subscription-id <SUBSCRIPTION_ID>
197
+ autotouch webhooks deliveries attempts --delivery-id <DELIVERY_ID>
198
+ ```
199
+
200
+ Developer key scopes:
201
+ - `webhooks:read`
202
+ - `webhooks:write`
203
+
204
+ Retention note:
205
+ - Webhook event cache and delivery-attempt logs default to 7 days
206
+ (`WEBHOOK_EVENTS_TTL_DAYS`, `WEBHOOK_DELIVERY_ATTEMPTS_TTL_DAYS`).
207
+
181
208
  ## Create basic/manual fields (text, number, date, etc.)
182
209
 
183
210
  Use `kind=manual` for non-enrichment columns.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "autotouch-cli"
7
- version = "0.2.13"
7
+ version = "0.2.17"
8
8
  description = "Autotouch Smart Table CLI"
9
9
  readme = "docs/research-table/reference/autotouch-cli-pypi.md"
10
10
  requires-python = ">=3.9"
@@ -0,0 +1,124 @@
1
+ """
2
+ Create outbound webhook subscription/outbox collections and indexes.
3
+ Also ensures 7-day default TTL retention for webhook event cache and attempt logs
4
+ (configurable via WEBHOOK_EVENTS_TTL_DAYS / WEBHOOK_DELIVERY_ATTEMPTS_TTL_DAYS).
5
+
6
+ Usage:
7
+ python3 scripts/migrations/20260303_add_webhook_subscription_collections.py \
8
+ --uri "<mongodb uri>" --db autotouch
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import os
15
+ from pymongo import MongoClient
16
+
17
+
18
+ WEBHOOK_EVENTS_TTL_DAYS = max(1, min(365, int(os.getenv("WEBHOOK_EVENTS_TTL_DAYS", "7") or 7)))
19
+ WEBHOOK_DELIVERY_ATTEMPTS_TTL_DAYS = max(
20
+ 1, min(365, int(os.getenv("WEBHOOK_DELIVERY_ATTEMPTS_TTL_DAYS", "7") or 7))
21
+ )
22
+ WEBHOOK_EVENTS_TTL_SECONDS = WEBHOOK_EVENTS_TTL_DAYS * 24 * 60 * 60
23
+ WEBHOOK_DELIVERY_ATTEMPTS_TTL_SECONDS = WEBHOOK_DELIVERY_ATTEMPTS_TTL_DAYS * 24 * 60 * 60
24
+
25
+
26
+ def ensure_indexes(db) -> None:
27
+ db.webhook_subscriptions.create_index(
28
+ [("organization_id", 1), ("enabled", 1), ("updated_at", -1)],
29
+ name="webhook_subscriptions_org_enabled_updated",
30
+ background=True,
31
+ )
32
+ db.webhook_subscriptions.create_index(
33
+ [("organization_id", 1), ("events", 1)],
34
+ name="webhook_subscriptions_org_events",
35
+ background=True,
36
+ )
37
+
38
+ db.webhook_events.create_index(
39
+ [("event_id", 1)],
40
+ name="webhook_events_event_id_unique",
41
+ unique=True,
42
+ background=True,
43
+ )
44
+ db.webhook_events.create_index(
45
+ [("organization_id", 1), ("occurred_at", -1)],
46
+ name="webhook_events_org_occurred",
47
+ background=True,
48
+ )
49
+ db.webhook_events.create_index(
50
+ [("type", 1), ("occurred_at", -1)],
51
+ name="webhook_events_type_occurred",
52
+ background=True,
53
+ )
54
+ db.webhook_events.create_index(
55
+ [("created_at", 1)],
56
+ name="webhook_events_created_ttl",
57
+ expireAfterSeconds=WEBHOOK_EVENTS_TTL_SECONDS,
58
+ background=True,
59
+ )
60
+
61
+ db.webhook_deliveries.create_index(
62
+ [("delivery_id", 1)],
63
+ name="webhook_deliveries_delivery_id_unique",
64
+ unique=True,
65
+ background=True,
66
+ )
67
+ db.webhook_deliveries.create_index(
68
+ [("organization_id", 1), ("status", 1), ("created_at", -1)],
69
+ name="webhook_deliveries_org_status_created",
70
+ background=True,
71
+ )
72
+ db.webhook_deliveries.create_index(
73
+ [("subscription_id", 1), ("created_at", -1)],
74
+ name="webhook_deliveries_subscription_created",
75
+ background=True,
76
+ )
77
+ db.webhook_deliveries.create_index(
78
+ [("next_attempt_at", 1), ("status", 1)],
79
+ name="webhook_deliveries_next_attempt_status",
80
+ background=True,
81
+ )
82
+
83
+ db.webhook_delivery_attempts.create_index(
84
+ [("delivery_id", 1), ("attempt_number", 1)],
85
+ name="webhook_delivery_attempts_delivery_attempt_unique",
86
+ unique=True,
87
+ background=True,
88
+ )
89
+ db.webhook_delivery_attempts.create_index(
90
+ [("delivery_id", 1), ("created_at", -1)],
91
+ name="webhook_delivery_attempts_delivery_created",
92
+ background=True,
93
+ )
94
+ db.webhook_delivery_attempts.create_index(
95
+ [("created_at", 1)],
96
+ name="webhook_delivery_attempts_created_ttl",
97
+ expireAfterSeconds=WEBHOOK_DELIVERY_ATTEMPTS_TTL_SECONDS,
98
+ background=True,
99
+ )
100
+
101
+
102
+ def main() -> None:
103
+ parser = argparse.ArgumentParser(description="Ensure webhook subscription/outbox indexes")
104
+ parser.add_argument("--uri", required=True, help="MongoDB URI")
105
+ parser.add_argument("--db", default="autotouch", help="Database name")
106
+ parser.add_argument(
107
+ "--tls-insecure",
108
+ action="store_true",
109
+ help="Allow invalid TLS certificates (for local trust-store issues)",
110
+ )
111
+ args = parser.parse_args()
112
+
113
+ client_kwargs = {}
114
+ if args.tls_insecure:
115
+ client_kwargs["tlsAllowInvalidCertificates"] = True
116
+
117
+ client = MongoClient(args.uri, **client_kwargs)
118
+ db = client[args.db]
119
+ ensure_indexes(db)
120
+ print("Webhook subscription indexes ensured")
121
+
122
+
123
+ if __name__ == "__main__":
124
+ main()
@@ -2718,6 +2718,225 @@ def cmd_webhooks_ingest(args: argparse.Namespace) -> None:
2718
2718
  _print_json(data, compact=args.compact)
2719
2719
 
2720
2720
 
2721
+ def cmd_webhooks_subscriptions_list(args: argparse.Namespace) -> None:
2722
+ token = _resolve_token(args.token, required=True)
2723
+ params: Dict[str, Any] = {"limit": int(args.limit or 100)}
2724
+ if args.include_disabled:
2725
+ params["includeDisabled"] = True
2726
+ data = _request_api(
2727
+ "GET",
2728
+ "/api/webhook-subscriptions",
2729
+ base_url=args.base_url,
2730
+ token=token,
2731
+ use_x_api_key=args.use_x_api_key,
2732
+ params=params,
2733
+ timeout=args.timeout,
2734
+ verbose=args.verbose,
2735
+ )
2736
+ _print_json(data, compact=args.compact)
2737
+
2738
+
2739
+ def cmd_webhooks_subscriptions_create(args: argparse.Namespace) -> None:
2740
+ token = _resolve_token(args.token, required=True)
2741
+ payload = _load_json_input(
2742
+ inline_json=args.data_json,
2743
+ file_path=args.data_file,
2744
+ context="data",
2745
+ default=None,
2746
+ )
2747
+ if payload is None:
2748
+ payload = {
2749
+ "url": args.url,
2750
+ "events": args.events or [],
2751
+ "enabled": not bool(args.paused),
2752
+ "filters": _load_json_input(
2753
+ inline_json=args.filters_json,
2754
+ file_path=args.filters_file,
2755
+ context="filters",
2756
+ default={},
2757
+ )
2758
+ or {},
2759
+ "metadata": _load_json_input(
2760
+ inline_json=args.metadata_json,
2761
+ file_path=args.metadata_file,
2762
+ context="metadata",
2763
+ default={},
2764
+ )
2765
+ or {},
2766
+ }
2767
+ if args.retry_policy_json or args.retry_policy_file:
2768
+ payload["retryPolicy"] = _load_json_input(
2769
+ inline_json=args.retry_policy_json,
2770
+ file_path=args.retry_policy_file,
2771
+ context="retry-policy",
2772
+ default={},
2773
+ ) or {}
2774
+ data = _request_api(
2775
+ "POST",
2776
+ "/api/webhook-subscriptions",
2777
+ base_url=args.base_url,
2778
+ token=token,
2779
+ use_x_api_key=args.use_x_api_key,
2780
+ payload=payload,
2781
+ timeout=args.timeout,
2782
+ verbose=args.verbose,
2783
+ )
2784
+ _print_json(data, compact=args.compact)
2785
+
2786
+
2787
+ def cmd_webhooks_subscriptions_get(args: argparse.Namespace) -> None:
2788
+ token = _resolve_token(args.token, required=True)
2789
+ data = _request_api(
2790
+ "GET",
2791
+ f"/api/webhook-subscriptions/{args.subscription_id}",
2792
+ base_url=args.base_url,
2793
+ token=token,
2794
+ use_x_api_key=args.use_x_api_key,
2795
+ timeout=args.timeout,
2796
+ verbose=args.verbose,
2797
+ )
2798
+ _print_json(data, compact=args.compact)
2799
+
2800
+
2801
+ def cmd_webhooks_subscriptions_update(args: argparse.Namespace) -> None:
2802
+ token = _resolve_token(args.token, required=True)
2803
+ payload = _load_json_input(
2804
+ inline_json=args.data_json,
2805
+ file_path=args.data_file,
2806
+ context="data",
2807
+ default={},
2808
+ )
2809
+ data = _request_api(
2810
+ "PATCH",
2811
+ f"/api/webhook-subscriptions/{args.subscription_id}",
2812
+ base_url=args.base_url,
2813
+ token=token,
2814
+ use_x_api_key=args.use_x_api_key,
2815
+ payload=payload,
2816
+ timeout=args.timeout,
2817
+ verbose=args.verbose,
2818
+ )
2819
+ _print_json(data, compact=args.compact)
2820
+
2821
+
2822
+ def cmd_webhooks_subscriptions_delete(args: argparse.Namespace) -> None:
2823
+ token = _resolve_token(args.token, required=True)
2824
+ data = _request_api(
2825
+ "DELETE",
2826
+ f"/api/webhook-subscriptions/{args.subscription_id}",
2827
+ base_url=args.base_url,
2828
+ token=token,
2829
+ use_x_api_key=args.use_x_api_key,
2830
+ timeout=args.timeout,
2831
+ verbose=args.verbose,
2832
+ )
2833
+ _print_json(data, compact=args.compact)
2834
+
2835
+
2836
+ def cmd_webhooks_subscriptions_pause(args: argparse.Namespace) -> None:
2837
+ token = _resolve_token(args.token, required=True)
2838
+ data = _request_api(
2839
+ "POST",
2840
+ f"/api/webhook-subscriptions/{args.subscription_id}/pause",
2841
+ base_url=args.base_url,
2842
+ token=token,
2843
+ use_x_api_key=args.use_x_api_key,
2844
+ timeout=args.timeout,
2845
+ verbose=args.verbose,
2846
+ )
2847
+ _print_json(data, compact=args.compact)
2848
+
2849
+
2850
+ def cmd_webhooks_subscriptions_resume(args: argparse.Namespace) -> None:
2851
+ token = _resolve_token(args.token, required=True)
2852
+ data = _request_api(
2853
+ "POST",
2854
+ f"/api/webhook-subscriptions/{args.subscription_id}/resume",
2855
+ base_url=args.base_url,
2856
+ token=token,
2857
+ use_x_api_key=args.use_x_api_key,
2858
+ timeout=args.timeout,
2859
+ verbose=args.verbose,
2860
+ )
2861
+ _print_json(data, compact=args.compact)
2862
+
2863
+
2864
+ def cmd_webhooks_subscriptions_rotate_secret(args: argparse.Namespace) -> None:
2865
+ token = _resolve_token(args.token, required=True)
2866
+ data = _request_api(
2867
+ "POST",
2868
+ f"/api/webhook-subscriptions/{args.subscription_id}/rotate-secret",
2869
+ base_url=args.base_url,
2870
+ token=token,
2871
+ use_x_api_key=args.use_x_api_key,
2872
+ timeout=args.timeout,
2873
+ verbose=args.verbose,
2874
+ )
2875
+ _print_json(data, compact=args.compact)
2876
+
2877
+
2878
+ def cmd_webhooks_subscriptions_test(args: argparse.Namespace) -> None:
2879
+ token = _resolve_token(args.token, required=True)
2880
+ payload = _load_json_input(
2881
+ inline_json=args.data_json,
2882
+ file_path=args.data_file,
2883
+ context="data",
2884
+ default={},
2885
+ )
2886
+ request_payload: Dict[str, Any] = {"data": payload or {}}
2887
+ if getattr(args, "event_type", None):
2888
+ request_payload["eventType"] = str(args.event_type).strip()
2889
+ data = _request_api(
2890
+ "POST",
2891
+ f"/api/webhook-subscriptions/{args.subscription_id}/test",
2892
+ base_url=args.base_url,
2893
+ token=token,
2894
+ use_x_api_key=args.use_x_api_key,
2895
+ payload=request_payload,
2896
+ timeout=args.timeout,
2897
+ verbose=args.verbose,
2898
+ )
2899
+ _print_json(data, compact=args.compact)
2900
+
2901
+
2902
+ def cmd_webhooks_deliveries_list(args: argparse.Namespace) -> None:
2903
+ token = _resolve_token(args.token, required=True)
2904
+ params: Dict[str, Any] = {"limit": int(args.limit or 100)}
2905
+ if args.subscription_id:
2906
+ params["subscriptionId"] = args.subscription_id
2907
+ if args.status:
2908
+ params["status"] = args.status
2909
+ if args.event_type:
2910
+ params["eventType"] = args.event_type
2911
+ data = _request_api(
2912
+ "GET",
2913
+ "/api/webhook-subscriptions/deliveries",
2914
+ base_url=args.base_url,
2915
+ token=token,
2916
+ use_x_api_key=args.use_x_api_key,
2917
+ params=params,
2918
+ timeout=args.timeout,
2919
+ verbose=args.verbose,
2920
+ )
2921
+ _print_json(data, compact=args.compact)
2922
+
2923
+
2924
+ def cmd_webhooks_deliveries_attempts(args: argparse.Namespace) -> None:
2925
+ token = _resolve_token(args.token, required=True)
2926
+ params: Dict[str, Any] = {"limit": int(args.limit or 100)}
2927
+ data = _request_api(
2928
+ "GET",
2929
+ f"/api/webhook-subscriptions/deliveries/{args.delivery_id}/attempts",
2930
+ base_url=args.base_url,
2931
+ token=token,
2932
+ use_x_api_key=args.use_x_api_key,
2933
+ params=params,
2934
+ timeout=args.timeout,
2935
+ verbose=args.verbose,
2936
+ )
2937
+ _print_json(data, compact=args.compact)
2938
+
2939
+
2721
2940
  def _mongo_client(uri: Optional[str], db_name: Optional[str]):
2722
2941
  if MongoClient is None:
2723
2942
  print("ERROR: pymongo not installed. Install requirements and retry.", file=sys.stderr)
@@ -3109,6 +3328,87 @@ def build_parser() -> argparse.ArgumentParser:
3109
3328
  pwhi.add_argument("--verbose", action="store_true", help="Print request metadata to stderr")
3110
3329
  pwhi.set_defaults(func=cmd_webhooks_ingest)
3111
3330
 
3331
+ pwhs = wh_sub.add_parser("subscriptions", help="Manage outbound webhook subscriptions")
3332
+ whs_sub = pwhs.add_subparsers(dest="webhooks_subscriptions_cmd", required=True)
3333
+
3334
+ pwhsl = whs_sub.add_parser("list", help="List webhook subscriptions")
3335
+ pwhsl.add_argument("--include-disabled", action="store_true", help="Include paused/disabled subscriptions")
3336
+ pwhsl.add_argument("--limit", type=int, default=100, help="Max subscriptions to return (1-500)")
3337
+ _add_api_common_arguments(pwhsl)
3338
+ pwhsl.set_defaults(func=cmd_webhooks_subscriptions_list)
3339
+
3340
+ pwhsc = whs_sub.add_parser("create", help="Create a webhook subscription")
3341
+ pwhsc.add_argument("--url", help="Webhook endpoint URL")
3342
+ pwhsc.add_argument("--events", nargs="*", help="Event names or families (for example bulk_job.*)")
3343
+ pwhsc.add_argument("--paused", action="store_true", help="Create subscription as paused/disabled")
3344
+ pwhsc.add_argument("--filters-json", help="Optional filters JSON")
3345
+ pwhsc.add_argument("--filters-file", help="Optional filters JSON file")
3346
+ pwhsc.add_argument("--metadata-json", help="Optional metadata JSON")
3347
+ pwhsc.add_argument("--metadata-file", help="Optional metadata JSON file")
3348
+ pwhsc.add_argument("--retry-policy-json", help="Optional retryPolicy JSON")
3349
+ pwhsc.add_argument("--retry-policy-file", help="Optional retryPolicy JSON file")
3350
+ pwhsc.add_argument("--data-json", help="Full request payload JSON")
3351
+ pwhsc.add_argument("--data-file", help="Full request payload JSON file")
3352
+ _add_api_common_arguments(pwhsc)
3353
+ pwhsc.set_defaults(func=cmd_webhooks_subscriptions_create)
3354
+
3355
+ pwhsg = whs_sub.add_parser("get", help="Get a webhook subscription")
3356
+ pwhsg.add_argument("--subscription-id", required=True)
3357
+ _add_api_common_arguments(pwhsg)
3358
+ pwhsg.set_defaults(func=cmd_webhooks_subscriptions_get)
3359
+
3360
+ pwhsu = whs_sub.add_parser("update", help="Update a webhook subscription")
3361
+ pwhsu.add_argument("--subscription-id", required=True)
3362
+ pwhsu.add_argument("--data-json", help="Patch payload JSON")
3363
+ pwhsu.add_argument("--data-file", help="Patch payload JSON file")
3364
+ _add_api_common_arguments(pwhsu)
3365
+ pwhsu.set_defaults(func=cmd_webhooks_subscriptions_update)
3366
+
3367
+ pwhsd = whs_sub.add_parser("delete", help="Delete a webhook subscription")
3368
+ pwhsd.add_argument("--subscription-id", required=True)
3369
+ _add_api_common_arguments(pwhsd)
3370
+ pwhsd.set_defaults(func=cmd_webhooks_subscriptions_delete)
3371
+
3372
+ pwhsp = whs_sub.add_parser("pause", help="Pause a webhook subscription")
3373
+ pwhsp.add_argument("--subscription-id", required=True)
3374
+ _add_api_common_arguments(pwhsp)
3375
+ pwhsp.set_defaults(func=cmd_webhooks_subscriptions_pause)
3376
+
3377
+ pwhsr = whs_sub.add_parser("resume", help="Resume a paused webhook subscription")
3378
+ pwhsr.add_argument("--subscription-id", required=True)
3379
+ _add_api_common_arguments(pwhsr)
3380
+ pwhsr.set_defaults(func=cmd_webhooks_subscriptions_resume)
3381
+
3382
+ pwhsrs = whs_sub.add_parser("rotate-secret", help="Rotate webhook subscription signing secret")
3383
+ pwhsrs.add_argument("--subscription-id", required=True)
3384
+ _add_api_common_arguments(pwhsrs)
3385
+ pwhsrs.set_defaults(func=cmd_webhooks_subscriptions_rotate_secret)
3386
+
3387
+ pwhst = whs_sub.add_parser("test", help="Fire a test event for a subscription")
3388
+ pwhst.add_argument("--subscription-id", required=True)
3389
+ pwhst.add_argument("--event-type", help="Optional event type (for example lead.created)")
3390
+ pwhst.add_argument("--data-json", help="Optional test payload JSON")
3391
+ pwhst.add_argument("--data-file", help="Optional test payload JSON file")
3392
+ _add_api_common_arguments(pwhst)
3393
+ pwhst.set_defaults(func=cmd_webhooks_subscriptions_test)
3394
+
3395
+ pwhd = wh_sub.add_parser("deliveries", help="Inspect webhook delivery outcomes")
3396
+ whd_sub = pwhd.add_subparsers(dest="webhooks_deliveries_cmd", required=True)
3397
+
3398
+ pwhdl = whd_sub.add_parser("list", help="List webhook deliveries")
3399
+ pwhdl.add_argument("--subscription-id", help="Filter by subscription id")
3400
+ pwhdl.add_argument("--status", help="Filter by status (queued/retry_scheduled/succeeded/failed)")
3401
+ pwhdl.add_argument("--event-type", help="Filter by event type")
3402
+ pwhdl.add_argument("--limit", type=int, default=100, help="Max deliveries to return (1-500)")
3403
+ _add_api_common_arguments(pwhdl)
3404
+ pwhdl.set_defaults(func=cmd_webhooks_deliveries_list)
3405
+
3406
+ pwhda = whd_sub.add_parser("attempts", help="List delivery attempts for one delivery id")
3407
+ pwhda.add_argument("--delivery-id", required=True)
3408
+ pwhda.add_argument("--limit", type=int, default=100, help="Max attempts to return (1-500)")
3409
+ _add_api_common_arguments(pwhda)
3410
+ pwhda.set_defaults(func=cmd_webhooks_deliveries_attempts)
3411
+
3112
3412
  # Backward-compatible aliases
3113
3413
  # run
3114
3414
  palias_run = sub.add_parser("run", help="Alias for: columns run")
File without changes