usenadia 0.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.
Files changed (253) hide show
  1. usenadia-0.1.0/.gitignore +6 -0
  2. usenadia-0.1.0/LICENSE +21 -0
  3. usenadia-0.1.0/PKG-INFO +98 -0
  4. usenadia-0.1.0/README.md +85 -0
  5. usenadia-0.1.0/pyproject.toml +33 -0
  6. usenadia-0.1.0/tests/test_facade.py +131 -0
  7. usenadia-0.1.0/usenadia/__init__.py +278 -0
  8. usenadia-0.1.0/usenadia/generated/__init__.py +8 -0
  9. usenadia-0.1.0/usenadia/generated/api/__init__.py +1 -0
  10. usenadia-0.1.0/usenadia/generated/api/public_api/__init__.py +1 -0
  11. usenadia-0.1.0/usenadia/generated/api/public_api/call_video_function.py +176 -0
  12. usenadia-0.1.0/usenadia/generated/api/public_api/change_post_status.py +192 -0
  13. usenadia-0.1.0/usenadia/generated/api/public_api/check_connection.py +144 -0
  14. usenadia-0.1.0/usenadia/generated/api/public_api/create_automation_flow.py +176 -0
  15. usenadia-0.1.0/usenadia/generated/api/public_api/create_content.py +181 -0
  16. usenadia-0.1.0/usenadia/generated/api/public_api/create_post.py +183 -0
  17. usenadia-0.1.0/usenadia/generated/api/public_api/create_webhook.py +176 -0
  18. usenadia-0.1.0/usenadia/generated/api/public_api/delete_automation_flow.py +171 -0
  19. usenadia-0.1.0/usenadia/generated/api/public_api/delete_automation_pose.py +171 -0
  20. usenadia-0.1.0/usenadia/generated/api/public_api/delete_channel.py +171 -0
  21. usenadia-0.1.0/usenadia/generated/api/public_api/delete_comment.py +185 -0
  22. usenadia-0.1.0/usenadia/generated/api/public_api/delete_content.py +171 -0
  23. usenadia-0.1.0/usenadia/generated/api/public_api/delete_post.py +171 -0
  24. usenadia-0.1.0/usenadia/generated/api/public_api/delete_post_group.py +171 -0
  25. usenadia-0.1.0/usenadia/generated/api/public_api/delete_webhook.py +171 -0
  26. usenadia-0.1.0/usenadia/generated/api/public_api/find_slot.py +171 -0
  27. usenadia-0.1.0/usenadia/generated/api/public_api/generate_video.py +176 -0
  28. usenadia-0.1.0/usenadia/generated/api/public_api/get_account_history.py +252 -0
  29. usenadia-0.1.0/usenadia/generated/api/public_api/get_automation_flow.py +171 -0
  30. usenadia-0.1.0/usenadia/generated/api/public_api/get_automation_pose.py +171 -0
  31. usenadia-0.1.0/usenadia/generated/api/public_api/get_channel_analytics.py +197 -0
  32. usenadia-0.1.0/usenadia/generated/api/public_api/get_channel_settings.py +171 -0
  33. usenadia-0.1.0/usenadia/generated/api/public_api/get_content.py +171 -0
  34. usenadia-0.1.0/usenadia/generated/api/public_api/get_contents_performance.py +146 -0
  35. usenadia-0.1.0/usenadia/generated/api/public_api/get_conversation.py +190 -0
  36. usenadia-0.1.0/usenadia/generated/api/public_api/get_hook_forms.py +265 -0
  37. usenadia-0.1.0/usenadia/generated/api/public_api/get_music_track.py +171 -0
  38. usenadia-0.1.0/usenadia/generated/api/public_api/get_post_analytics.py +192 -0
  39. usenadia-0.1.0/usenadia/generated/api/public_api/get_video_history.py +252 -0
  40. usenadia-0.1.0/usenadia/generated/api/public_api/get_webhook.py +171 -0
  41. usenadia-0.1.0/usenadia/generated/api/public_api/hide_comment.py +206 -0
  42. usenadia-0.1.0/usenadia/generated/api/public_api/import_hooks.py +171 -0
  43. usenadia-0.1.0/usenadia/generated/api/public_api/import_music.py +176 -0
  44. usenadia-0.1.0/usenadia/generated/api/public_api/link_content_post.py +208 -0
  45. usenadia-0.1.0/usenadia/generated/api/public_api/list_automation_flow_poses.py +178 -0
  46. usenadia-0.1.0/usenadia/generated/api/public_api/list_automation_flows.py +151 -0
  47. usenadia-0.1.0/usenadia/generated/api/public_api/list_automation_pose_runs.py +199 -0
  48. usenadia-0.1.0/usenadia/generated/api/public_api/list_channel_automation_poses.py +198 -0
  49. usenadia-0.1.0/usenadia/generated/api/public_api/list_channel_media.py +176 -0
  50. usenadia-0.1.0/usenadia/generated/api/public_api/list_channel_stories.py +176 -0
  51. usenadia-0.1.0/usenadia/generated/api/public_api/list_channels.py +181 -0
  52. usenadia-0.1.0/usenadia/generated/api/public_api/list_contents.py +239 -0
  53. usenadia-0.1.0/usenadia/generated/api/public_api/list_conversations.py +197 -0
  54. usenadia-0.1.0/usenadia/generated/api/public_api/list_groups.py +149 -0
  55. usenadia-0.1.0/usenadia/generated/api/public_api/list_hook_families.py +196 -0
  56. usenadia-0.1.0/usenadia/generated/api/public_api/list_media_comments.py +190 -0
  57. usenadia-0.1.0/usenadia/generated/api/public_api/list_missing_media.py +192 -0
  58. usenadia-0.1.0/usenadia/generated/api/public_api/list_music.py +252 -0
  59. usenadia-0.1.0/usenadia/generated/api/public_api/list_music_pillars.py +152 -0
  60. usenadia-0.1.0/usenadia/generated/api/public_api/list_notifications.py +176 -0
  61. usenadia-0.1.0/usenadia/generated/api/public_api/list_posts.py +236 -0
  62. usenadia-0.1.0/usenadia/generated/api/public_api/list_video_performance.py +209 -0
  63. usenadia-0.1.0/usenadia/generated/api/public_api/list_webhook_events.py +144 -0
  64. usenadia-0.1.0/usenadia/generated/api/public_api/list_webhooks.py +149 -0
  65. usenadia-0.1.0/usenadia/generated/api/public_api/move_content.py +192 -0
  66. usenadia-0.1.0/usenadia/generated/api/public_api/poll_automation_pose.py +171 -0
  67. usenadia-0.1.0/usenadia/generated/api/public_api/poll_inbox.py +171 -0
  68. usenadia-0.1.0/usenadia/generated/api/public_api/pose_automation_flow.py +192 -0
  69. usenadia-0.1.0/usenadia/generated/api/public_api/preview_automation_email.py +176 -0
  70. usenadia-0.1.0/usenadia/generated/api/public_api/replace_hook_families.py +176 -0
  71. usenadia-0.1.0/usenadia/generated/api/public_api/replay_automation_pose.py +199 -0
  72. usenadia-0.1.0/usenadia/generated/api/public_api/reply_to_comment.py +192 -0
  73. usenadia-0.1.0/usenadia/generated/api/public_api/run_channel_tool.py +192 -0
  74. usenadia-0.1.0/usenadia/generated/api/public_api/search_hooks.py +267 -0
  75. usenadia-0.1.0/usenadia/generated/api/public_api/send_automation_test_email.py +176 -0
  76. usenadia-0.1.0/usenadia/generated/api/public_api/send_direct_message.py +192 -0
  77. usenadia-0.1.0/usenadia/generated/api/public_api/set_automation_flow_status.py +192 -0
  78. usenadia-0.1.0/usenadia/generated/api/public_api/set_post_release_id.py +192 -0
  79. usenadia-0.1.0/usenadia/generated/api/public_api/start_channel_connection.py +192 -0
  80. usenadia-0.1.0/usenadia/generated/api/public_api/subscribe_inbox_webhook.py +171 -0
  81. usenadia-0.1.0/usenadia/generated/api/public_api/update_automation_flow.py +192 -0
  82. usenadia-0.1.0/usenadia/generated/api/public_api/update_automation_pose.py +192 -0
  83. usenadia-0.1.0/usenadia/generated/api/public_api/update_content.py +192 -0
  84. usenadia-0.1.0/usenadia/generated/api/public_api/upload_file.py +176 -0
  85. usenadia-0.1.0/usenadia/generated/api/public_api/upload_from_url.py +176 -0
  86. usenadia-0.1.0/usenadia/generated/api/public_api/upload_music_file.py +197 -0
  87. usenadia-0.1.0/usenadia/generated/api/public_api/upsert_content.py +188 -0
  88. usenadia-0.1.0/usenadia/generated/client.py +280 -0
  89. usenadia-0.1.0/usenadia/generated/errors.py +16 -0
  90. usenadia-0.1.0/usenadia/generated/models/__init__.py +335 -0
  91. usenadia-0.1.0/usenadia/generated/models/account_history_item_dto.py +86 -0
  92. usenadia-0.1.0/usenadia/generated/models/analytics_metric_dto.py +94 -0
  93. usenadia-0.1.0/usenadia/generated/models/analytics_point_dto.py +70 -0
  94. usenadia-0.1.0/usenadia/generated/models/api_error_dto.py +61 -0
  95. usenadia-0.1.0/usenadia/generated/models/automation_flow_counts_dto.py +69 -0
  96. usenadia-0.1.0/usenadia/generated/models/automation_flow_dto.py +97 -0
  97. usenadia-0.1.0/usenadia/generated/models/automation_flow_dto_definition.py +45 -0
  98. usenadia-0.1.0/usenadia/generated/models/automation_flow_issue_dto.py +116 -0
  99. usenadia-0.1.0/usenadia/generated/models/automation_flow_issue_dto_level.py +9 -0
  100. usenadia-0.1.0/usenadia/generated/models/automation_flow_issue_dto_params.py +45 -0
  101. usenadia-0.1.0/usenadia/generated/models/automation_flow_poll_result_dto.py +69 -0
  102. usenadia-0.1.0/usenadia/generated/models/automation_flow_pose_response_dto.py +206 -0
  103. usenadia-0.1.0/usenadia/generated/models/automation_flow_pose_response_dto_source.py +9 -0
  104. usenadia-0.1.0/usenadia/generated/models/automation_flow_pose_response_dto_variables.py +47 -0
  105. usenadia-0.1.0/usenadia/generated/models/automation_flow_replay_result_dto.py +119 -0
  106. usenadia-0.1.0/usenadia/generated/models/automation_flow_response_dto.py +173 -0
  107. usenadia-0.1.0/usenadia/generated/models/automation_flow_response_dto_definition.py +50 -0
  108. usenadia-0.1.0/usenadia/generated/models/automation_flow_response_dto_status.py +10 -0
  109. usenadia-0.1.0/usenadia/generated/models/automation_flow_run_response_dto.py +269 -0
  110. usenadia-0.1.0/usenadia/generated/models/automation_flow_run_response_dto_status.py +14 -0
  111. usenadia-0.1.0/usenadia/generated/models/automation_flow_status_dto.py +63 -0
  112. usenadia-0.1.0/usenadia/generated/models/automation_flow_status_dto_status.py +10 -0
  113. usenadia-0.1.0/usenadia/generated/models/automation_pose_counts_dto.py +93 -0
  114. usenadia-0.1.0/usenadia/generated/models/automation_pose_flow_dto.py +79 -0
  115. usenadia-0.1.0/usenadia/generated/models/automation_pose_flow_dto_status.py +10 -0
  116. usenadia-0.1.0/usenadia/generated/models/call_video_function_response_201.py +45 -0
  117. usenadia-0.1.0/usenadia/generated/models/change_post_status_dto.py +63 -0
  118. usenadia-0.1.0/usenadia/generated/models/change_post_status_dto_status.py +9 -0
  119. usenadia-0.1.0/usenadia/generated/models/content_channel_performance_dto.py +368 -0
  120. usenadia-0.1.0/usenadia/generated/models/content_dto.py +408 -0
  121. usenadia-0.1.0/usenadia/generated/models/content_dto_resource_status.py +9 -0
  122. usenadia-0.1.0/usenadia/generated/models/content_dto_stage.py +14 -0
  123. usenadia-0.1.0/usenadia/generated/models/content_list_item_dto.py +441 -0
  124. usenadia-0.1.0/usenadia/generated/models/content_list_item_dto_resource_status.py +9 -0
  125. usenadia-0.1.0/usenadia/generated/models/content_list_item_dto_stage.py +14 -0
  126. usenadia-0.1.0/usenadia/generated/models/content_performance_dto.py +175 -0
  127. usenadia-0.1.0/usenadia/generated/models/content_post_dto.py +109 -0
  128. usenadia-0.1.0/usenadia/generated/models/content_post_dto_state.py +12 -0
  129. usenadia-0.1.0/usenadia/generated/models/content_upsert_dto.py +75 -0
  130. usenadia-0.1.0/usenadia/generated/models/create_content_dto.py +202 -0
  131. usenadia-0.1.0/usenadia/generated/models/create_content_dto_resource_status.py +9 -0
  132. usenadia-0.1.0/usenadia/generated/models/create_content_dto_stage.py +14 -0
  133. usenadia-0.1.0/usenadia/generated/models/create_post_result_item_dto.py +69 -0
  134. usenadia-0.1.0/usenadia/generated/models/create_public_webhook_dto.py +133 -0
  135. usenadia-0.1.0/usenadia/generated/models/create_public_webhook_dto_events_item.py +12 -0
  136. usenadia-0.1.0/usenadia/generated/models/deleted_id_dto.py +61 -0
  137. usenadia-0.1.0/usenadia/generated/models/email_preview_dto.py +143 -0
  138. usenadia-0.1.0/usenadia/generated/models/email_preview_dto_response.py +122 -0
  139. usenadia-0.1.0/usenadia/generated/models/email_preview_dto_response_params.py +47 -0
  140. usenadia-0.1.0/usenadia/generated/models/email_preview_dto_response_sender.py +47 -0
  141. usenadia-0.1.0/usenadia/generated/models/email_sent_dto.py +69 -0
  142. usenadia-0.1.0/usenadia/generated/models/email_test_dto.py +163 -0
  143. usenadia-0.1.0/usenadia/generated/models/find_slot_dto.py +62 -0
  144. usenadia-0.1.0/usenadia/generated/models/generated_video_dto.py +119 -0
  145. usenadia-0.1.0/usenadia/generated/models/get_contents_performance_response_200.py +62 -0
  146. usenadia-0.1.0/usenadia/generated/models/get_hook_forms_language.py +10 -0
  147. usenadia-0.1.0/usenadia/generated/models/get_post_analytics_response_200.py +45 -0
  148. usenadia-0.1.0/usenadia/generated/models/group_dto.py +69 -0
  149. usenadia-0.1.0/usenadia/generated/models/hide_comment_dto.py +61 -0
  150. usenadia-0.1.0/usenadia/generated/models/history_page_dto.py +116 -0
  151. usenadia-0.1.0/usenadia/generated/models/hook_dto.py +311 -0
  152. usenadia-0.1.0/usenadia/generated/models/hook_families_import_dto.py +83 -0
  153. usenadia-0.1.0/usenadia/generated/models/hook_family_dto.py +220 -0
  154. usenadia-0.1.0/usenadia/generated/models/hook_family_stat_dto.py +212 -0
  155. usenadia-0.1.0/usenadia/generated/models/hook_form_dto.py +186 -0
  156. usenadia-0.1.0/usenadia/generated/models/hook_import_item_dto.py +211 -0
  157. usenadia-0.1.0/usenadia/generated/models/hooks_import_dto.py +75 -0
  158. usenadia-0.1.0/usenadia/generated/models/hooks_import_result_dto.py +69 -0
  159. usenadia-0.1.0/usenadia/generated/models/hooks_search_result_dto.py +83 -0
  160. usenadia-0.1.0/usenadia/generated/models/inbox_conversation_dto.py +128 -0
  161. usenadia-0.1.0/usenadia/generated/models/inbox_conversation_dto_inbox.py +47 -0
  162. usenadia-0.1.0/usenadia/generated/models/inbox_conversation_dto_messages.py +47 -0
  163. usenadia-0.1.0/usenadia/generated/models/inbox_conversation_dto_participants.py +47 -0
  164. usenadia-0.1.0/usenadia/generated/models/inbox_message_dto.py +102 -0
  165. usenadia-0.1.0/usenadia/generated/models/inbox_participant_dto.py +72 -0
  166. usenadia-0.1.0/usenadia/generated/models/inbox_poll_result_dto.py +69 -0
  167. usenadia-0.1.0/usenadia/generated/models/instagram_comment_author_dto.py +70 -0
  168. usenadia-0.1.0/usenadia/generated/models/instagram_comment_dto.py +123 -0
  169. usenadia-0.1.0/usenadia/generated/models/instagram_media_dto.py +145 -0
  170. usenadia-0.1.0/usenadia/generated/models/integration.py +61 -0
  171. usenadia-0.1.0/usenadia/generated/models/integration_list_item_dto.py +138 -0
  172. usenadia-0.1.0/usenadia/generated/models/integration_settings_dto.py +69 -0
  173. usenadia-0.1.0/usenadia/generated/models/integration_settings_output_dto.py +106 -0
  174. usenadia-0.1.0/usenadia/generated/models/integration_settings_output_dto_settings.py +47 -0
  175. usenadia-0.1.0/usenadia/generated/models/integration_tool_dto.py +91 -0
  176. usenadia-0.1.0/usenadia/generated/models/integration_tool_param_dto.py +77 -0
  177. usenadia-0.1.0/usenadia/generated/models/integration_trigger_dto.py +85 -0
  178. usenadia-0.1.0/usenadia/generated/models/integration_trigger_dto_data.py +47 -0
  179. usenadia-0.1.0/usenadia/generated/models/integration_trigger_result_dto.py +71 -0
  180. usenadia-0.1.0/usenadia/generated/models/integration_trigger_result_dto_output.py +47 -0
  181. usenadia-0.1.0/usenadia/generated/models/is_connected_dto.py +61 -0
  182. usenadia-0.1.0/usenadia/generated/models/link_content_post_dto.py +61 -0
  183. usenadia-0.1.0/usenadia/generated/models/list_contents_stage.py +14 -0
  184. usenadia-0.1.0/usenadia/generated/models/list_music_pillar.py +11 -0
  185. usenadia-0.1.0/usenadia/generated/models/list_video_performance_response_200.py +45 -0
  186. usenadia-0.1.0/usenadia/generated/models/media_dto.py +89 -0
  187. usenadia-0.1.0/usenadia/generated/models/media_response_dto.py +119 -0
  188. usenadia-0.1.0/usenadia/generated/models/missing_content_item_dto.py +69 -0
  189. usenadia-0.1.0/usenadia/generated/models/move_content_dto.py +73 -0
  190. usenadia-0.1.0/usenadia/generated/models/move_content_dto_stage.py +14 -0
  191. usenadia-0.1.0/usenadia/generated/models/music_import_dto.py +75 -0
  192. usenadia-0.1.0/usenadia/generated/models/music_import_item_dto.py +238 -0
  193. usenadia-0.1.0/usenadia/generated/models/music_import_item_dto_pillar.py +11 -0
  194. usenadia-0.1.0/usenadia/generated/models/music_import_item_dto_verdict.py +10 -0
  195. usenadia-0.1.0/usenadia/generated/models/music_import_result_dto.py +69 -0
  196. usenadia-0.1.0/usenadia/generated/models/music_list_result_dto.py +91 -0
  197. usenadia-0.1.0/usenadia/generated/models/music_pillar_dto.py +85 -0
  198. usenadia-0.1.0/usenadia/generated/models/music_track_dto.py +318 -0
  199. usenadia-0.1.0/usenadia/generated/models/notification_dto.py +100 -0
  200. usenadia-0.1.0/usenadia/generated/models/notifications_page_dto.py +107 -0
  201. usenadia-0.1.0/usenadia/generated/models/ok_dto.py +61 -0
  202. usenadia-0.1.0/usenadia/generated/models/pose_automation_flow_dto.py +125 -0
  203. usenadia-0.1.0/usenadia/generated/models/pose_automation_flow_dto_kind.py +9 -0
  204. usenadia-0.1.0/usenadia/generated/models/pose_automation_flow_dto_variables.py +45 -0
  205. usenadia-0.1.0/usenadia/generated/models/post.py +114 -0
  206. usenadia-0.1.0/usenadia/generated/models/post_content.py +99 -0
  207. usenadia-0.1.0/usenadia/generated/models/post_dto.py +219 -0
  208. usenadia-0.1.0/usenadia/generated/models/post_dto_creation_method.py +11 -0
  209. usenadia-0.1.0/usenadia/generated/models/post_dto_state.py +12 -0
  210. usenadia-0.1.0/usenadia/generated/models/post_integration_summary_dto.py +91 -0
  211. usenadia-0.1.0/usenadia/generated/models/post_list_dto.py +75 -0
  212. usenadia-0.1.0/usenadia/generated/models/post_settings.py +45 -0
  213. usenadia-0.1.0/usenadia/generated/models/post_status_dto.py +71 -0
  214. usenadia-0.1.0/usenadia/generated/models/post_status_dto_state.py +11 -0
  215. usenadia-0.1.0/usenadia/generated/models/post_tag_dto.py +67 -0
  216. usenadia-0.1.0/usenadia/generated/models/post_tag_dto_tag.py +47 -0
  217. usenadia-0.1.0/usenadia/generated/models/public_create_post_dto.py +160 -0
  218. usenadia-0.1.0/usenadia/generated/models/public_create_post_dto_creation_method.py +9 -0
  219. usenadia-0.1.0/usenadia/generated/models/public_create_post_dto_type.py +11 -0
  220. usenadia-0.1.0/usenadia/generated/models/replay_pose_dto.py +72 -0
  221. usenadia-0.1.0/usenadia/generated/models/reply_to_comment_dto.py +69 -0
  222. usenadia-0.1.0/usenadia/generated/models/search_hooks_language.py +10 -0
  223. usenadia-0.1.0/usenadia/generated/models/send_message_dto.py +89 -0
  224. usenadia-0.1.0/usenadia/generated/models/social_auth_url_dto.py +61 -0
  225. usenadia-0.1.0/usenadia/generated/models/success_dto.py +61 -0
  226. usenadia-0.1.0/usenadia/generated/models/tags.py +69 -0
  227. usenadia-0.1.0/usenadia/generated/models/update_automation_flow_dto.py +107 -0
  228. usenadia-0.1.0/usenadia/generated/models/update_automation_flow_dto_definition.py +45 -0
  229. usenadia-0.1.0/usenadia/generated/models/update_automation_flow_pose_dto.py +98 -0
  230. usenadia-0.1.0/usenadia/generated/models/update_automation_flow_pose_dto_variables.py +45 -0
  231. usenadia-0.1.0/usenadia/generated/models/update_content_dto.py +300 -0
  232. usenadia-0.1.0/usenadia/generated/models/update_content_dto_resource_status.py +9 -0
  233. usenadia-0.1.0/usenadia/generated/models/update_release_id_dto.py +61 -0
  234. usenadia-0.1.0/usenadia/generated/models/upload_dto.py +61 -0
  235. usenadia-0.1.0/usenadia/generated/models/upload_file_body.py +75 -0
  236. usenadia-0.1.0/usenadia/generated/models/upload_music_file_body.py +75 -0
  237. usenadia-0.1.0/usenadia/generated/models/upsert_content_dto.py +200 -0
  238. usenadia-0.1.0/usenadia/generated/models/upsert_content_dto_resource_status.py +9 -0
  239. usenadia-0.1.0/usenadia/generated/models/upsert_content_dto_stage.py +14 -0
  240. usenadia-0.1.0/usenadia/generated/models/video_dto.py +85 -0
  241. usenadia-0.1.0/usenadia/generated/models/video_dto_custom_params.py +45 -0
  242. usenadia-0.1.0/usenadia/generated/models/video_dto_output.py +9 -0
  243. usenadia-0.1.0/usenadia/generated/models/video_function_dto.py +93 -0
  244. usenadia-0.1.0/usenadia/generated/models/video_function_dto_params.py +45 -0
  245. usenadia-0.1.0/usenadia/generated/models/video_history_page_dto.py +143 -0
  246. usenadia-0.1.0/usenadia/generated/models/video_identity_dto.py +123 -0
  247. usenadia-0.1.0/usenadia/generated/models/webhook_created_dto.py +135 -0
  248. usenadia-0.1.0/usenadia/generated/models/webhook_dto.py +125 -0
  249. usenadia-0.1.0/usenadia/generated/models/webhook_event_dto.py +69 -0
  250. usenadia-0.1.0/usenadia/generated/models/webhook_event_list_dto.py +75 -0
  251. usenadia-0.1.0/usenadia/generated/models/webhooks_integration_dto.py +61 -0
  252. usenadia-0.1.0/usenadia/generated/types.py +54 -0
  253. usenadia-0.1.0/uv.lock +127 -0
@@ -0,0 +1,6 @@
1
+ usenadia/generated/
2
+ dist/
3
+ *.egg-info/
4
+ __pycache__/
5
+ .venv/
6
+ .ruff_cache/
usenadia-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vincent Ventalon (UseNadia)
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.
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.5
2
+ Name: usenadia
3
+ Version: 0.1.0
4
+ Summary: Python SDK for the UseNadia public API — schedule posts, manage channels, run the Instagram comment/story → DM machinery
5
+ Project-URL: Homepage, https://usenadia.com
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: attrs>=22.2
10
+ Requires-Dist: httpx<1,>=0.23
11
+ Requires-Dist: python-dateutil>=2.8
12
+ Description-Content-Type: text/markdown
13
+
14
+ # usenadia
15
+
16
+ Python SDK for the **UseNadia** public API (`/public/v1`) — schedule posts,
17
+ manage channels, and drive the Instagram comment/story → DM machinery.
18
+
19
+ ```bash
20
+ pip install usenadia
21
+ ```
22
+
23
+ ```python
24
+ from usenadia import Nadia, NadiaError
25
+
26
+ nadia = Nadia(api_key=os.environ["USENADIA_API_KEY"])
27
+
28
+ channels = nadia.integrations()
29
+
30
+ try:
31
+ nadia.post({
32
+ "type": "schedule",
33
+ "date": "2026-10-01T09:00:00.000Z",
34
+ "shortLink": False,
35
+ "tags": [],
36
+ "posts": [{
37
+ "integration": {"id": channels[0]["id"]},
38
+ "value": [{"content": "Hello from the SDK", "image": []}],
39
+ "settings": {},
40
+ }],
41
+ })
42
+ except NadiaError as err:
43
+ print(err.status, err) # 402 You have reached your limit
44
+ ```
45
+
46
+ ## The content board
47
+
48
+ Every card of the board in the app is reachable: create one from anywhere
49
+ (a voice note, a Notion page, a DM), move it along, read its numbers once
50
+ it is published.
51
+
52
+ ```python
53
+ card = nadia.create_content(
54
+ "Three mistakes when moving to Malta",
55
+ hook="Nobody told me about the third one.",
56
+ )
57
+
58
+ nadia.move_content(card["id"], "SCRIPT")
59
+ nadia.update_content(card["id"], script="…")
60
+
61
+ # Scheduled with nadia.post({..., "posts": [{"group": "g-42", ...}]}):
62
+ nadia.link_content_post(card["id"], "g-42") # → PUBLISHED when it goes live
63
+
64
+ numbers = nadia.contents_performance() # keyed by card id
65
+ ```
66
+
67
+ Columns, in order: `IDEA`, `SCRIPT`, `VALIDATED`, `TO_SHOOT`, `TO_EDIT`,
68
+ `TO_SCHEDULE`, `PUBLISHED`.
69
+
70
+ ## How it is built
71
+
72
+ Two layers, and the split is deliberate.
73
+
74
+ - **`usenadia/generated/`** — the transport. Generated from
75
+ `openapi.public.json` by
76
+ [`openapi-python-client`](https://github.com/openapi-generators/openapi-python-client)
77
+ (httpx + attrs), covers every operation, never edited by hand, not
78
+ committed.
79
+ - **`usenadia/__init__.py`** — this SDK's own surface: the `Nadia` class,
80
+ sane defaults, typed errors, retries. Small, hand-written, reviewed.
81
+
82
+ Anything the facade does not wrap is reachable through `nadia.raw`, the
83
+ configured generated client.
84
+
85
+ ## Errors
86
+
87
+ Every response with a status ≥ 400 raises a `NadiaError` carrying `status`,
88
+ `body` and the API's `msg`. `err.is_transient` is true for 429 and 5xx — those
89
+ are retried automatically (twice by default, `Nadia(key, retries=0)` to turn
90
+ it off).
91
+
92
+ ## Regenerating
93
+
94
+ ```bash
95
+ pnpm run sdk:generate # from the repo root — regenerates both SDKs
96
+ ```
97
+
98
+ Plan: `docs/roadmap/19-sdk-public-api.md`.
@@ -0,0 +1,85 @@
1
+ # usenadia
2
+
3
+ Python SDK for the **UseNadia** public API (`/public/v1`) — schedule posts,
4
+ manage channels, and drive the Instagram comment/story → DM machinery.
5
+
6
+ ```bash
7
+ pip install usenadia
8
+ ```
9
+
10
+ ```python
11
+ from usenadia import Nadia, NadiaError
12
+
13
+ nadia = Nadia(api_key=os.environ["USENADIA_API_KEY"])
14
+
15
+ channels = nadia.integrations()
16
+
17
+ try:
18
+ nadia.post({
19
+ "type": "schedule",
20
+ "date": "2026-10-01T09:00:00.000Z",
21
+ "shortLink": False,
22
+ "tags": [],
23
+ "posts": [{
24
+ "integration": {"id": channels[0]["id"]},
25
+ "value": [{"content": "Hello from the SDK", "image": []}],
26
+ "settings": {},
27
+ }],
28
+ })
29
+ except NadiaError as err:
30
+ print(err.status, err) # 402 You have reached your limit
31
+ ```
32
+
33
+ ## The content board
34
+
35
+ Every card of the board in the app is reachable: create one from anywhere
36
+ (a voice note, a Notion page, a DM), move it along, read its numbers once
37
+ it is published.
38
+
39
+ ```python
40
+ card = nadia.create_content(
41
+ "Three mistakes when moving to Malta",
42
+ hook="Nobody told me about the third one.",
43
+ )
44
+
45
+ nadia.move_content(card["id"], "SCRIPT")
46
+ nadia.update_content(card["id"], script="…")
47
+
48
+ # Scheduled with nadia.post({..., "posts": [{"group": "g-42", ...}]}):
49
+ nadia.link_content_post(card["id"], "g-42") # → PUBLISHED when it goes live
50
+
51
+ numbers = nadia.contents_performance() # keyed by card id
52
+ ```
53
+
54
+ Columns, in order: `IDEA`, `SCRIPT`, `VALIDATED`, `TO_SHOOT`, `TO_EDIT`,
55
+ `TO_SCHEDULE`, `PUBLISHED`.
56
+
57
+ ## How it is built
58
+
59
+ Two layers, and the split is deliberate.
60
+
61
+ - **`usenadia/generated/`** — the transport. Generated from
62
+ `openapi.public.json` by
63
+ [`openapi-python-client`](https://github.com/openapi-generators/openapi-python-client)
64
+ (httpx + attrs), covers every operation, never edited by hand, not
65
+ committed.
66
+ - **`usenadia/__init__.py`** — this SDK's own surface: the `Nadia` class,
67
+ sane defaults, typed errors, retries. Small, hand-written, reviewed.
68
+
69
+ Anything the facade does not wrap is reachable through `nadia.raw`, the
70
+ configured generated client.
71
+
72
+ ## Errors
73
+
74
+ Every response with a status ≥ 400 raises a `NadiaError` carrying `status`,
75
+ `body` and the API's `msg`. `err.is_transient` is true for 429 and 5xx — those
76
+ are retried automatically (twice by default, `Nadia(key, retries=0)` to turn
77
+ it off).
78
+
79
+ ## Regenerating
80
+
81
+ ```bash
82
+ pnpm run sdk:generate # from the repo root — regenerates both SDKs
83
+ ```
84
+
85
+ Plan: `docs/roadmap/19-sdk-public-api.md`.
@@ -0,0 +1,33 @@
1
+ [project]
2
+ name = "usenadia"
3
+ version = "0.1.0"
4
+ description = "Python SDK for the UseNadia public API — schedule posts, manage channels, run the Instagram comment/story → DM machinery"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ license = { text = "MIT" }
8
+ dependencies = [
9
+ "httpx>=0.23,<1",
10
+ "attrs>=22.2",
11
+ "python-dateutil>=2.8",
12
+ ]
13
+
14
+ [project.urls]
15
+ Homepage = "https://usenadia.com"
16
+
17
+ [build-system]
18
+ requires = ["hatchling"]
19
+ build-backend = "hatchling.build"
20
+
21
+ [tool.hatch.build.targets.wheel]
22
+ packages = ["usenadia"]
23
+
24
+ # usenadia/generated is git-ignored (regenerated from the spec) and hatch
25
+ # leaves ignored files out: without this, the wheel ships a facade whose
26
+ # generated client is missing.
27
+ [tool.hatch.build]
28
+ artifacts = ["usenadia/generated"]
29
+
30
+ # openapi-python-client is NOT a dependency of this package: it is a build
31
+ # tool, run isolated. Its output uses `typing.Self`, hence Python >= 3.11:
32
+ # uvx openapi-python-client generate ...
33
+ # See the repo-root `pnpm sdk:generate`.
@@ -0,0 +1,131 @@
1
+ """Offline tests of the hand-written layer — no network, no API key.
2
+
3
+ Same reason as the Node side: what this facade adds over a bare `requests`
4
+ call is error handling and retries, and a regression there would be silent.
5
+
6
+ The smoke tests against the real API (plan 19, phase 4) are a different thing
7
+ and live elsewhere: these run in CI with nothing configured.
8
+
9
+ uv run --python 3.11 --with httpx --with pytest pytest tests/
10
+ """
11
+
12
+ import json
13
+
14
+ import httpx
15
+ import pytest
16
+
17
+ from usenadia import DEFAULT_BASE_URL, Nadia, NadiaError
18
+
19
+
20
+ def client_with(*responses):
21
+ """An httpx client that replays the queued responses and records requests."""
22
+ calls = []
23
+
24
+ def handler(request: httpx.Request) -> httpx.Response:
25
+ calls.append(request)
26
+ return responses[min(len(calls) - 1, len(responses) - 1)]
27
+
28
+ transport = httpx.MockTransport(handler)
29
+ return (
30
+ httpx.Client(
31
+ base_url=DEFAULT_BASE_URL,
32
+ headers={"Authorization": "ma-clef"},
33
+ transport=transport,
34
+ ),
35
+ calls,
36
+ )
37
+
38
+
39
+ def test_sends_the_api_key_and_hits_the_documented_base_url():
40
+ http, calls = client_with(httpx.Response(200, json=[{"id": "c1", "name": "Channel"}]))
41
+ nadia = Nadia("ma-clef", client=http)
42
+
43
+ assert nadia.integrations() == [{"id": "c1", "name": "Channel"}]
44
+ assert str(calls[0].url) == f"{DEFAULT_BASE_URL}/public/v1/integrations"
45
+ assert calls[0].method == "GET"
46
+ assert calls[0].headers["authorization"] == "ma-clef"
47
+
48
+
49
+ def test_a_402_raises_with_the_api_message():
50
+ http, _ = client_with(httpx.Response(402, json={"msg": "You have reached your limit"}))
51
+ nadia = Nadia("ma-clef", client=http)
52
+
53
+ with pytest.raises(NadiaError) as excinfo:
54
+ nadia.post({"type": "schedule"})
55
+
56
+ assert excinfo.value.status == 402
57
+ assert str(excinfo.value) == "You have reached your limit"
58
+ assert excinfo.value.is_transient is False
59
+
60
+
61
+ def test_a_401_raises_so_a_bad_key_is_not_silent():
62
+ http, _ = client_with(httpx.Response(401, json={"msg": "Unauthorized"}))
63
+ nadia = Nadia("mauvaise-clef", client=http)
64
+
65
+ with pytest.raises(NadiaError) as excinfo:
66
+ nadia.is_connected()
67
+
68
+ assert excinfo.value.status == 401
69
+
70
+
71
+ def test_retries_a_500_then_succeeds():
72
+ http, calls = client_with(
73
+ httpx.Response(500, json={"msg": "boom"}),
74
+ httpx.Response(200, json={"date": "2026-10-01T09:00:00.000Z"}),
75
+ )
76
+ nadia = Nadia("ma-clef", client=http)
77
+
78
+ assert nadia.find_slot("c1") == {"date": "2026-10-01T09:00:00.000Z"}
79
+ assert len(calls) == 2
80
+
81
+
82
+ def test_gives_up_after_the_configured_retries():
83
+ http, calls = client_with(httpx.Response(503, json={"msg": "boom"}))
84
+ nadia = Nadia("ma-clef", client=http, retries=1)
85
+
86
+ with pytest.raises(NadiaError) as excinfo:
87
+ nadia.groups()
88
+
89
+ assert excinfo.value.status == 503
90
+ assert len(calls) == 2
91
+
92
+
93
+ def test_an_empty_body_is_not_a_json_error():
94
+ http, _ = client_with(httpx.Response(204))
95
+ nadia = Nadia("ma-clef", client=http)
96
+
97
+ assert nadia.delete_post("p1") is None
98
+
99
+
100
+ def test_an_error_without_the_msg_shape_still_raises_cleanly():
101
+ http, _ = client_with(httpx.Response(400, text="<html>nginx</html>"))
102
+ nadia = Nadia("ma-clef", client=http)
103
+
104
+ with pytest.raises(NadiaError) as excinfo:
105
+ nadia.groups()
106
+
107
+ assert excinfo.value.status == 400
108
+ assert excinfo.value.body == "<html>nginx</html>"
109
+
110
+
111
+ def test_an_empty_api_key_is_refused_up_front():
112
+ with pytest.raises(ValueError):
113
+ Nadia("")
114
+
115
+
116
+ def test_the_board_creates_then_moves_a_card_with_only_a_stage():
117
+ http, calls = client_with(
118
+ httpx.Response(201, json={"id": "k1", "title": "Idée", "stage": "IDEA"}),
119
+ httpx.Response(200, json={"id": "k1", "stage": "SCRIPT"}),
120
+ )
121
+ nadia = Nadia("ma-clef", client=http)
122
+
123
+ card = nadia.create_content("Idée", hook="Accroche")
124
+ nadia.move_content(card["id"], "SCRIPT")
125
+
126
+ assert calls[0].method == "POST"
127
+ assert str(calls[0].url) == f"{DEFAULT_BASE_URL}/public/v1/contents"
128
+ assert json.loads(calls[0].content) == {"title": "Idée", "hook": "Accroche"}
129
+ assert calls[1].method == "PUT"
130
+ assert str(calls[1].url) == f"{DEFAULT_BASE_URL}/public/v1/contents/k1/move"
131
+ assert json.loads(calls[1].content) == {"stage": "SCRIPT"}
@@ -0,0 +1,278 @@
1
+ """UseNadia Python SDK.
2
+
3
+ Two layers, on purpose (plan 19) — this module is the second one.
4
+
5
+ usenadia/generated/ transport, regenerated from ``openapi.public.json``
6
+ by openapi-python-client, covers every operation,
7
+ never edited by hand, not committed.
8
+ usenadia/__init__.py this file: the small, hand-written surface that makes
9
+ the common calls pleasant, and that we take
10
+ responsibility for.
11
+
12
+ Anything the facade does not wrap stays reachable through :attr:`Nadia.raw`,
13
+ the configured generated client.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import time
19
+ from typing import Any, Callable, Mapping, Optional, TypeVar
20
+
21
+ import httpx
22
+
23
+ __all__ = ["Nadia", "NadiaError", "DEFAULT_BASE_URL"]
24
+
25
+ DEFAULT_BASE_URL = "https://app.usenadia.com/api"
26
+
27
+ T = TypeVar("T")
28
+
29
+
30
+ class NadiaError(Exception):
31
+ """Raised for every response with a status >= 400."""
32
+
33
+ def __init__(self, status: int, body: Any, message: Optional[str] = None):
34
+ self.status = status
35
+ self.body = body
36
+ super().__init__(message or f"UseNadia API responded {status}")
37
+
38
+ @property
39
+ def is_transient(self) -> bool:
40
+ """True when retrying later could plausibly work (rate limit, server hiccup)."""
41
+ return self.status == 429 or self.status >= 500
42
+
43
+
44
+ def _message_of(body: Any) -> Optional[str]:
45
+ """Read the API's ``{"msg": ...}`` error shape without assuming it is there."""
46
+ if isinstance(body, Mapping):
47
+ msg = body.get("msg")
48
+ if isinstance(msg, str):
49
+ return msg
50
+ return None
51
+
52
+
53
+ class Nadia:
54
+ """Client for the UseNadia public API.
55
+
56
+ >>> nadia = Nadia(api_key="...")
57
+ >>> channels = nadia.integrations()
58
+ """
59
+
60
+ def __init__(
61
+ self,
62
+ api_key: str,
63
+ base_url: str = DEFAULT_BASE_URL,
64
+ *,
65
+ retries: int = 2,
66
+ timeout: float = 30.0,
67
+ client: Optional[httpx.Client] = None,
68
+ ):
69
+ if not api_key:
70
+ raise ValueError("An API key is required.")
71
+
72
+ self._api_key = api_key
73
+ self._retries = retries
74
+ self._typed: Any = None
75
+ self._client = client or httpx.Client(
76
+ base_url=base_url.rstrip("/"),
77
+ headers={"Authorization": api_key},
78
+ timeout=timeout,
79
+ )
80
+
81
+ # ------------------------------------------------------------------ #
82
+
83
+ def _request(self, method: str, path: str, **kwargs: Any) -> Any:
84
+ """Send a request, raise :class:`NadiaError` on non-2xx, retry the
85
+ transient ones. Every method below goes through here — that is the
86
+ whole point of the facade."""
87
+ last: Optional[NadiaError] = None
88
+
89
+ for attempt in range(self._retries + 1):
90
+ response = self._client.request(method, path, **kwargs)
91
+
92
+ if response.is_success:
93
+ if not response.content:
94
+ return None
95
+ try:
96
+ return response.json()
97
+ except ValueError:
98
+ return response.content
99
+
100
+ try:
101
+ body: Any = response.json()
102
+ except ValueError:
103
+ body = response.text
104
+
105
+ last = NadiaError(response.status_code, body, _message_of(body))
106
+
107
+ if not last.is_transient or attempt == self._retries:
108
+ raise last
109
+
110
+ time.sleep(2**attempt * 0.5)
111
+
112
+ assert last is not None
113
+ raise last
114
+
115
+ # -- the five calls upstream's Node SDK had, same names -------------- #
116
+
117
+ def post(self, body: Mapping[str, Any]) -> Any:
118
+ """Schedule, publish or draft a post on one or more channels."""
119
+ return self._request("POST", "/public/v1/posts", json=body)
120
+
121
+ def post_list(self, **query: Any) -> Any:
122
+ """List posts in a date range."""
123
+ return self._request("GET", "/public/v1/posts", params=query or None)
124
+
125
+ def upload(self, file: bytes, filename: str = "upload") -> Any:
126
+ """Upload a file and get a URL usable in a post."""
127
+ return self._request(
128
+ "POST", "/public/v1/upload", files={"file": (filename, file)}
129
+ )
130
+
131
+ def integrations(self, group: Optional[str] = None) -> Any:
132
+ """List your connected channels."""
133
+ return self._request(
134
+ "GET",
135
+ "/public/v1/integrations",
136
+ params={"group": group} if group else None,
137
+ )
138
+
139
+ def delete_post(self, post_id: str) -> Any:
140
+ """Delete a post and everything published with it."""
141
+ return self._request("DELETE", f"/public/v1/posts/{post_id}")
142
+
143
+ # -- the rest of our surface, which upstream never had --------------- #
144
+
145
+ def is_connected(self) -> bool:
146
+ """Check the API key. Raises :class:`NadiaError` with status 401 if invalid."""
147
+ self._request("GET", "/public/v1/is-connected")
148
+ return True
149
+
150
+ def find_slot(self, integration_id: str) -> Any:
151
+ """Next free slot in a channel's schedule."""
152
+ return self._request("GET", f"/public/v1/find-slot/{integration_id}")
153
+
154
+ def groups(self) -> Any:
155
+ """List your groups (brands)."""
156
+ return self._request("GET", "/public/v1/groups")
157
+
158
+ def inbox(self, integration_id: str, limit: Optional[int] = None) -> Any:
159
+ """Direct message conversations of a channel."""
160
+ return self._request(
161
+ "GET",
162
+ f"/public/v1/inbox/{integration_id}",
163
+ params={"limit": limit} if limit else None,
164
+ )
165
+
166
+ # -- the content board: one card per video, idea to numbers --------- #
167
+
168
+ def contents(self, **filters: Any) -> Any:
169
+ """The cards of the board, with the posts scheduled from each.
170
+
171
+ Filters combine: ``stage``, ``tag``, ``externalId``; ``fields``
172
+ (``"id,title,stage"``) leaves the scripts out.
173
+ """
174
+ return self._request(
175
+ "GET", "/public/v1/contents", params=filters or None
176
+ )
177
+
178
+ def content(self, content_id: str) -> Any:
179
+ """One card."""
180
+ return self._request("GET", f"/public/v1/contents/{content_id}")
181
+
182
+ def create_content(self, title: str, **fields: Any) -> Any:
183
+ """Create a card — in ``IDEA`` unless ``stage`` says otherwise.
184
+
185
+ Other fields: ``externalId``, ``hook``, ``hookText``, ``script``,
186
+ ``notes``, ``tags``, ``resourceStatus``, ``resourceUrl``,
187
+ ``resourceBrief``, ``integrationIds``, ``plannedAt``, ``parentId``.
188
+ """
189
+ return self._request(
190
+ "POST", "/public/v1/contents", json={"title": title, **fields}
191
+ )
192
+
193
+ def upsert_content(self, external_id: str, title: str, **fields: Any) -> Any:
194
+ """Create or update the card holding ``external_id`` (your own id).
195
+
196
+ Re-running an import never duplicates; an existing card keeps its
197
+ column. Returns ``{"created": bool, "content": {...}}``.
198
+ """
199
+ return self._request(
200
+ "POST",
201
+ "/public/v1/contents/upsert",
202
+ json={"externalId": external_id, "title": title, **fields},
203
+ )
204
+
205
+ def update_content(self, content_id: str, **fields: Any) -> Any:
206
+ """Update a card: only the fields passed change, ``None`` clears one."""
207
+ return self._request(
208
+ "PUT", f"/public/v1/contents/{content_id}", json=fields
209
+ )
210
+
211
+ def move_content(
212
+ self, content_id: str, stage: str, position: Optional[float] = None
213
+ ) -> Any:
214
+ """Move a card to another column (to the bottom unless ``position`` is given)."""
215
+ body: dict = {"stage": stage}
216
+ if position is not None:
217
+ body["position"] = position
218
+ return self._request(
219
+ "PUT", f"/public/v1/contents/{content_id}/move", json=body
220
+ )
221
+
222
+ def link_content_post(self, content_id: str, post_group: str) -> Any:
223
+ """Tie a card to a post scheduled from it (the post's ``group``).
224
+
225
+ A card holds several posts (a TikTok draft, an Instagram post): each
226
+ call adds one. The card moves to ``PUBLISHED`` when the first of them
227
+ goes live.
228
+ """
229
+ return self._request(
230
+ "PUT",
231
+ f"/public/v1/contents/{content_id}/post",
232
+ json={"postGroup": post_group},
233
+ )
234
+
235
+ def delete_content(self, content_id: str) -> Any:
236
+ """Delete a card."""
237
+ return self._request("DELETE", f"/public/v1/contents/{content_id}")
238
+
239
+ def contents_performance(self) -> Any:
240
+ """The numbers of the published cards, keyed by card id."""
241
+ return self._request("GET", "/public/v1/contents/performance")
242
+
243
+ # ------------------------------------------------------------------ #
244
+
245
+ @property
246
+ def raw(self) -> httpx.Client:
247
+ """The configured httpx client, for a call the facade does not wrap."""
248
+ return self._client
249
+
250
+ @property
251
+ def typed(self) -> Any:
252
+ """The generated, fully typed client — every operation, with models.
253
+
254
+ >>> from usenadia.generated.api.public_api import list_channels
255
+ >>> list_channels.sync(client=nadia.typed)
256
+
257
+ Imported lazily so the facade still works from a checkout where the
258
+ client has not been generated yet (it is gitignored, see the README).
259
+ """
260
+ if self._typed is None:
261
+ from .generated import AuthenticatedClient # noqa: PLC0415
262
+
263
+ self._typed = AuthenticatedClient(
264
+ base_url=str(self._client.base_url),
265
+ token=self._api_key,
266
+ # The API reads `Authorization: <key>`, with no `Bearer` prefix.
267
+ prefix="",
268
+ )
269
+ return self._typed
270
+
271
+ def close(self) -> None:
272
+ self._client.close()
273
+
274
+ def __enter__(self) -> "Nadia":
275
+ return self
276
+
277
+ def __exit__(self, *exc: Any) -> None:
278
+ self.close()
@@ -0,0 +1,8 @@
1
+ """A client library for accessing UseNadia public API"""
2
+
3
+ from .client import AuthenticatedClient, Client
4
+
5
+ __all__ = (
6
+ "AuthenticatedClient",
7
+ "Client",
8
+ )
@@ -0,0 +1 @@
1
+ """Contains methods for accessing the API"""
@@ -0,0 +1 @@
1
+ """Contains endpoint functions for accessing the API"""