primitivedotdev 0.3.0__tar.gz → 0.4.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.
Files changed (151) hide show
  1. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/PKG-INFO +1 -1
  2. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/pyproject.toml +1 -1
  3. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/domains/add_domain.py +7 -0
  4. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/emails/replay_email_webhooks.py +23 -8
  5. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/webhook_deliveries/replay_delivery.py +19 -8
  6. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/__init__.py +4 -0
  7. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/error_response_error.py +26 -0
  8. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/error_response_error_code.py +2 -0
  9. primitivedotdev-0.4.0/src/primitive/api/models/error_response_error_details.py +95 -0
  10. primitivedotdev-0.4.0/src/primitive/api/models/error_response_error_details_mx_conflict.py +85 -0
  11. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/.gitignore +0 -0
  12. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/README.md +0 -0
  13. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/json-schema/email-received-event.schema.json +0 -0
  14. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/scripts/generate_api_client.py +0 -0
  15. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/scripts/generate_models.py +0 -0
  16. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/scripts/generate_schema_module.py +0 -0
  17. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/__init__.py +0 -0
  18. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/_compat.py +0 -0
  19. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/__init__.py +0 -0
  20. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/__init__.py +0 -0
  21. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/account/__init__.py +0 -0
  22. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/account/get_account.py +0 -0
  23. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/account/get_storage_stats.py +0 -0
  24. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/account/get_webhook_secret.py +0 -0
  25. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/account/rotate_webhook_secret.py +0 -0
  26. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/account/update_account.py +0 -0
  27. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/domains/__init__.py +0 -0
  28. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/domains/delete_domain.py +0 -0
  29. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/domains/list_domains.py +0 -0
  30. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/domains/update_domain.py +0 -0
  31. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/domains/verify_domain.py +0 -0
  32. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/emails/__init__.py +0 -0
  33. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/emails/delete_email.py +0 -0
  34. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/emails/download_attachments.py +0 -0
  35. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/emails/download_raw_email.py +0 -0
  36. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/emails/get_email.py +0 -0
  37. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/emails/list_emails.py +0 -0
  38. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/endpoints/__init__.py +0 -0
  39. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/endpoints/create_endpoint.py +0 -0
  40. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/endpoints/delete_endpoint.py +0 -0
  41. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/endpoints/list_endpoints.py +0 -0
  42. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/endpoints/test_endpoint.py +0 -0
  43. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/endpoints/update_endpoint.py +0 -0
  44. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/filters/__init__.py +0 -0
  45. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/filters/create_filter.py +0 -0
  46. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/filters/delete_filter.py +0 -0
  47. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/filters/list_filters.py +0 -0
  48. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/filters/update_filter.py +0 -0
  49. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/webhook_deliveries/__init__.py +0 -0
  50. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/api/webhook_deliveries/list_deliveries.py +0 -0
  51. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/client.py +0 -0
  52. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/downloads.py +0 -0
  53. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/errors.py +0 -0
  54. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/account.py +0 -0
  55. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/account_updated.py +0 -0
  56. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/add_domain_input.py +0 -0
  57. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/add_domain_response_201.py +0 -0
  58. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/create_endpoint_input.py +0 -0
  59. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/create_endpoint_input_rules.py +0 -0
  60. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/create_endpoint_response_201.py +0 -0
  61. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/create_filter_input.py +0 -0
  62. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/create_filter_input_type.py +0 -0
  63. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/create_filter_response_201.py +0 -0
  64. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delete_domain_response_200.py +0 -0
  65. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delete_domain_response_200_data.py +0 -0
  66. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delete_email_response_200.py +0 -0
  67. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delete_email_response_200_data.py +0 -0
  68. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delete_endpoint_response_200.py +0 -0
  69. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delete_endpoint_response_200_data.py +0 -0
  70. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delete_filter_response_200.py +0 -0
  71. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delete_filter_response_200_data.py +0 -0
  72. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delivery_summary.py +0 -0
  73. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delivery_summary_email_type_0.py +0 -0
  74. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/delivery_summary_status.py +0 -0
  75. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/domain_verify_result_type_0.py +0 -0
  76. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/domain_verify_result_type_1.py +0 -0
  77. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/email_detail.py +0 -0
  78. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/email_detail_status.py +0 -0
  79. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/email_detail_webhook_status_type_1.py +0 -0
  80. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/email_detail_webhook_status_type_2_type_1.py +0 -0
  81. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/email_detail_webhook_status_type_3_type_1.py +0 -0
  82. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/email_summary.py +0 -0
  83. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/email_summary_status.py +0 -0
  84. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/email_summary_webhook_status_type_1.py +0 -0
  85. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/email_summary_webhook_status_type_2_type_1.py +0 -0
  86. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/email_summary_webhook_status_type_3_type_1.py +0 -0
  87. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/endpoint.py +0 -0
  88. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/endpoint_rules.py +0 -0
  89. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/error_response.py +0 -0
  90. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/filter_.py +0 -0
  91. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/filter_type.py +0 -0
  92. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/get_account_response_200.py +0 -0
  93. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/get_email_response_200.py +0 -0
  94. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/get_storage_stats_response_200.py +0 -0
  95. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/get_webhook_secret_response_200.py +0 -0
  96. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/list_deliveries_response_200.py +0 -0
  97. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/list_deliveries_status.py +0 -0
  98. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/list_domains_response_200.py +0 -0
  99. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/list_emails_response_200.py +0 -0
  100. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/list_emails_status.py +0 -0
  101. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/list_endpoints_response_200.py +0 -0
  102. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/list_envelope.py +0 -0
  103. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/list_filters_response_200.py +0 -0
  104. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/pagination_meta.py +0 -0
  105. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/replay_delivery_response_200.py +0 -0
  106. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/replay_email_webhooks_response_200.py +0 -0
  107. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/replay_result.py +0 -0
  108. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/rotate_webhook_secret_response_200.py +0 -0
  109. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/storage_stats.py +0 -0
  110. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/success_envelope.py +0 -0
  111. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/test_endpoint_response_200.py +0 -0
  112. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/test_result.py +0 -0
  113. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/unverified_domain.py +0 -0
  114. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/update_account_input.py +0 -0
  115. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/update_account_response_200.py +0 -0
  116. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/update_domain_input.py +0 -0
  117. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/update_domain_response_200.py +0 -0
  118. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/update_endpoint_input.py +0 -0
  119. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/update_endpoint_input_rules.py +0 -0
  120. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/update_endpoint_response_200.py +0 -0
  121. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/update_filter_input.py +0 -0
  122. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/update_filter_response_200.py +0 -0
  123. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/verified_domain.py +0 -0
  124. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/verify_domain_response_200.py +0 -0
  125. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/models/webhook_secret.py +0 -0
  126. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/api/types.py +0 -0
  127. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/errors.py +0 -0
  128. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/models_generated.py +0 -0
  129. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/py.typed +0 -0
  130. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/schema.py +0 -0
  131. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/schemas/email_received_event.schema.json +0 -0
  132. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/types.py +0 -0
  133. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/validation.py +0 -0
  134. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/src/primitive/webhook.py +0 -0
  135. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/test-fixtures/auth/cases.json +0 -0
  136. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/test-fixtures/handle-webhook/cases.json +0 -0
  137. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/test-fixtures/handle-webhook/standard-webhooks-cases.json +0 -0
  138. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/test-fixtures/parse-webhook-event/cases.json +0 -0
  139. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/test-fixtures/raw/cases.json +0 -0
  140. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/test-fixtures/signing/standard-webhooks-vectors.json +0 -0
  141. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/test-fixtures/signing/vectors.json +0 -0
  142. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/test-fixtures/webhook/valid-email-received.json +0 -0
  143. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/test-fixtures/webhook/validation-cases.json +0 -0
  144. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/tests/conftest.py +0 -0
  145. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/tests/test_auth.py +0 -0
  146. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/tests/test_encoding.py +0 -0
  147. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/tests/test_parsing.py +0 -0
  148. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/tests/test_shared_fixtures.py +0 -0
  149. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/tests/test_signing.py +0 -0
  150. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/tests/test_validation.py +0 -0
  151. {primitivedotdev-0.3.0 → primitivedotdev-0.4.0}/tests/test_webhook.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: primitivedotdev
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Official Primitive Python SDK for webhook handling and API access
5
5
  Project-URL: Homepage, https://primitive.dev
6
6
  Project-URL: Repository, https://github.com/primitivedotdev/sdks
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "primitivedotdev"
7
- version = "0.3.0"
7
+ version = "0.4.0"
8
8
  description = "Official Primitive Python SDK for webhook handling and API access"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -64,6 +64,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
64
64
 
65
65
  return response_401
66
66
 
67
+ if response.status_code == 409:
68
+ response_409 = ErrorResponse.from_dict(response.json())
69
+
70
+
71
+
72
+ return response_409
73
+
67
74
  if client.raise_on_unexpected_status:
68
75
  raise errors.UnexpectedStatus(response.status_code, response.content)
69
76
  else:
@@ -64,6 +64,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
64
64
 
65
65
  return response_404
66
66
 
67
+ if response.status_code == 429:
68
+ response_429 = ErrorResponse.from_dict(response.json())
69
+
70
+
71
+
72
+ return response_429
73
+
67
74
  if client.raise_on_unexpected_status:
68
75
  raise errors.UnexpectedStatus(response.status_code, response.content)
69
76
  else:
@@ -88,8 +95,10 @@ def sync_detailed(
88
95
  """ Replay email webhooks
89
96
 
90
97
  Re-delivers the webhook payload for this email to all active
91
- endpoints matching the email's domain. Includes rate limiting
92
- to prevent stampeding.
98
+ endpoints matching the email's domain. Rate limited per-email
99
+ (short cooldown between successive replays of the same email)
100
+ and per-org (burst + sustained windows), sharing an org-wide
101
+ budget with delivery replays.
93
102
 
94
103
  Args:
95
104
  id (UUID):
@@ -123,8 +132,10 @@ def sync(
123
132
  """ Replay email webhooks
124
133
 
125
134
  Re-delivers the webhook payload for this email to all active
126
- endpoints matching the email's domain. Includes rate limiting
127
- to prevent stampeding.
135
+ endpoints matching the email's domain. Rate limited per-email
136
+ (short cooldown between successive replays of the same email)
137
+ and per-org (burst + sustained windows), sharing an org-wide
138
+ budget with delivery replays.
128
139
 
129
140
  Args:
130
141
  id (UUID):
@@ -153,8 +164,10 @@ async def asyncio_detailed(
153
164
  """ Replay email webhooks
154
165
 
155
166
  Re-delivers the webhook payload for this email to all active
156
- endpoints matching the email's domain. Includes rate limiting
157
- to prevent stampeding.
167
+ endpoints matching the email's domain. Rate limited per-email
168
+ (short cooldown between successive replays of the same email)
169
+ and per-org (burst + sustained windows), sharing an org-wide
170
+ budget with delivery replays.
158
171
 
159
172
  Args:
160
173
  id (UUID):
@@ -188,8 +201,10 @@ async def asyncio(
188
201
  """ Replay email webhooks
189
202
 
190
203
  Re-delivers the webhook payload for this email to all active
191
- endpoints matching the email's domain. Includes rate limiting
192
- to prevent stampeding.
204
+ endpoints matching the email's domain. Rate limited per-email
205
+ (short cooldown between successive replays of the same email)
206
+ and per-org (burst + sustained windows), sharing an org-wide
207
+ budget with delivery replays.
193
208
 
194
209
  Args:
195
210
  id (UUID):
@@ -63,6 +63,13 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
63
63
 
64
64
  return response_404
65
65
 
66
+ if response.status_code == 429:
67
+ response_429 = ErrorResponse.from_dict(response.json())
68
+
69
+
70
+
71
+ return response_429
72
+
66
73
  if client.raise_on_unexpected_status:
67
74
  raise errors.UnexpectedStatus(response.status_code, response.content)
68
75
  else:
@@ -88,8 +95,9 @@ def sync_detailed(
88
95
 
89
96
  Re-sends the stored webhook payload from a previous delivery attempt.
90
97
  If the original endpoint is still active, it is targeted. If the
91
- original endpoint was deleted, the first active endpoint is used.
92
- Deactivated endpoints cannot be replayed to.
98
+ original endpoint was deleted, the oldest active endpoint is used.
99
+ Deactivated endpoints cannot be replayed to. Rate limited per-org,
100
+ sharing an org-wide budget with email replays.
93
101
 
94
102
  Args:
95
103
  id (str):
@@ -124,8 +132,9 @@ def sync(
124
132
 
125
133
  Re-sends the stored webhook payload from a previous delivery attempt.
126
134
  If the original endpoint is still active, it is targeted. If the
127
- original endpoint was deleted, the first active endpoint is used.
128
- Deactivated endpoints cannot be replayed to.
135
+ original endpoint was deleted, the oldest active endpoint is used.
136
+ Deactivated endpoints cannot be replayed to. Rate limited per-org,
137
+ sharing an org-wide budget with email replays.
129
138
 
130
139
  Args:
131
140
  id (str):
@@ -155,8 +164,9 @@ async def asyncio_detailed(
155
164
 
156
165
  Re-sends the stored webhook payload from a previous delivery attempt.
157
166
  If the original endpoint is still active, it is targeted. If the
158
- original endpoint was deleted, the first active endpoint is used.
159
- Deactivated endpoints cannot be replayed to.
167
+ original endpoint was deleted, the oldest active endpoint is used.
168
+ Deactivated endpoints cannot be replayed to. Rate limited per-org,
169
+ sharing an org-wide budget with email replays.
160
170
 
161
171
  Args:
162
172
  id (str):
@@ -191,8 +201,9 @@ async def asyncio(
191
201
 
192
202
  Re-sends the stored webhook payload from a previous delivery attempt.
193
203
  If the original endpoint is still active, it is targeted. If the
194
- original endpoint was deleted, the first active endpoint is used.
195
- Deactivated endpoints cannot be replayed to.
204
+ original endpoint was deleted, the oldest active endpoint is used.
205
+ Deactivated endpoints cannot be replayed to. Rate limited per-org,
206
+ sharing an org-wide budget with email replays.
196
207
 
197
208
  Args:
198
209
  id (str):
@@ -38,6 +38,8 @@ from .endpoint_rules import EndpointRules
38
38
  from .error_response import ErrorResponse
39
39
  from .error_response_error import ErrorResponseError
40
40
  from .error_response_error_code import ErrorResponseErrorCode
41
+ from .error_response_error_details import ErrorResponseErrorDetails
42
+ from .error_response_error_details_mx_conflict import ErrorResponseErrorDetailsMxConflict
41
43
  from .filter_ import Filter
42
44
  from .filter_type import FilterType
43
45
  from .get_account_response_200 import GetAccountResponse200
@@ -114,6 +116,8 @@ __all__ = (
114
116
  "ErrorResponse",
115
117
  "ErrorResponseError",
116
118
  "ErrorResponseErrorCode",
119
+ "ErrorResponseErrorDetails",
120
+ "ErrorResponseErrorDetailsMxConflict",
117
121
  "Filter",
118
122
  "FilterType",
119
123
  "GetAccountResponse200",
@@ -9,7 +9,10 @@ from attrs import field as _attrs_field
9
9
  from ..types import UNSET, Unset
10
10
 
11
11
  from ..models.error_response_error_code import ErrorResponseErrorCode
12
+ from typing import cast
12
13
 
14
+ if TYPE_CHECKING:
15
+ from ..models.error_response_error_details import ErrorResponseErrorDetails
13
16
 
14
17
 
15
18
 
@@ -25,10 +28,14 @@ class ErrorResponseError:
25
28
  Attributes:
26
29
  code (ErrorResponseErrorCode):
27
30
  message (str):
31
+ details (ErrorResponseErrorDetails | Unset): Optional structured data that callers can inspect to recover
32
+ from the error. The fields present depend on `code`. Additional
33
+ keys may be added over time without a major-version bump.
28
34
  """
29
35
 
30
36
  code: ErrorResponseErrorCode
31
37
  message: str
38
+ details: ErrorResponseErrorDetails | Unset = UNSET
32
39
  additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
33
40
 
34
41
 
@@ -36,10 +43,15 @@ class ErrorResponseError:
36
43
 
37
44
 
38
45
  def to_dict(self) -> dict[str, Any]:
46
+ from ..models.error_response_error_details import ErrorResponseErrorDetails
39
47
  code = self.code.value
40
48
 
41
49
  message = self.message
42
50
 
51
+ details: dict[str, Any] | Unset = UNSET
52
+ if not isinstance(self.details, Unset):
53
+ details = self.details.to_dict()
54
+
43
55
 
44
56
  field_dict: dict[str, Any] = {}
45
57
  field_dict.update(self.additional_properties)
@@ -47,6 +59,8 @@ class ErrorResponseError:
47
59
  "code": code,
48
60
  "message": message,
49
61
  })
62
+ if details is not UNSET:
63
+ field_dict["details"] = details
50
64
 
51
65
  return field_dict
52
66
 
@@ -54,6 +68,7 @@ class ErrorResponseError:
54
68
 
55
69
  @classmethod
56
70
  def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
71
+ from ..models.error_response_error_details import ErrorResponseErrorDetails
57
72
  d = dict(src_dict)
58
73
  code = ErrorResponseErrorCode(d.pop("code"))
59
74
 
@@ -62,9 +77,20 @@ class ErrorResponseError:
62
77
 
63
78
  message = d.pop("message")
64
79
 
80
+ _details = d.pop("details", UNSET)
81
+ details: ErrorResponseErrorDetails | Unset
82
+ if isinstance(_details, Unset):
83
+ details = UNSET
84
+ else:
85
+ details = ErrorResponseErrorDetails.from_dict(_details)
86
+
87
+
88
+
89
+
65
90
  error_response_error = cls(
66
91
  code=code,
67
92
  message=message,
93
+ details=details,
68
94
  )
69
95
 
70
96
 
@@ -1,8 +1,10 @@
1
1
  from enum import Enum
2
2
 
3
3
  class ErrorResponseErrorCode(str, Enum):
4
+ CONFLICT = "conflict"
4
5
  FORBIDDEN = "forbidden"
5
6
  INTERNAL_ERROR = "internal_error"
7
+ MX_CONFLICT = "mx_conflict"
6
8
  NOT_FOUND = "not_found"
7
9
  RATE_LIMIT_EXCEEDED = "rate_limit_exceeded"
8
10
  UNAUTHORIZED = "unauthorized"
@@ -0,0 +1,95 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ from ..types import UNSET, Unset
10
+
11
+ from typing import cast
12
+
13
+ if TYPE_CHECKING:
14
+ from ..models.error_response_error_details_mx_conflict import ErrorResponseErrorDetailsMxConflict
15
+
16
+
17
+
18
+
19
+
20
+ T = TypeVar("T", bound="ErrorResponseErrorDetails")
21
+
22
+
23
+
24
+ @_attrs_define
25
+ class ErrorResponseErrorDetails:
26
+ """ Optional structured data that callers can inspect to recover
27
+ from the error. The fields present depend on `code`. Additional
28
+ keys may be added over time without a major-version bump.
29
+
30
+ Attributes:
31
+ mx_conflict (ErrorResponseErrorDetailsMxConflict | Unset): Present when `code == mx_conflict`.
32
+ """
33
+
34
+ mx_conflict: ErrorResponseErrorDetailsMxConflict | Unset = UNSET
35
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
36
+
37
+
38
+
39
+
40
+
41
+ def to_dict(self) -> dict[str, Any]:
42
+ from ..models.error_response_error_details_mx_conflict import ErrorResponseErrorDetailsMxConflict
43
+ mx_conflict: dict[str, Any] | Unset = UNSET
44
+ if not isinstance(self.mx_conflict, Unset):
45
+ mx_conflict = self.mx_conflict.to_dict()
46
+
47
+
48
+ field_dict: dict[str, Any] = {}
49
+ field_dict.update(self.additional_properties)
50
+ field_dict.update({
51
+ })
52
+ if mx_conflict is not UNSET:
53
+ field_dict["mx_conflict"] = mx_conflict
54
+
55
+ return field_dict
56
+
57
+
58
+
59
+ @classmethod
60
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
61
+ from ..models.error_response_error_details_mx_conflict import ErrorResponseErrorDetailsMxConflict
62
+ d = dict(src_dict)
63
+ _mx_conflict = d.pop("mx_conflict", UNSET)
64
+ mx_conflict: ErrorResponseErrorDetailsMxConflict | Unset
65
+ if isinstance(_mx_conflict, Unset):
66
+ mx_conflict = UNSET
67
+ else:
68
+ mx_conflict = ErrorResponseErrorDetailsMxConflict.from_dict(_mx_conflict)
69
+
70
+
71
+
72
+
73
+ error_response_error_details = cls(
74
+ mx_conflict=mx_conflict,
75
+ )
76
+
77
+
78
+ error_response_error_details.additional_properties = d
79
+ return error_response_error_details
80
+
81
+ @property
82
+ def additional_keys(self) -> list[str]:
83
+ return list(self.additional_properties.keys())
84
+
85
+ def __getitem__(self, key: str) -> Any:
86
+ return self.additional_properties[key]
87
+
88
+ def __setitem__(self, key: str, value: Any) -> None:
89
+ self.additional_properties[key] = value
90
+
91
+ def __delitem__(self, key: str) -> None:
92
+ del self.additional_properties[key]
93
+
94
+ def __contains__(self, key: str) -> bool:
95
+ return key in self.additional_properties
@@ -0,0 +1,85 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ from ..types import UNSET, Unset
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+ T = TypeVar("T", bound="ErrorResponseErrorDetailsMxConflict")
18
+
19
+
20
+
21
+ @_attrs_define
22
+ class ErrorResponseErrorDetailsMxConflict:
23
+ """ Present when `code == mx_conflict`.
24
+
25
+ Attributes:
26
+ provider_name (str): Human-readable name of the detected mailbox provider (e.g. "Google Workspace").
27
+ suggested_subdomain (str): Subdomain to try instead (e.g. "mail" for `mail.example.com`).
28
+ """
29
+
30
+ provider_name: str
31
+ suggested_subdomain: str
32
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
33
+
34
+
35
+
36
+
37
+
38
+ def to_dict(self) -> dict[str, Any]:
39
+ provider_name = self.provider_name
40
+
41
+ suggested_subdomain = self.suggested_subdomain
42
+
43
+
44
+ field_dict: dict[str, Any] = {}
45
+ field_dict.update(self.additional_properties)
46
+ field_dict.update({
47
+ "provider_name": provider_name,
48
+ "suggested_subdomain": suggested_subdomain,
49
+ })
50
+
51
+ return field_dict
52
+
53
+
54
+
55
+ @classmethod
56
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
57
+ d = dict(src_dict)
58
+ provider_name = d.pop("provider_name")
59
+
60
+ suggested_subdomain = d.pop("suggested_subdomain")
61
+
62
+ error_response_error_details_mx_conflict = cls(
63
+ provider_name=provider_name,
64
+ suggested_subdomain=suggested_subdomain,
65
+ )
66
+
67
+
68
+ error_response_error_details_mx_conflict.additional_properties = d
69
+ return error_response_error_details_mx_conflict
70
+
71
+ @property
72
+ def additional_keys(self) -> list[str]:
73
+ return list(self.additional_properties.keys())
74
+
75
+ def __getitem__(self, key: str) -> Any:
76
+ return self.additional_properties[key]
77
+
78
+ def __setitem__(self, key: str, value: Any) -> None:
79
+ self.additional_properties[key] = value
80
+
81
+ def __delitem__(self, key: str) -> None:
82
+ del self.additional_properties[key]
83
+
84
+ def __contains__(self, key: str) -> bool:
85
+ return key in self.additional_properties