From 04ef3ba592875430ce0e56341c5fe124e6a6843a Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 22:52:53 +0000 Subject: [PATCH] [fern-generated] Update SDK Generated by Fern CLI Version: unknown Generators: - fernapi/fern-python-sdk: 4.63.4 --- .fern/metadata.json | 6 +- .fern/replay.lock | 10 + .fernignore | 5 +- .gitattributes | 1 + poetry.lock | 116 +- pyproject.toml | 2 +- reference.md | 4630 ++++++++++++----- src/webflow/__init__.py | 195 +- src/webflow/client.py | 38 + src/webflow/core/client_wrapper.py | 4 +- src/webflow/errors/__init__.py | 3 + .../errors/service_unavailable_error.py | 11 + src/webflow/resources/__init__.py | 27 +- src/webflow/resources/analyze/__init__.py | 55 + src/webflow/resources/analyze/client.py | 63 + src/webflow/resources/analyze/raw_client.py | 13 + .../resources/analyze/resources/__init__.py | 55 + .../analyze/resources/reports/__init__.py | 52 + .../analyze/resources/reports/client.py | 1482 ++++++ .../analyze/resources/reports/raw_client.py | 2046 ++++++++ .../resources/reports/types/__init__.py | 50 + ...eports_time_on_page_request_device_type.py | 5 + ...orts_top_dimensions_request_device_type.py | 5 + .../reports_top_events_request_device_type.py | 5 + .../reports_top_pages_request_device_type.py | 5 + .../reports_traffic_request_device_type.py | 5 + src/webflow/resources/assets/client.py | 106 +- src/webflow/resources/assets/raw_client.py | 90 +- .../resources/fields/raw_client.py | 6 - .../collections/resources/items/client.py | 52 +- .../collections/resources/items/raw_client.py | 66 +- .../items_list_items_live_request_sort_by.py | 4 +- .../types/items_list_items_request_sort_by.py | 4 +- src/webflow/resources/components/client.py | 16 +- .../resources/components/raw_client.py | 16 +- .../resources/custom_fonts/__init__.py | 52 + src/webflow/resources/custom_fonts/client.py | 903 ++++ .../resources/custom_fonts/raw_client.py | 1969 +++++++ .../resources/custom_fonts/types/__init__.py | 50 + ...om_font_batch_delete_request_items_item.py | 22 + ...ustom_fonts_create_request_font_display.py | 7 + .../types/custom_fonts_get_response.py | 24 + ...ustom_fonts_update_request_font_display.py | 7 + .../types/custom_fonts_update_response.py | 24 + src/webflow/resources/pages/client.py | 26 +- src/webflow/resources/pages/raw_client.py | 26 +- .../pages/resources/scripts/client.py | 8 + .../pages/resources/scripts/raw_client.py | 14 +- src/webflow/resources/scripts/client.py | 12 + src/webflow/resources/scripts/raw_client.py | 12 + src/webflow/resources/sites/__init__.py | 7 +- src/webflow/resources/sites/client.py | 43 +- src/webflow/resources/sites/raw_client.py | 24 +- .../resources/sites/resources/__init__.py | 4 +- .../sites/resources/comments/client.py | 12 +- .../sites/resources/comments/raw_client.py | 12 +- .../sites/resources/google_tag/__init__.py | 4 + .../sites/resources/google_tag/client.py | 388 ++ .../sites/resources/google_tag/raw_client.py | 863 +++ .../sites/resources/redirects/raw_client.py | 12 - .../sites/resources/robots_txt/raw_client.py | 18 - .../sites/resources/scripts/client.py | 12 + .../sites/resources/scripts/raw_client.py | 18 +- src/webflow/resources/sites/types/__init__.py | 8 +- .../sites/types/sites_publish_response.py | 6 + .../sites_publish_response_publish_scope.py | 5 + src/webflow/resources/token/client.py | 4 +- src/webflow/resources/token/raw_client.py | 4 +- src/webflow/resources/webhooks/client.py | 4 +- src/webflow/resources/webhooks/raw_client.py | 10 +- src/webflow/types/__init__.py | 170 +- src/webflow/types/analyze_bucket_time_zone.py | 3 + src/webflow/types/analyze_daily_bucketing.py | 33 + .../types/analyze_daily_timeseries_query.py | 28 + src/webflow/types/analyze_filter_operators.py | 46 + .../types/analyze_time_on_page_bucketing.py | 32 + src/webflow/types/analyze_window.py | 39 + src/webflow/types/asset.py | 8 + src/webflow/types/comment_payload.py | 9 +- src/webflow/types/component_property.py | 44 +- src/webflow/types/component_property_text.py | 45 + .../types/component_property_text_type.py | 5 + src/webflow/types/component_property_type.py | 5 - src/webflow/types/custom_font.py | 72 + src/webflow/types/custom_font_axis.py | 52 + .../custom_font_batch_delete_response.py | 26 + ...font_batch_delete_response_deleted_item.py | 22 + ..._font_batch_delete_response_failed_item.py | 32 + .../types/custom_font_create_response.py | 30 + src/webflow/types/custom_font_font_display.py | 5 + src/webflow/types/custom_font_format.py | 7 + src/webflow/types/custom_font_upload.py | 40 + .../types/custom_font_upload_fields.py | 94 + ...ditional_properties.py => custom_fonts.py} | 13 +- src/webflow/types/error_code.py | 7 + ...field_validations_additional_properties.py | 8 +- src/webflow/types/form_submission.py | 8 + .../types/form_submission_trigger_payload.py | 8 + src/webflow/types/google_tag_id.py | 42 + src/webflow/types/google_tag_ids.py | 30 + ...tems_list_items_live_request_created_on.py | 28 + ...ms_list_items_live_request_last_updated.py | 28 + .../items_list_items_request_created_on.py | 28 + .../items_list_items_request_last_updated.py | 28 + .../types/page_created_webhook_payload.py | 20 + .../types/page_deleted_webhook_payload.py | 20 + .../page_metadata_updated_webhook_payload.py | 20 + src/webflow/types/site_activity_log_item.py | 31 + .../site_activity_log_item_actor_type.py | 5 + .../types/site_activity_log_item_source.py | 5 + src/webflow/types/site_publish_payload.py | 13 +- .../site_publish_payload_publish_scope.py | 5 + src/webflow/types/time_on_page_data_point.py | 38 + src/webflow/types/time_on_page_filter.py | 114 + .../types/time_on_page_granularity_period.py | 5 + .../types/time_on_page_metric_scope.py | 5 + src/webflow/types/time_on_page_response.py | 45 + .../types/time_on_page_timeseries_query.py | 32 + src/webflow/types/top_dimensions_dimension.py | 24 + src/webflow/types/top_dimensions_filter.py | 114 + .../types/top_dimensions_metric_scope.py | 5 + src/webflow/types/top_dimensions_response.py | 50 + src/webflow/types/top_dimensions_row.py | 41 + .../types/top_events_cms_context_entry.py | 32 + .../top_events_component_context_entry.py | 34 + src/webflow/types/top_events_filter.py | 85 + src/webflow/types/top_events_response.py | 44 + src/webflow/types/top_events_row.py | 93 + .../types/top_events_timeseries_point.py | 34 + src/webflow/types/top_pages_filter.py | 114 + src/webflow/types/top_pages_response.py | 48 + src/webflow/types/top_pages_row.py | 76 + src/webflow/types/top_pages_sort_by.py | 5 + .../types/top_pages_timeseries_point.py | 39 + src/webflow/types/traffic_data_point.py | 32 + src/webflow/types/traffic_filter.py | 114 + src/webflow/types/traffic_metric_scope.py | 5 + src/webflow/types/traffic_response.py | 45 + 138 files changed, 14830 insertions(+), 1500 deletions(-) create mode 100644 .fern/replay.lock create mode 100644 .gitattributes create mode 100644 src/webflow/errors/service_unavailable_error.py create mode 100644 src/webflow/resources/analyze/__init__.py create mode 100644 src/webflow/resources/analyze/client.py create mode 100644 src/webflow/resources/analyze/raw_client.py create mode 100644 src/webflow/resources/analyze/resources/__init__.py create mode 100644 src/webflow/resources/analyze/resources/reports/__init__.py create mode 100644 src/webflow/resources/analyze/resources/reports/client.py create mode 100644 src/webflow/resources/analyze/resources/reports/raw_client.py create mode 100644 src/webflow/resources/analyze/resources/reports/types/__init__.py create mode 100644 src/webflow/resources/analyze/resources/reports/types/reports_time_on_page_request_device_type.py create mode 100644 src/webflow/resources/analyze/resources/reports/types/reports_top_dimensions_request_device_type.py create mode 100644 src/webflow/resources/analyze/resources/reports/types/reports_top_events_request_device_type.py create mode 100644 src/webflow/resources/analyze/resources/reports/types/reports_top_pages_request_device_type.py create mode 100644 src/webflow/resources/analyze/resources/reports/types/reports_traffic_request_device_type.py create mode 100644 src/webflow/resources/custom_fonts/__init__.py create mode 100644 src/webflow/resources/custom_fonts/client.py create mode 100644 src/webflow/resources/custom_fonts/raw_client.py create mode 100644 src/webflow/resources/custom_fonts/types/__init__.py create mode 100644 src/webflow/resources/custom_fonts/types/custom_font_batch_delete_request_items_item.py create mode 100644 src/webflow/resources/custom_fonts/types/custom_fonts_create_request_font_display.py create mode 100644 src/webflow/resources/custom_fonts/types/custom_fonts_get_response.py create mode 100644 src/webflow/resources/custom_fonts/types/custom_fonts_update_request_font_display.py create mode 100644 src/webflow/resources/custom_fonts/types/custom_fonts_update_response.py create mode 100644 src/webflow/resources/sites/resources/google_tag/__init__.py create mode 100644 src/webflow/resources/sites/resources/google_tag/client.py create mode 100644 src/webflow/resources/sites/resources/google_tag/raw_client.py create mode 100644 src/webflow/resources/sites/types/sites_publish_response_publish_scope.py create mode 100644 src/webflow/types/analyze_bucket_time_zone.py create mode 100644 src/webflow/types/analyze_daily_bucketing.py create mode 100644 src/webflow/types/analyze_daily_timeseries_query.py create mode 100644 src/webflow/types/analyze_filter_operators.py create mode 100644 src/webflow/types/analyze_time_on_page_bucketing.py create mode 100644 src/webflow/types/analyze_window.py create mode 100644 src/webflow/types/component_property_text.py create mode 100644 src/webflow/types/component_property_text_type.py delete mode 100644 src/webflow/types/component_property_type.py create mode 100644 src/webflow/types/custom_font.py create mode 100644 src/webflow/types/custom_font_axis.py create mode 100644 src/webflow/types/custom_font_batch_delete_response.py create mode 100644 src/webflow/types/custom_font_batch_delete_response_deleted_item.py create mode 100644 src/webflow/types/custom_font_batch_delete_response_failed_item.py create mode 100644 src/webflow/types/custom_font_create_response.py create mode 100644 src/webflow/types/custom_font_font_display.py create mode 100644 src/webflow/types/custom_font_format.py create mode 100644 src/webflow/types/custom_font_upload.py create mode 100644 src/webflow/types/custom_font_upload_fields.py rename src/webflow/types/{field_validations_additional_properties_additional_properties.py => custom_fonts.py} (61%) create mode 100644 src/webflow/types/google_tag_id.py create mode 100644 src/webflow/types/google_tag_ids.py create mode 100644 src/webflow/types/items_list_items_live_request_created_on.py create mode 100644 src/webflow/types/items_list_items_live_request_last_updated.py create mode 100644 src/webflow/types/items_list_items_request_created_on.py create mode 100644 src/webflow/types/items_list_items_request_last_updated.py create mode 100644 src/webflow/types/site_activity_log_item_actor_type.py create mode 100644 src/webflow/types/site_activity_log_item_source.py create mode 100644 src/webflow/types/site_publish_payload_publish_scope.py create mode 100644 src/webflow/types/time_on_page_data_point.py create mode 100644 src/webflow/types/time_on_page_filter.py create mode 100644 src/webflow/types/time_on_page_granularity_period.py create mode 100644 src/webflow/types/time_on_page_metric_scope.py create mode 100644 src/webflow/types/time_on_page_response.py create mode 100644 src/webflow/types/time_on_page_timeseries_query.py create mode 100644 src/webflow/types/top_dimensions_dimension.py create mode 100644 src/webflow/types/top_dimensions_filter.py create mode 100644 src/webflow/types/top_dimensions_metric_scope.py create mode 100644 src/webflow/types/top_dimensions_response.py create mode 100644 src/webflow/types/top_dimensions_row.py create mode 100644 src/webflow/types/top_events_cms_context_entry.py create mode 100644 src/webflow/types/top_events_component_context_entry.py create mode 100644 src/webflow/types/top_events_filter.py create mode 100644 src/webflow/types/top_events_response.py create mode 100644 src/webflow/types/top_events_row.py create mode 100644 src/webflow/types/top_events_timeseries_point.py create mode 100644 src/webflow/types/top_pages_filter.py create mode 100644 src/webflow/types/top_pages_response.py create mode 100644 src/webflow/types/top_pages_row.py create mode 100644 src/webflow/types/top_pages_sort_by.py create mode 100644 src/webflow/types/top_pages_timeseries_point.py create mode 100644 src/webflow/types/traffic_data_point.py create mode 100644 src/webflow/types/traffic_filter.py create mode 100644 src/webflow/types/traffic_metric_scope.py create mode 100644 src/webflow/types/traffic_response.py diff --git a/.fern/metadata.json b/.fern/metadata.json index 44a2882..365afaf 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -1,5 +1,5 @@ { - "cliVersion": "4.22.0", + "cliVersion": "5.35.2", "generatorName": "fernapi/fern-python-sdk", "generatorVersion": "4.63.4", "generatorConfig": { @@ -9,6 +9,6 @@ "use_str_enums": false } }, - "originGitCommit": "3ad89f5558f1774e8535f034a87bfe8c2fdfcd50", - "sdkVersion": "2.0.0" + "originGitCommit": "296506977541e3dff661bd5dfeb4fe64f201051f", + "sdkVersion": "2.0.1" } \ No newline at end of file diff --git a/.fern/replay.lock b/.fern/replay.lock new file mode 100644 index 0000000..6168824 --- /dev/null +++ b/.fern/replay.lock @@ -0,0 +1,10 @@ +# DO NOT EDIT MANUALLY - Managed by Fern Replay +version: "1.0" +generations: + - commit_sha: 1e6e7e02a6c6be33f48b6569f6ca20dc332a6c1c + tree_hash: 5fb8f4ca091f71069b3a2604ea9f5211f2e417e5 + timestamp: 2026-06-16T22:52:51.469Z + cli_version: unknown + generator_versions: {} +current_generation: 1e6e7e02a6c6be33f48b6569f6ca20dc332a6c1c +patches: [] diff --git a/.fernignore b/.fernignore index e83159b..e2a4565 100644 --- a/.fernignore +++ b/.fernignore @@ -4,4 +4,7 @@ README.md assets/ src/webflow/oauth.py -src/webflow/types/oauth_scope.py \ No newline at end of file +src/webflow/types/oauth_scope.py +.fern/replay.lock +.fern/replay.yml +.gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..74928d6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +.fern/replay.lock linguist-generated=true diff --git a/poetry.lock b/poetry.lock index 83fdc8b..1f9536d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,13 +38,13 @@ trio = ["trio (>=0.26.1)"] [[package]] name = "certifi" -version = "2026.2.25" +version = "2026.5.20" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" files = [ - {file = "certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa"}, - {file = "certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"}, + {file = "certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897"}, + {file = "certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d"}, ] [[package]] @@ -147,17 +147,17 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "idna" -version = "3.11" +version = "3.15" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.8" files = [ - {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, - {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, + {file = "idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8"}, + {file = "idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc"}, ] [package.extras] -all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] [[package]] name = "iniconfig" @@ -236,13 +236,13 @@ files = [ [[package]] name = "packaging" -version = "26.0" +version = "26.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, - {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, + {file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"}, + {file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"}, ] [[package]] @@ -517,58 +517,58 @@ files = [ [[package]] name = "tomli" -version = "2.4.0" +version = "2.4.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, - {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, - {file = "tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95"}, - {file = "tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76"}, - {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d"}, - {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576"}, - {file = "tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a"}, - {file = "tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa"}, - {file = "tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614"}, - {file = "tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1"}, - {file = "tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8"}, - {file = "tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a"}, - {file = "tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1"}, - {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b"}, - {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51"}, - {file = "tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729"}, - {file = "tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da"}, - {file = "tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3"}, - {file = "tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0"}, - {file = "tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e"}, - {file = "tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4"}, - {file = "tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e"}, - {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c"}, - {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f"}, - {file = "tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86"}, - {file = "tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87"}, - {file = "tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132"}, - {file = "tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6"}, - {file = "tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc"}, - {file = "tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66"}, - {file = "tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d"}, - {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702"}, - {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8"}, - {file = "tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776"}, - {file = "tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475"}, - {file = "tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2"}, - {file = "tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9"}, - {file = "tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0"}, - {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df"}, - {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d"}, - {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f"}, - {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b"}, - {file = "tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087"}, - {file = "tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd"}, - {file = "tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4"}, - {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"}, - {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc"}, + {file = "tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049"}, + {file = "tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e"}, + {file = "tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1"}, + {file = "tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917"}, + {file = "tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9"}, + {file = "tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5"}, + {file = "tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd"}, + {file = "tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36"}, + {file = "tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba"}, + {file = "tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6"}, + {file = "tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7"}, + {file = "tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f"}, + {file = "tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8"}, + {file = "tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26"}, + {file = "tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396"}, + {file = "tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe"}, + {file = "tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 786103a..2aa101e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ dynamic = ["version"] [tool.poetry] name = "webflow" -version = "2.0.0" +version = "2.0.1" description = "" readme = "README.md" authors = [] diff --git a/reference.md b/reference.md index fbfbd16..e248b2b 100644 --- a/reference.md +++ b/reference.md @@ -79,7 +79,7 @@ client.token.authorized_by() Information about the authorization token -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). +Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/data-clients/getting-started). @@ -630,10 +630,15 @@ client.sites.get_custom_domain(
-Publishes a site to one or more more domains. +Publishes a site or an individual page to one or more domains. +If multiple individual pages are published to staging, publishing from staging to production publishes all staged changes. To publish to a specific custom domain, use the domain IDs from the [Get Custom Domains](/data/reference/sites/get-custom-domain) endpoint. +You must include at least one of the `customDomains` or `publishToWebflowSubdomain` properties in the request body. + +To publish an individual page instead of the entire site, provide the ID of the page in the `pageId` parameter. + This endpoint has a specific rate limit of one successful publish queue per minute. Required scope | `sites:write` @@ -706,6 +711,14 @@ client.sites.publish(
+**page_id:** `typing.Optional[str]` — The ID of the page to publish + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -1147,7 +1160,7 @@ client.pages.list( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization)
@@ -1251,7 +1264,7 @@ client.pages.get_metadata( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) @@ -1352,7 +1365,7 @@ client.pages.update_page_settings( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) @@ -1372,8 +1385,9 @@ Unique identifier for a specific Locale. Slug for the page. - -**Note:** Updating slugs in secondary locales is only supported in Advanced and Enterprise localization add-on plans. +**Note:** The slug field is ignored in the following cases — all other fields in the same request still apply: +- The site's home page, collection template pages, and utility pages (e.g. 404, password, search). +- For secondary locales, updating the slug requires an Advanced or Enterprise localization add-on plan. @@ -1481,7 +1495,7 @@ client.pages.get_content( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) @@ -1826,7 +1840,7 @@ client.components.get_content( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) @@ -1987,7 +2001,7 @@ client.components.update_content( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) @@ -2097,7 +2111,7 @@ client.components.get_properties( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) @@ -2244,7 +2258,7 @@ client.components.update_properties( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) @@ -2291,6 +2305,8 @@ Get a list of scripts that have been registered to a site. A site can have a max To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. +Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` @@ -2370,6 +2386,8 @@ Register a hosted script to a site. To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. +Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` @@ -2493,6 +2511,8 @@ Register an inline script to a site. Inline scripts are limited to 2000 characte To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. +Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` @@ -2637,8 +2657,10 @@ client = Webflow( client.assets.list( site_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", offset=1, limit=1, + folder_id="folderId", ) ``` @@ -2663,6 +2685,18 @@ client.assets.list(
+**locale_id:** `typing.Optional[str]` + +Unique identifier for a specific Locale. + +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + +
+
+ +
+
+ **offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
@@ -2679,6 +2713,17 @@ client.assets.list(
+**folder_id:** `typing.Optional[str]` + +Filter assets to those in the specified folder and all descendant folders. +Must be a 24-character hex ObjectId. + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -2840,6 +2885,7 @@ client = Webflow( client.assets.get( asset_id="580e63fc8c9a982ac9b8b745", + locale_id="65427cf400e02b306eaa04a0", ) ``` @@ -2864,6 +2910,18 @@ client.assets.get(
+**locale_id:** `typing.Optional[str]` + +Unique identifier for a specific Locale. + +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -2990,6 +3048,7 @@ client = Webflow( client.assets.update( asset_id="580e63fc8c9a982ac9b8b745", + locale_id="65427cf400e02b306eaa04a0", ) ``` @@ -3014,7 +3073,19 @@ client.assets.update(
-**locale_id:** `typing.Optional[str]` — Unique identifier for a specific locale. Applicable, when using localization. +**locale_id:** `typing.Optional[str]` + +Unique identifier for a specific Locale. + +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + +
+
+ +
+
+ +**display_name:** `typing.Optional[str]` — A human readable name for the asset. This value is not localizable.
@@ -3022,7 +3093,7 @@ client.assets.update(
-**display_name:** `typing.Optional[str]` — A human readable name for the asset +**alt_text:** `typing.Optional[str]` — Alternate text describing the image
@@ -3284,8 +3355,8 @@ client.assets.get_folder(
-## Webhooks -
client.webhooks.list(...) -> WebhookList +## Custom Fonts +
client.custom_fonts.list(...) -> CustomFonts
@@ -3297,7 +3368,7 @@ client.assets.get_folder(
-List all App-created Webhooks registered for a given site +List the custom fonts uploaded to a site. Required scope | `sites:read`
@@ -3322,8 +3393,10 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.webhooks.list( +client.custom_fonts.list( site_id="580e63e98c9a982ac9b8b741", + offset=1, + limit=1, ) ``` @@ -3348,6 +3421,22 @@ client.webhooks.list(
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -3360,7 +3449,7 @@ client.webhooks.list(
-
client.webhooks.create(...) -> Webhook +
client.custom_fonts.create(...) -> CustomFontCreateResponse
@@ -3372,11 +3461,14 @@ client.webhooks.list(
-Create a new Webhook. +Register a custom font on a site and get a presigned S3 URL to upload the font binary. -Limit of 75 registrations per `triggerType`, per site. +The response includes a `customFont` object and an `upload` object. Use the `upload.url` and `upload.fields` +to POST the font binary directly to S3 as `multipart/form-data`. The binary must go in a field named `file` +and must be the last field in the form (an AWS S3 requirement). S3 returns `201 Created` on a successful upload. + +To learn more, see [Custom fonts](/data/docs/custom-fonts). -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). Required scope | `sites:write`
@@ -3394,22 +3486,20 @@ Required scope | `sites:write` ```python from webflow import Webflow from webflow.environment import WebflowEnvironment -import datetime client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.webhooks.create( - site_id_="580e63e98c9a982ac9b8b741", - id="582266e0cd48de0f0e3c6d8b", - trigger_type="form_submission", - url="https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f", - workspace_id="4f4e46fd476ea8c507000001", - site_id="562ac0395358780a1f5e6fbd", - last_triggered=datetime.datetime.fromisoformat("2023-02-08T23:59:28+00:00"), - created_on=datetime.datetime.fromisoformat("2022-11-08T23:59:28+00:00"), +client.custom_fonts.create( + site_id="580e63e98c9a982ac9b8b741", + file_name="AcmeSans-Regular.woff2", + file_hash="3c7d87c9575702bc3b1e991f4d3c638e", + font_family="Acme Sans", + weight=400, + italic=False, + font_display="auto", ) ``` @@ -3434,7 +3524,7 @@ client.webhooks.create(
-**request:** `Webhook` +**file_name:** `str` — File name including extension. Accepted extensions are `.woff2`, `.woff`, `.ttf`, `.otf`, and `.eot`. Maximum 256 characters.
@@ -3442,74 +3532,47 @@ client.webhooks.create(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**file_hash:** `str` — Lowercase hex MD5 hash of the font binary (exactly 32 characters)
-
-
+
+
+**font_family:** `str` — The CSS font-family name (1-256 characters). Commas are stripped server-side. +
-
-
client.webhooks.get(...) -> Webhook
-#### 📝 Description - -
-
+**weight:** `int` — CSS font-weight value (1-1000) + +
+
-Get a specific Webhook instance - -Required scope: `sites:read` -
-
+**italic:** `bool` — Whether the font is italic +
-#### 🔌 Usage - -
-
-
-```python -from webflow import Webflow -from webflow.environment import WebflowEnvironment - -client = Webflow( - access_token="", - environment=WebflowEnvironment.DATA_API, -) - -client.webhooks.get( - webhook_id="580e64008c9a982ac9b8b754", -) - -``` -
-
+**font_display:** `CustomFontsCreateRequestFontDisplay` — CSS font-display value +
-#### ⚙️ Parameters -
-
-
- -**webhook_id:** `str` — Unique identifier for a Webhook +**axes:** `typing.Optional[typing.List[CustomFontAxis]]` — Variable font axes. Omit or pass an empty array for static fonts.
@@ -3529,7 +3592,7 @@ client.webhooks.get(
-
client.webhooks.delete(...) +
client.custom_fonts.get(...) -> CustomFontsGetResponse
@@ -3541,9 +3604,9 @@ client.webhooks.get(
-Remove a Webhook +Get details about a custom font on a site. -Required scope: `sites:read` +Required scope | `sites:read`
@@ -3566,8 +3629,9 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.webhooks.delete( - webhook_id="580e64008c9a982ac9b8b754", +client.custom_fonts.get( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", ) ``` @@ -3584,7 +3648,15 @@ client.webhooks.delete(
-**webhook_id:** `str` — Unique identifier for a Webhook +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**font_id:** `str` — Unique identifier for a custom font on a site
@@ -3604,8 +3676,7 @@ client.webhooks.delete(
-## Forms -
client.forms.list(...) -> FormList +
client.custom_fonts.delete(...)
@@ -3617,9 +3688,9 @@ client.webhooks.delete(
-List forms for a given site. +Delete a custom font from a site. -Required scope | `forms:read` +Required scope | `sites:write`
@@ -3642,10 +3713,9 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.forms.list( +client.custom_fonts.delete( site_id="580e63e98c9a982ac9b8b741", - limit=1, - offset=1, + font_id="66f3a1b2c4d5e6f7a8b9c0d1", ) ``` @@ -3670,15 +3740,7 @@ client.forms.list(
-**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100) - -
-
- -
-
- -**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records +**font_id:** `str` — Unique identifier for a custom font on a site
@@ -3698,7 +3760,7 @@ client.forms.list(
-
client.forms.get(...) -> Form +
client.custom_fonts.update(...) -> CustomFontsUpdateResponse
@@ -3710,9 +3772,12 @@ client.forms.list(
-Get information about a given form. +Update the metadata of a custom font. The font binary is not changed by this endpoint. +To replace the binary, use [Replace custom font file](#operation/replace-custom-font-file). -Required scope | `forms:read` +The request body must include at least one of `fontFamily`, `weight`, `italic`, or `fontDisplay`. + +Required scope | `sites:write`
@@ -3735,8 +3800,9 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.forms.get( - form_id="580e63e98c9a982ac9b8b741", +client.custom_fonts.update( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", ) ``` @@ -3753,7 +3819,47 @@ client.forms.get(
-**form_id:** `str` — Unique identifier for a Form +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**font_id:** `str` — Unique identifier for a custom font on a site + +
+
+ +
+
+ +**font_family:** `typing.Optional[str]` — The CSS font-family name (1-256 characters) + +
+
+ +
+
+ +**weight:** `typing.Optional[int]` — CSS font-weight value (1-1000) + +
+
+ +
+
+ +**italic:** `typing.Optional[bool]` — Whether the font is italic + +
+
+ +
+
+ +**font_display:** `typing.Optional[CustomFontsUpdateRequestFontDisplay]` — CSS font-display value
@@ -3773,7 +3879,7 @@ client.forms.get(
-
client.forms.list_submissions(...) -> FormSubmissionList +
client.custom_fonts.replace_file(...) -> CustomFontCreateResponse
@@ -3785,15 +3891,14 @@ client.forms.get(
-List form submissions for a given form - - - When a form is used in a component definition, each instance of the form is considered a unique form. +Replace the binary of an existing custom font while preserving its ID and any references to it. +The upload handshake is identical to [Create custom font](#operation/create-custom-font). - To get a combined list of submissions for a form that appears across multiple component instances, use the [List Form Submissions by Site](/data/reference/forms/form-submissions/list-submissions-by-site) endpoint. - +If the existing font has a non-empty `axes` array (a variable font), you must include an `axes` field +in the request. Send `axes: []` to declare that the new binary is a static font, or send the new variable +axes to declare it is still variable. Omitting `axes` when the existing font is variable returns `400`. -Required scope | `forms:read` +Required scope | `sites:write`
@@ -3816,10 +3921,11 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.forms.list_submissions( - form_id="580e63e98c9a982ac9b8b741", - offset=1, - limit=1, +client.custom_fonts.replace_file( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", + file_name="AcmeSans-Regular-v2.woff2", + file_hash="3c7d87c9575702bc3b1e991f4d3c638e", ) ``` @@ -3836,7 +3942,7 @@ client.forms.list_submissions(
-**form_id:** `str` — Unique identifier for a Form +**site_id:** `str` — Unique identifier for a Site
@@ -3844,7 +3950,7 @@ client.forms.list_submissions(
-**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records +**font_id:** `str` — Unique identifier for a custom font on a site
@@ -3852,7 +3958,7 @@ client.forms.list_submissions(
-**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100) +**file_name:** `str` — File name including extension. Accepted extensions are `.woff2`, `.woff`, `.ttf`, `.otf`, and `.eot`. Maximum 256 characters.
@@ -3860,33 +3966,54 @@ client.forms.list_submissions(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**file_hash:** `str` — Lowercase hex MD5 hash of the font binary (exactly 32 characters)
- -
+
+
+**axes:** `typing.Optional[typing.List[CustomFontAxis]]` — Variable font axes for the replacement binary. Required when the existing font has a non-empty `axes` array. +
-
-
client.forms.get_submission(...) -> FormSubmission
-#### 📝 Description - -
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ +
+ + + +
+ + +
client.custom_fonts.batch_delete(...) -> CustomFontBatchDeleteResponse +
+#### 📝 Description +
-Get information about a given form submissio. +
+
-Required scope | `forms:read` +Delete 1-100 custom fonts in a single request. The response is always `200 OK` for a valid request body. +Per-font results are reported in the `deleted` and `failed` arrays. + +The endpoint is idempotent: fonts that do not exist appear in `failed` with `name: "NotFound"` rather than +failing the entire request. You can safely retry a partial failure by re-sending only the IDs that did not +appear in `deleted`. + +Required scope | `sites:write`
@@ -3903,14 +4030,20 @@ Required scope | `forms:read` ```python from webflow import Webflow from webflow.environment import WebflowEnvironment +from webflow.custom_fonts import CustomFontBatchDeleteRequestItemsItem client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.forms.get_submission( - form_submission_id="580e63e98c9a982ac9b8b741", +client.custom_fonts.batch_delete( + site_id="580e63e98c9a982ac9b8b741", + items=[ + CustomFontBatchDeleteRequestItemsItem( + id="66f3a1b2c4d5e6f7a8b9c0d1", + ) + ], ) ``` @@ -3927,7 +4060,15 @@ client.forms.get_submission(
-**form_submission_id:** `str` — Unique identifier for a Form Submission +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**items:** `typing.List[CustomFontBatchDeleteRequestItemsItem]`
@@ -3947,7 +4088,8 @@ client.forms.get_submission(
-
client.forms.delete_submission(...) +## Webhooks +
client.webhooks.list(...) -> WebhookList
@@ -3959,10 +4101,9 @@ client.forms.get_submission(
-Delete a form submission - +List all App-created Webhooks registered for a given site -Required scope | `forms:write` +Required scope | `sites:read`
@@ -3985,8 +4126,8 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.forms.delete_submission( - form_submission_id="580e63e98c9a982ac9b8b741", +client.webhooks.list( + site_id="580e63e98c9a982ac9b8b741", ) ``` @@ -4003,7 +4144,7 @@ client.forms.delete_submission(
-**form_submission_id:** `str` — Unique identifier for a Form Submission +**site_id:** `str` — Unique identifier for a Site
@@ -4023,7 +4164,7 @@ client.forms.delete_submission(
-
client.forms.update_submission(...) -> FormSubmission +
client.webhooks.create(...) -> Webhook
@@ -4035,9 +4176,12 @@ client.forms.delete_submission(
-Update hidden fields on a form submission +Create a new Webhook. -Required scope | `forms:write` +Limit of 75 registrations per `triggerType`, per site. + +Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/data-clients/getting-started). +Required scope | `sites:write`
@@ -4054,14 +4198,22 @@ Required scope | `forms:write` ```python from webflow import Webflow from webflow.environment import WebflowEnvironment +import datetime client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.forms.update_submission( - form_submission_id="580e63e98c9a982ac9b8b741", +client.webhooks.create( + site_id_="580e63e98c9a982ac9b8b741", + id="582266e0cd48de0f0e3c6d8b", + trigger_type="form_submission", + url="https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f", + workspace_id="4f4e46fd476ea8c507000001", + site_id="562ac0395358780a1f5e6fbd", + last_triggered=datetime.datetime.fromisoformat("2023-02-08T23:59:28+00:00"), + created_on=datetime.datetime.fromisoformat("2022-11-08T23:59:28+00:00"), ) ``` @@ -4078,7 +4230,7 @@ client.forms.update_submission(
-**form_submission_id:** `str` — Unique identifier for a Form Submission +**site_id:** `str` — Unique identifier for a Site
@@ -4086,7 +4238,7 @@ client.forms.update_submission(
-**form_submission_data:** `typing.Optional[typing.Dict[str, typing.Any]]` — An existing **hidden field** defined on the form schema, and the corresponding value to set +**request:** `Webhook`
@@ -4106,8 +4258,7 @@ client.forms.update_submission(
-## Products -
client.products.list(...) -> ProductAndSkUsList +
client.webhooks.get(...) -> Webhook
@@ -4119,12 +4270,9 @@ client.forms.update_submission(
-Retrieve all products for a site. - -Use `limit` and `offset` to page through all products with subsequent requests. All SKUs for each product -will also be fetched and returned. The `limit`, `offset` and `total` values represent Products only and do not include any SKUs. +Get a specific Webhook instance -Required scope | `ecommerce:read` +Required scope: `sites:read`
@@ -4147,10 +4295,8 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.products.list( - site_id="580e63e98c9a982ac9b8b741", - offset=1, - limit=1, +client.webhooks.get( + webhook_id="580e64008c9a982ac9b8b754", ) ``` @@ -4167,23 +4313,7 @@ client.products.list(
-**site_id:** `str` — Unique identifier for a Site - -
-
- -
-
- -**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100) +**webhook_id:** `str` — Unique identifier for a Webhook
@@ -4203,7 +4333,7 @@ client.products.list(
-
client.products.create(...) -> ProductAndSkUs +
client.webhooks.delete(...)
@@ -4215,16 +4345,9 @@ client.products.list(
-Create a new ecommerce product and defaultSKU. A product, at minimum, must have a single SKU. - -To create a product with multiple SKUs: - - First, create a list of `sku-properties`, also known as [product options](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants). For example, a T-shirt product may have a "color" `sku-property`, with a list of enum values: red, yellow, and blue, another `sku-property` may be "size", with a list of enum values: small, medium, and large. - - Once, a product is created with a list of `sku-properties`, Webflow will create a **default SKU**, which is always a combination of the first `enum` values of each `sku-property`. (e.g. Small - Red - T-Shirt) - - After creation, you can create additional SKUs for the product, using the [Create SKUs endpoint.](/data/reference/ecommerce/products/create-sku) - -Upon creation, the default product type will be `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer. +Remove a Webhook -Required scope | `ecommerce:write` +Required scope: `sites:read`
@@ -4239,81 +4362,16 @@ Required scope | `ecommerce:write`
```python -from webflow import Webflow, ProductFieldData, SkuPropertyList, SkuPropertyListEnumItem, SkuFieldData, SkuFieldDataPrice +from webflow import Webflow from webflow.environment import WebflowEnvironment -from webflow.products import ProductSkuCreateProduct, ProductSkuCreateSku client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.products.create( - site_id="580e63e98c9a982ac9b8b741", - publish_status="staging", - product=ProductSkuCreateProduct( - field_data=ProductFieldData( - name="Colorful T-shirt", - slug="colorful-t-shirt", - description="Our best-selling t-shirt available in multiple colors and sizes", - sku_properties=[ - SkuPropertyList( - id="color", - name="Color", - enum=[ - SkuPropertyListEnumItem( - id="red", - name="Red", - slug="red", - ), - SkuPropertyListEnumItem( - id="yellow", - name="Yellow", - slug="yellow", - ), - SkuPropertyListEnumItem( - id="blue", - name="Blue", - slug="blue", - ) - ], - ), - SkuPropertyList( - id="size", - name="Size", - enum=[ - SkuPropertyListEnumItem( - id="small", - name="Small", - slug="small", - ), - SkuPropertyListEnumItem( - id="medium", - name="Medium", - slug="medium", - ), - SkuPropertyListEnumItem( - id="large", - name="Large", - slug="large", - ) - ], - ) - ], - ), - ), - sku=ProductSkuCreateSku( - field_data=SkuFieldData( - name="Colorful T-shirt - Red Small", - slug="colorful-t-shirt-red-small", - price=SkuFieldDataPrice( - value=2499, - unit="USD", - currency="USD", - ), - main_image="https://rocketamp-sample-store.myshopify.com/cdn/shop/products/Gildan_2000_Antique_Cherry_Red_Front_1024x1024.jpg?v=1527232987", - ), - ), +client.webhooks.delete( + webhook_id="580e64008c9a982ac9b8b754", ) ``` @@ -4330,31 +4388,7 @@ client.products.create(
-**site_id:** `str` — Unique identifier for a Site - -
-
- -
-
- -**product:** `ProductSkuCreateProduct` - -
-
- -
-
- -**sku:** `ProductSkuCreateSku` - -
-
- -
-
- -**publish_status:** `typing.Optional[PublishStatus]` +**webhook_id:** `str` — Unique identifier for a Webhook
@@ -4374,7 +4408,8 @@ client.products.create(
-
client.products.get(...) -> ProductAndSkUs +## Forms +
client.forms.list(...) -> FormList
@@ -4386,10 +4421,9 @@ client.products.create(
-Retrieve a single product by its ID. All of its SKUs will also be -retrieved. +List forms for a given site. -Required scope | `ecommerce:read` +Required scope | `forms:read`
@@ -4412,9 +4446,10 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.products.get( +client.forms.list( site_id="580e63e98c9a982ac9b8b741", - product_id="580e63fc8c9a982ac9b8b745", + limit=1, + offset=1, ) ``` @@ -4439,7 +4474,15 @@ client.products.get(
-**product_id:** `str` — Unique identifier for a Product +**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
@@ -4459,7 +4502,7 @@ client.products.get(
-
client.products.update(...) -> Product +
client.forms.get(...) -> Form
@@ -4471,11 +4514,9 @@ client.products.get(
-Update an existing Product. - -Updating an existing Product will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer. +Get information about a given form. -Required scope | `ecommerce:write` +Required scope | `forms:read`
@@ -4498,9 +4539,8 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.products.update( - site_id="580e63e98c9a982ac9b8b741", - product_id="580e63fc8c9a982ac9b8b745", +client.forms.get( + form_id="580e63e98c9a982ac9b8b741", ) ``` @@ -4517,7 +4557,2045 @@ client.products.update(
-**site_id:** `str` — Unique identifier for a Site +**form_id:** `str` — Unique identifier for a Form + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ +
+ + + + +
+ +
client.forms.list_submissions(...) -> FormSubmissionList +
+
+ +#### 📝 Description + +
+
+ +
+
+ +List form submissions for a given form + + + When a form is used in a component definition, each instance of the form is considered a unique form. + + To get a combined list of submissions for a form that appears across multiple component instances, use the [List Form Submissions by Site](/data/reference/forms/form-submissions/list-submissions-by-site) endpoint. + + +Required scope | `forms:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.forms.list_submissions( + form_id="580e63e98c9a982ac9b8b741", + offset=1, + limit=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**form_id:** `str` — Unique identifier for a Form + +
+
+ +
+
+ +**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.forms.get_submission(...) -> FormSubmission +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get information about a given form submissio. + +Required scope | `forms:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.forms.get_submission( + form_submission_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**form_submission_id:** `str` — Unique identifier for a Form Submission + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.forms.delete_submission(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Delete a form submission + + +Required scope | `forms:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.forms.delete_submission( + form_submission_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**form_submission_id:** `str` — Unique identifier for a Form Submission + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.forms.update_submission(...) -> FormSubmission +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Update hidden fields on a form submission + +Required scope | `forms:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.forms.update_submission( + form_submission_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**form_submission_id:** `str` — Unique identifier for a Form Submission + +
+
+ +
+
+ +**form_submission_data:** `typing.Optional[typing.Dict[str, typing.Any]]` — An existing **hidden field** defined on the form schema, and the corresponding value to set + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +## Products +
client.products.list(...) -> ProductAndSkUsList +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve all products for a site. + +Use `limit` and `offset` to page through all products with subsequent requests. All SKUs for each product +will also be fetched and returned. The `limit`, `offset` and `total` values represent Products only and do not include any SKUs. + +Required scope | `ecommerce:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.products.list( + site_id="580e63e98c9a982ac9b8b741", + offset=1, + limit=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.products.create(...) -> ProductAndSkUs +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Create a new ecommerce product and defaultSKU. A product, at minimum, must have a single SKU. + +To create a product with multiple SKUs: + - First, create a list of `sku-properties`, also known as [product options](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants). For example, a T-shirt product may have a "color" `sku-property`, with a list of enum values: red, yellow, and blue, another `sku-property` may be "size", with a list of enum values: small, medium, and large. + - Once, a product is created with a list of `sku-properties`, Webflow will create a **default SKU**, which is always a combination of the first `enum` values of each `sku-property`. (e.g. Small - Red - T-Shirt) + - After creation, you can create additional SKUs for the product, using the [Create SKUs endpoint.](/data/reference/ecommerce/products/create-sku) + +Upon creation, the default product type will be `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer. + +Required scope | `ecommerce:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow, ProductFieldData, SkuPropertyList, SkuPropertyListEnumItem, SkuFieldData, SkuFieldDataPrice +from webflow.environment import WebflowEnvironment +from webflow.products import ProductSkuCreateProduct, ProductSkuCreateSku + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.products.create( + site_id="580e63e98c9a982ac9b8b741", + publish_status="staging", + product=ProductSkuCreateProduct( + field_data=ProductFieldData( + name="Colorful T-shirt", + slug="colorful-t-shirt", + description="Our best-selling t-shirt available in multiple colors and sizes", + sku_properties=[ + SkuPropertyList( + id="color", + name="Color", + enum=[ + SkuPropertyListEnumItem( + id="red", + name="Red", + slug="red", + ), + SkuPropertyListEnumItem( + id="yellow", + name="Yellow", + slug="yellow", + ), + SkuPropertyListEnumItem( + id="blue", + name="Blue", + slug="blue", + ) + ], + ), + SkuPropertyList( + id="size", + name="Size", + enum=[ + SkuPropertyListEnumItem( + id="small", + name="Small", + slug="small", + ), + SkuPropertyListEnumItem( + id="medium", + name="Medium", + slug="medium", + ), + SkuPropertyListEnumItem( + id="large", + name="Large", + slug="large", + ) + ], + ) + ], + ), + ), + sku=ProductSkuCreateSku( + field_data=SkuFieldData( + name="Colorful T-shirt - Red Small", + slug="colorful-t-shirt-red-small", + price=SkuFieldDataPrice( + value=2499, + unit="USD", + currency="USD", + ), + main_image="https://rocketamp-sample-store.myshopify.com/cdn/shop/products/Gildan_2000_Antique_Cherry_Red_Front_1024x1024.jpg?v=1527232987", + ), + ), +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**product:** `ProductSkuCreateProduct` + +
+
+ +
+
+ +**sku:** `ProductSkuCreateSku` + +
+
+ +
+
+ +**publish_status:** `typing.Optional[PublishStatus]` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.products.get(...) -> ProductAndSkUs +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve a single product by its ID. All of its SKUs will also be +retrieved. + +Required scope | `ecommerce:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.products.get( + site_id="580e63e98c9a982ac9b8b741", + product_id="580e63fc8c9a982ac9b8b745", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**product_id:** `str` — Unique identifier for a Product + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.products.update(...) -> Product +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Update an existing Product. + +Updating an existing Product will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer. + +Required scope | `ecommerce:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.products.update( + site_id="580e63e98c9a982ac9b8b741", + product_id="580e63fc8c9a982ac9b8b745", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**product_id:** `str` — Unique identifier for a Product + +
+
+ +
+
+ +**publish_status:** `typing.Optional[PublishStatus]` + +
+
+ +
+
+ +**product:** `typing.Optional[Product]` + +
+
+ +
+
+ +**sku:** `typing.Optional[Sku]` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.products.create_sku(...) -> ProductsCreateSkuResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Create additional SKUs to manage every [option and variant of your Product.](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants) + +Creating SKUs through the API will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer. + +Required scope | `ecommerce:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow, Sku, SkuFieldData, SkuFieldDataPrice +from webflow.environment import WebflowEnvironment +import datetime + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.products.create_sku( + site_id="580e63e98c9a982ac9b8b741", + product_id="580e63fc8c9a982ac9b8b745", + skus=[ + Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), + last_updated=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), + created_on=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499, + unit="USD", + currency="USD", + ), + ), + ) + ], +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**product_id:** `str` — Unique identifier for a Product + +
+
+ +
+
+ +**skus:** `typing.List[Sku]` — An array of the SKU data your are adding + +
+
+ +
+
+ +**publish_status:** `typing.Optional[PublishStatus]` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.products.update_sku(...) -> Sku +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Update a specified SKU. + +Updating an existing SKU will set the Product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer. + +Required scope | `ecommerce:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow, Sku, SkuFieldData, SkuFieldDataPrice +from webflow.environment import WebflowEnvironment +import datetime + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.products.update_sku( + site_id="580e63e98c9a982ac9b8b741", + product_id="580e63fc8c9a982ac9b8b745", + sku_id="5e8518516e147040726cc415", + sku=Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), + last_updated=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), + created_on=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499, + unit="USD", + currency="USD", + ), + ), + ), +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**product_id:** `str` — Unique identifier for a Product + +
+
+ +
+
+ +**sku_id:** `str` — Unique identifier for a SKU + +
+
+ +
+
+ +**sku:** `Sku` + +
+
+ +
+
+ +**publish_status:** `typing.Optional[PublishStatus]` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +## Orders +
client.orders.list(...) -> OrderList +
+
+ +#### 📝 Description + +
+
+ +
+
+ +List all orders created for a given site. + +Required scope | `ecommerce:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.orders.list( + site_id="580e63e98c9a982ac9b8b741", + status="pending", + offset=1, + limit=1, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**status:** `typing.Optional[OrdersListRequestStatus]` — Filter the orders by status + +
+
+ +
+
+ +**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.orders.get(...) -> Order +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve a single product by its ID. All of its SKUs will also be +retrieved. + +Required scope | `ecommerce:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.orders.get( + site_id="580e63e98c9a982ac9b8b741", + order_id="5e8518516e147040726cc415", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**order_id:** `str` — Unique identifier for an Order + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.orders.update(...) -> Order +
+
+ +#### 📝 Description + +
+
+ +
+
+ +This API lets you update the fields, `comment`, `shippingProvider`, +and/or `shippingTracking` for a given order. All three fields can be +updated simultaneously or independently. + +Required scope | `ecommerce:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.orders.update( + site_id="580e63e98c9a982ac9b8b741", + order_id="5e8518516e147040726cc415", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**order_id:** `str` — Unique identifier for an Order + +
+
+ +
+
+ +**comment:** `typing.Optional[str]` — Arbitrary data for your records + +
+
+ +
+
+ +**shipping_provider:** `typing.Optional[str]` — Company or method used to ship order + +
+
+ +
+
+ +**shipping_tracking:** `typing.Optional[str]` — Tracking number for order shipment + +
+
+ +
+
+ +**shipping_tracking_url:** `typing.Optional[str]` — URL to track order shipment + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.orders.update_fulfill(...) -> Order +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Updates an order's status to fulfilled + +Required scope | `ecommerce:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.orders.update_fulfill( + site_id="580e63e98c9a982ac9b8b741", + order_id="5e8518516e147040726cc415", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**order_id:** `str` — Unique identifier for an Order + +
+
+ +
+
+ +**send_order_fulfilled_email:** `typing.Optional[bool]` — Whether or not the Order Fulfilled email should be sent + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.orders.update_unfulfill(...) -> Order +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Updates an order's status to unfulfilled + +Required scope | `ecommerce:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.orders.update_unfulfill( + site_id="580e63e98c9a982ac9b8b741", + order_id="5e8518516e147040726cc415", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**order_id:** `str` — Unique identifier for an Order + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.orders.refund(...) -> Order +
+
+ +#### 📝 Description + +
+
+ +
+
+ +This API will reverse a Stripe charge and refund an order back to a +customer. It will also set the order's status to `refunded`. + +Required scope | `ecommerce:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.orders.refund( + site_id="580e63e98c9a982ac9b8b741", + order_id="5e8518516e147040726cc415", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**order_id:** `str` — Unique identifier for an Order + +
+
+ +
+
+ +**reason:** `typing.Optional[OrdersRefundRequestReason]` — The reason for the refund + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +## Inventory +
client.inventory.list(...) -> InventoryItem +
+
+ +#### 📝 Description + +
+
+ +
+
+ +List the current inventory levels for a particular SKU item. + +Required scope | `ecommerce:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.inventory.list( + sku_collection_id="6377a7c4b7a79608c34a46f7", + sku_id="5e8518516e147040726cc415", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**sku_collection_id:** `str` — Unique identifier for a SKU collection. Use the List Collections API to find this ID. + +
+
+ +
+
+ +**sku_id:** `str` — Unique identifier for a SKU + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.inventory.update(...) -> InventoryItem +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Updates the current inventory levels for a particular SKU item. + +Updates may be given in one or two methods, absolutely or incrementally. +- Absolute updates are done by setting `quantity` directly. +- Incremental updates are by specifying the inventory delta in `updateQuantity` which is then added to the `quantity` stored on the server. + +Required scope | `ecommerce:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.inventory.update( + sku_collection_id="6377a7c4b7a79608c34a46f7", + sku_id="5e8518516e147040726cc415", + inventory_type="infinite", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**sku_collection_id:** `str` — Unique identifier for a SKU collection. Use the List Collections API to find this ID. + +
+
+ +
+
+ +**sku_id:** `str` — Unique identifier for a SKU + +
+
+ +
+
+ +**inventory_type:** `InventoryUpdateRequestInventoryType` — infinite or finite + +
+
+ +
+
+ +**update_quantity:** `typing.Optional[float]` — Adds this quantity to currently store quantity. Can be negative. + +
+
+ +
+
+ +**quantity:** `typing.Optional[float]` — Immediately sets quantity to this value. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +## Ecommerce +
client.ecommerce.get_settings(...) -> EcommerceSettings +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve ecommerce settings for a site. + +Required scope | `ecommerce:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.ecommerce.get_settings( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +## Analyze Reports +
client.analyze.reports.traffic(...) -> TrafficResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Returns a daily time series of a single metric — sessions, users, or pageviews — over a time window. + +Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + +This endpoint requires a workspace with the Analyze add-on. + +Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + +Required scope | `sites:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment +import datetime + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.analyze.reports.traffic( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat("2026-04-01T00:00:00+00:00"), + end_time=datetime.datetime.fromisoformat("2026-04-08T00:00:00+00:00"), + metric_scope="session", + bucket_time_zone="America/New_York", + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**start_time:** `datetime.datetime` — Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + +
+
+ +
+
+ +**end_time:** `datetime.datetime` — Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + +
+
+ +
+
+ +**metric_scope:** `TrafficMetricScope` — The unit each `count` data point is measured in. + +
+
+ +
+
+ +**bucket_time_zone:** `AnalyzeBucketTimeZone` — IANA time zone used to align daily bucket boundaries. + +
+
+ +
+
+ +**device_type:** `typing.Optional[ReportsTrafficRequestDeviceType]` — Restrict the report to a single device type. + +
+
+ +
+
+ +**country:** `typing.Optional[str]` — Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase).
@@ -4525,7 +6603,7 @@ client.products.update(
-**product_id:** `str` — Unique identifier for a Product +**page_path:** `typing.Optional[str]` — Restrict the report to a single page path.
@@ -4533,7 +6611,7 @@ client.products.update(
-**publish_status:** `typing.Optional[PublishStatus]` +**traffic_source:** `typing.Optional[str]` — Restrict the report to a single traffic source code (for example, `SO` for Organic Search).
@@ -4541,7 +6619,7 @@ client.products.update(
-**product:** `typing.Optional[Product]` +**referrer:** `typing.Optional[str]` — Restrict the report to a single referrer domain.
@@ -4549,7 +6627,42 @@ client.products.update(
-**sku:** `typing.Optional[Sku]` +**browser:** `typing.Optional[str]` — Restrict the report to a single browser. + +
+
+ +
+
+ +**utm_campaign:** `typing.Optional[str]` — Restrict the report to a single `utm_campaign` value. + +
+
+ +
+
+ +**utm_medium:** `typing.Optional[str]` — Restrict the report to a single `utm_medium` value. + +
+
+ +
+
+ +**utm_source:** `typing.Optional[str]` — Restrict the report to a single `utm_source` value. + +
+
+ +
+
+ +**filter:** `typing.Optional[TrafficFilter]` + +Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). +Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TrafficFilter` schema for the full list of supported dimensions.
@@ -4569,7 +6682,7 @@ client.products.update(
-
client.products.create_sku(...) -> ProductsCreateSkuResponse +
client.analyze.reports.top_pages(...) -> TopPagesResponse
@@ -4581,11 +6694,17 @@ client.products.update(
-Create additional SKUs to manage every [option and variant of your Product.](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants) +Returns the most-visited pages over a time window, ranked by `sortBy` (sessions, users, or pageviews). -Creating SKUs through the API will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer. +Each row carries all three scope counts; `sortBy` only governs ordering. Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. -Required scope | `ecommerce:write` +Set `timeseries[bucketTimeZone]` to attach a daily pageview `timeseries` to each row. Bucket counts are always pageviews regardless of `sortBy` — row-level counts honor the requested sort; the timeseries does not. + +This endpoint requires a workspace with the Analyze add-on. + +Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + +Required scope | `sites:read`
@@ -4600,7 +6719,7 @@ Required scope | `ecommerce:write`
```python -from webflow import Webflow, Sku, SkuFieldData, SkuFieldDataPrice +from webflow import Webflow from webflow.environment import WebflowEnvironment import datetime @@ -4609,27 +6728,21 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.products.create_sku( +client.analyze.reports.top_pages( site_id="580e63e98c9a982ac9b8b741", - product_id="580e63fc8c9a982ac9b8b745", - skus=[ - Sku( - id="66072fb71b89448912e2681c", - cms_locale_id="653ad57de882f528b32e810e", - last_published=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), - last_updated=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), - created_on=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), - field_data=SkuFieldData( - name="Colorful T-shirt - Default", - slug="colorful-t-shirt-default", - price=SkuFieldDataPrice( - value=2499, - unit="USD", - currency="USD", - ), - ), - ) - ], + start_time=datetime.datetime.fromisoformat("2026-04-01T00:00:00+00:00"), + end_time=datetime.datetime.fromisoformat("2026-04-08T00:00:00+00:00"), + sort_by="session", + limit=1, + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", ) ``` @@ -4654,7 +6767,7 @@ client.products.create_sku(
-**product_id:** `str` — Unique identifier for a Product +**start_time:** `datetime.datetime` — Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`.
@@ -4662,7 +6775,7 @@ client.products.create_sku(
-**skus:** `typing.List[Sku]` — An array of the SKU data your are adding +**end_time:** `datetime.datetime` — Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it.
@@ -4670,7 +6783,106 @@ client.products.create_sku(
-**publish_status:** `typing.Optional[PublishStatus]` +**sort_by:** `typing.Optional[TopPagesSortBy]` — Metric used to rank rows in the response, descending. Defaults to `session`. + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` — Maximum number of rows to return. Defaults to `25`, up to a maximum of `250`. + +
+
+ +
+
+ +**timeseries:** `typing.Optional[AnalyzeDailyTimeseriesQuery]` — Include a daily pageview `timeseries` for each row, bucketed in the supplied IANA time zone. Omit this parameter to return ranked rows without per-page timeseries data. + +
+
+ +
+
+ +**device_type:** `typing.Optional[ReportsTopPagesRequestDeviceType]` — Restrict the report to a single device type. + +
+
+ +
+
+ +**country:** `typing.Optional[str]` — Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + +
+
+ +
+
+ +**page_path:** `typing.Optional[str]` — Restrict the report to a single page path. + +
+
+ +
+
+ +**traffic_source:** `typing.Optional[str]` — Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + +
+
+ +
+
+ +**referrer:** `typing.Optional[str]` — Restrict the report to a single referrer domain. + +
+
+ +
+
+ +**browser:** `typing.Optional[str]` — Restrict the report to a single browser. + +
+
+ +
+
+ +**utm_campaign:** `typing.Optional[str]` — Restrict the report to a single `utm_campaign` value. + +
+
+ +
+
+ +**utm_medium:** `typing.Optional[str]` — Restrict the report to a single `utm_medium` value. + +
+
+ +
+
+ +**utm_source:** `typing.Optional[str]` — Restrict the report to a single `utm_source` value. + +
+
+ +
+
+ +**filter:** `typing.Optional[TopPagesFilter]` + +Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). +Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopPagesFilter` schema for the full list of supported dimensions.
@@ -4690,7 +6902,7 @@ client.products.create_sku(
-
client.products.update_sku(...) -> Sku +
client.analyze.reports.top_dimensions(...) -> TopDimensionsResponse
@@ -4702,11 +6914,15 @@ client.products.create_sku(
-Update a specified SKU. +Returns the top values within a chosen `dimension` — top countries, top traffic sources, top campaigns, top audiences, and so on — over a time window, ranked by sessions or users. -Updating an existing SKU will set the Product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer. +Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. -Required scope | `ecommerce:write` +This endpoint requires a workspace with the Analyze add-on. + +Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + +Required scope | `sites:read`
@@ -4721,7 +6937,7 @@ Required scope | `ecommerce:write`
```python -from webflow import Webflow, Sku, SkuFieldData, SkuFieldDataPrice +from webflow import Webflow from webflow.environment import WebflowEnvironment import datetime @@ -4730,43 +6946,127 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.products.update_sku( +client.analyze.reports.top_dimensions( site_id="580e63e98c9a982ac9b8b741", - product_id="580e63fc8c9a982ac9b8b745", - sku_id="5e8518516e147040726cc415", - sku=Sku( - id="66072fb71b89448912e2681c", - cms_locale_id="653ad57de882f528b32e810e", - last_published=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), - last_updated=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), - created_on=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"), - field_data=SkuFieldData( - name="Colorful T-shirt - Default", - slug="colorful-t-shirt-default", - price=SkuFieldDataPrice( - value=2499, - unit="USD", - currency="USD", - ), - ), - ), + start_time=datetime.datetime.fromisoformat("2026-04-01T00:00:00+00:00"), + end_time=datetime.datetime.fromisoformat("2026-04-08T00:00:00+00:00"), + dimension="country", + metric_scope="session", + limit=1, + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", ) -``` +``` +
+
+ + + +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**start_time:** `datetime.datetime` — Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + +
+
+ +
+
+ +**end_time:** `datetime.datetime` — Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + +
+
+ +
+
+ +**dimension:** `TopDimensionsDimension` — The dimension whose top values are ranked. See `TopDimensionsDimension` for the supported values. + +
+
+ +
+
+ +**metric_scope:** `TopDimensionsMetricScope` — The unit each row's `count` is measured in — sessions or users. + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` — Maximum number of rows to return. Defaults to `25`, up to a maximum of `100`. + +
+
+ +
+
+ +**device_type:** `typing.Optional[ReportsTopDimensionsRequestDeviceType]` — Restrict the report to a single device type. + +
+
+ +
+
+ +**country:** `typing.Optional[str]` — Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + +
+
+ +
+
+ +**page_path:** `typing.Optional[str]` — Restrict the report to a single page path. +
+ +
+
+ +**traffic_source:** `typing.Optional[str]` — Restrict the report to a single traffic source code (for example, `SO` for Organic Search). +
-#### ⚙️ Parameters -
+**referrer:** `typing.Optional[str]` — Restrict the report to a single referrer domain. + +
+
+
-**site_id:** `str` — Unique identifier for a Site +**browser:** `typing.Optional[str]` — Restrict the report to a single browser.
@@ -4774,7 +7074,7 @@ client.products.update_sku(
-**product_id:** `str` — Unique identifier for a Product +**utm_campaign:** `typing.Optional[str]` — Restrict the report to a single `utm_campaign` value.
@@ -4782,7 +7082,7 @@ client.products.update_sku(
-**sku_id:** `str` — Unique identifier for a SKU +**utm_medium:** `typing.Optional[str]` — Restrict the report to a single `utm_medium` value.
@@ -4790,7 +7090,7 @@ client.products.update_sku(
-**sku:** `Sku` +**utm_source:** `typing.Optional[str]` — Restrict the report to a single `utm_source` value.
@@ -4798,7 +7098,10 @@ client.products.update_sku(
-**publish_status:** `typing.Optional[PublishStatus]` +**filter:** `typing.Optional[TopDimensionsFilter]` + +Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). +Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopDimensionsFilter` schema for the full list of supported dimensions.
@@ -4818,8 +7121,7 @@ client.products.update_sku(
-## Orders -
client.orders.list(...) -> OrderList +
client.analyze.reports.top_events(...) -> TopEventsResponse
@@ -4831,9 +7133,17 @@ client.products.update_sku(
-List all orders created for a given site. +Returns the top events over a time window, ranked by how often they occurred. -Required scope | `ecommerce:read` +Events are counted individually, not rolled up into sessions, users, or pageviews — so this report has no `metricScope`. Each row's `count` is how many times the event occurred. Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + +Set `timeseries[bucketTimeZone]` to attach a daily event count `timeseries` to each row. + +This endpoint requires a workspace with the Analyze add-on. + +Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + +Required scope | `sites:read`
@@ -4850,17 +7160,26 @@ Required scope | `ecommerce:read` ```python from webflow import Webflow from webflow.environment import WebflowEnvironment +import datetime client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.orders.list( +client.analyze.reports.top_events( site_id="580e63e98c9a982ac9b8b741", - status="pending", - offset=1, + start_time=datetime.datetime.fromisoformat("2026-04-01T00:00:00+00:00"), + end_time=datetime.datetime.fromisoformat("2026-04-08T00:00:00+00:00"), limit=1, + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", ) ``` @@ -4885,7 +7204,7 @@ client.orders.list(
-**status:** `typing.Optional[OrdersListRequestStatus]` — Filter the orders by status +**start_time:** `datetime.datetime` — Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`.
@@ -4893,7 +7212,7 @@ client.orders.list(
-**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records +**end_time:** `datetime.datetime` — Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it.
@@ -4901,7 +7220,7 @@ client.orders.list(
-**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100) +**limit:** `typing.Optional[int]` — Maximum number of rows to return. Defaults to `25`, up to a maximum of `250`.
@@ -4909,76 +7228,71 @@ client.orders.list(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**timeseries:** `typing.Optional[AnalyzeDailyTimeseriesQuery]` — Include a daily event count `timeseries` for each row, bucketed in the supplied IANA time zone. Omit this parameter to return ranked rows without per-event timeseries data.
- -
+
+
+**device_type:** `typing.Optional[ReportsTopEventsRequestDeviceType]` — Restrict the report to a single device type. +
-
-
client.orders.get(...) -> Order
-#### 📝 Description +**country:** `typing.Optional[str]` — Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + +
+
+**page_path:** `typing.Optional[str]` — Restrict the report to a single page path. + +
+
+
-Retrieve a single product by its ID. All of its SKUs will also be -retrieved. - -Required scope | `ecommerce:read` -
-
+**traffic_source:** `typing.Optional[str]` — Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + -#### 🔌 Usage -
+**browser:** `typing.Optional[str]` — Restrict the report to a single browser. + +
+
+
-```python -from webflow import Webflow -from webflow.environment import WebflowEnvironment - -client = Webflow( - access_token="", - environment=WebflowEnvironment.DATA_API, -) - -client.orders.get( - site_id="580e63e98c9a982ac9b8b741", - order_id="5e8518516e147040726cc415", -) - -``` -
-
+**utm_campaign:** `typing.Optional[str]` — Restrict the report to a single `utm_campaign` value. + -#### ⚙️ Parameters -
+**utm_medium:** `typing.Optional[str]` — Restrict the report to a single `utm_medium` value. + +
+
+
-**site_id:** `str` — Unique identifier for a Site +**utm_source:** `typing.Optional[str]` — Restrict the report to a single `utm_source` value.
@@ -4986,7 +7300,10 @@ client.orders.get(
-**order_id:** `str` — Unique identifier for an Order +**filter:** `typing.Optional[TopEventsFilter]` + +Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). +Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopEventsFilter` schema for the full list of supported dimensions.
@@ -5006,7 +7323,7 @@ client.orders.get(
-
client.orders.update(...) -> Order +
client.analyze.reports.time_on_page(...) -> TimeOnPageResponse
@@ -5018,11 +7335,15 @@ client.orders.get(
-This API lets you update the fields, `comment`, `shippingProvider`, -and/or `shippingTracking` for a given order. All three fields can be -updated simultaneously or independently. +Returns the average time on page over a time window — as a single aggregate value, or bucketed by day or week when `timeseries` is supplied. -Required scope | `ecommerce:write` +Choose how the average is computed with `metricScope` (per session, user, or pageview). Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + +This endpoint requires a workspace with the Analyze add-on. + +Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + +Required scope | `sites:read`
@@ -5039,15 +7360,27 @@ Required scope | `ecommerce:write` ```python from webflow import Webflow from webflow.environment import WebflowEnvironment +import datetime client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.orders.update( +client.analyze.reports.time_on_page( site_id="580e63e98c9a982ac9b8b741", - order_id="5e8518516e147040726cc415", + start_time=datetime.datetime.fromisoformat("2026-04-01T00:00:00+00:00"), + end_time=datetime.datetime.fromisoformat("2026-04-08T00:00:00+00:00"), + metric_scope="session", + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", ) ``` @@ -5072,7 +7405,7 @@ client.orders.update(
-**order_id:** `str` — Unique identifier for an Order +**start_time:** `datetime.datetime` — Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`.
@@ -5080,7 +7413,7 @@ client.orders.update(
-**comment:** `typing.Optional[str]` — Arbitrary data for your records +**end_time:** `datetime.datetime` — Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it.
@@ -5088,7 +7421,7 @@ client.orders.update(
-**shipping_provider:** `typing.Optional[str]` — Company or method used to ship order +**metric_scope:** `TimeOnPageMetricScope` — How the average time on page is computed — per session, user, or pageview.
@@ -5096,7 +7429,7 @@ client.orders.update(
-**shipping_tracking:** `typing.Optional[str]` — Tracking number for order shipment +**timeseries:** `typing.Optional[TimeOnPageTimeseriesQuery]` — Include bucketed average time data using the supplied granularity and IANA time zone. Omit this parameter to return a single aggregate value for the requested window.
@@ -5104,7 +7437,7 @@ client.orders.update(
-**shipping_tracking_url:** `typing.Optional[str]` — URL to track order shipment +**device_type:** `typing.Optional[ReportsTimeOnPageRequestDeviceType]` — Restrict the report to a single device type.
@@ -5112,75 +7445,55 @@ client.orders.update(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**country:** `typing.Optional[str]` — Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase).
- -
+
+
+**page_path:** `typing.Optional[str]` — Restrict the report to a single page path. +
-
-
client.orders.update_fulfill(...) -> Order
-#### 📝 Description - -
-
+**traffic_source:** `typing.Optional[str]` — Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + +
+
-Updates an order's status to fulfilled - -Required scope | `ecommerce:write` -
-
+**referrer:** `typing.Optional[str]` — Restrict the report to a single referrer domain. +
-#### 🔌 Usage -
-
-
- -```python -from webflow import Webflow -from webflow.environment import WebflowEnvironment - -client = Webflow( - access_token="", - environment=WebflowEnvironment.DATA_API, -) - -client.orders.update_fulfill( - site_id="580e63e98c9a982ac9b8b741", - order_id="5e8518516e147040726cc415", -) - -``` -
-
+**browser:** `typing.Optional[str]` — Restrict the report to a single browser. +
-#### ⚙️ Parameters -
+**utm_campaign:** `typing.Optional[str]` — Restrict the report to a single `utm_campaign` value. + +
+
+
-**site_id:** `str` — Unique identifier for a Site +**utm_medium:** `typing.Optional[str]` — Restrict the report to a single `utm_medium` value.
@@ -5188,7 +7501,7 @@ client.orders.update_fulfill(
-**order_id:** `str` — Unique identifier for an Order +**utm_source:** `typing.Optional[str]` — Restrict the report to a single `utm_source` value.
@@ -5196,7 +7509,10 @@ client.orders.update_fulfill(
-**send_order_fulfilled_email:** `typing.Optional[bool]` — Whether or not the Order Fulfilled email should be sent +**filter:** `typing.Optional[TimeOnPageFilter]` + +Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). +Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TimeOnPageFilter` schema for the full list of supported dimensions.
@@ -5216,7 +7532,8 @@ client.orders.update_fulfill(
-
client.orders.update_unfulfill(...) -> Order +## Collections Fields +
client.collections.fields.create(...) -> FieldCreate
@@ -5228,9 +7545,13 @@ client.orders.update_fulfill(
-Updates an order's status to unfulfilled +Create a custom field in a collection. -Required scope | `ecommerce:write` +Field validation is currently not available through the API. + +Bulk creation of fields is not supported with this endpoint. To add multiple fields at once, include them when you [create the collection.](/data/v2.0.0/reference/cms/collections/create) + +Required scope | `cms:write`
@@ -5245,7 +7566,7 @@ Required scope | `ecommerce:write`
```python -from webflow import Webflow +from webflow import Webflow, StaticField from webflow.environment import WebflowEnvironment client = Webflow( @@ -5253,9 +7574,16 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.orders.update_unfulfill( - site_id="580e63e98c9a982ac9b8b741", - order_id="5e8518516e147040726cc415", +client.collections.fields.create( + collection_id="580e63fc8c9a982ac9b8b745", + request=StaticField( + id="562ac0395358780a1f5e6fbc", + is_editable=True, + is_required=False, + type="RichText", + display_name="Post Body", + help_text="Add the body of your post here", + ), ) ``` @@ -5272,7 +7600,7 @@ client.orders.update_unfulfill(
-**site_id:** `str` — Unique identifier for a Site +**collection_id:** `str` — Unique identifier for a Collection
@@ -5280,7 +7608,7 @@ client.orders.update_unfulfill(
-**order_id:** `str` — Unique identifier for an Order +**request:** `FieldCreate`
@@ -5300,7 +7628,7 @@ client.orders.update_unfulfill(
-
client.orders.refund(...) -> Order +
client.collections.fields.delete(...)
@@ -5312,10 +7640,9 @@ client.orders.update_unfulfill(
-This API will reverse a Stripe charge and refund an order back to a -customer. It will also set the order's status to `refunded`. +Delete a custom field in a collection. This endpoint does not currently support bulk deletion. -Required scope | `ecommerce:write` +Required scope | `cms:write`
@@ -5338,9 +7665,9 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.orders.refund( - site_id="580e63e98c9a982ac9b8b741", - order_id="5e8518516e147040726cc415", +client.collections.fields.delete( + collection_id="580e63fc8c9a982ac9b8b745", + field_id="580e63fc8c9a982ac9b8b745", ) ``` @@ -5357,15 +7684,7 @@ client.orders.refund(
-**site_id:** `str` — Unique identifier for a Site - -
-
- -
-
- -**order_id:** `str` — Unique identifier for an Order +**collection_id:** `str` — Unique identifier for a Collection
@@ -5373,7 +7692,7 @@ client.orders.refund(
-**reason:** `typing.Optional[OrdersRefundRequestReason]` — The reason for the refund +**field_id:** `str` — Unique identifier for a Field in a collection
@@ -5393,8 +7712,7 @@ client.orders.refund(
-## Inventory -
client.inventory.list(...) -> InventoryItem +
client.collections.fields.update(...) -> Field
@@ -5406,9 +7724,9 @@ client.orders.refund(
-List the current inventory levels for a particular SKU item. +Update a custom field in a collection. -Required scope | `ecommerce:read` +Required scope | `cms:write`
@@ -5422,35 +7740,62 @@ Required scope | `ecommerce:read`
-```python -from webflow import Webflow -from webflow.environment import WebflowEnvironment - -client = Webflow( - access_token="", - environment=WebflowEnvironment.DATA_API, -) - -client.inventory.list( - sku_collection_id="6377a7c4b7a79608c34a46f7", - sku_id="5e8518516e147040726cc415", -) - -``` +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.collections.fields.update( + collection_id="580e63fc8c9a982ac9b8b745", + field_id="580e63fc8c9a982ac9b8b745", + is_required=False, + display_name="Post Body", + help_text="Add the body of your post here", +) + +``` +
+
+ +
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**collection_id:** `str` — Unique identifier for a Collection +
+ +
+
+ +**field_id:** `str` — Unique identifier for a Field in a collection +
-#### ⚙️ Parameters -
+**is_required:** `typing.Optional[bool]` — Define whether a field is required in a collection + +
+
+
-**sku_collection_id:** `str` — Unique identifier for a SKU collection. Use the List Collections API to find this ID. +**display_name:** `typing.Optional[str]` — The name of a field
@@ -5458,7 +7803,7 @@ client.inventory.list(
-**sku_id:** `str` — Unique identifier for a SKU +**help_text:** `typing.Optional[str]` — Additional text to help anyone filling out this field
@@ -5478,7 +7823,8 @@ client.inventory.list(
-
client.inventory.update(...) -> InventoryItem +## Collections Items +
client.collections.items.list_items(...) -> CollectionItemList
@@ -5490,13 +7836,9 @@ client.inventory.list(
-Updates the current inventory levels for a particular SKU item. - -Updates may be given in one or two methods, absolutely or incrementally. -- Absolute updates are done by setting `quantity` directly. -- Incremental updates are by specifying the inventory delta in `updateQuantity` which is then added to the `quantity` stored on the server. +List of all Items within a Collection. -Required scope | `ecommerce:write` +Required scope | `CMS:read`
@@ -5519,10 +7861,15 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.inventory.update( - sku_collection_id="6377a7c4b7a79608c34a46f7", - sku_id="5e8518516e147040726cc415", - inventory_type="infinite", +client.collections.items.list_items( + collection_id="580e63fc8c9a982ac9b8b745", + cms_locale_id="cmsLocaleId", + offset=1, + limit=1, + name="name", + slug="slug", + sort_by="createdOn", + sort_order="asc", ) ``` @@ -5539,7 +7886,7 @@ client.inventory.update(
-**sku_collection_id:** `str` — Unique identifier for a SKU collection. Use the List Collections API to find this ID. +**collection_id:** `str` — Unique identifier for a Collection
@@ -5547,7 +7894,7 @@ client.inventory.update(
-**sku_id:** `str` — Unique identifier for a SKU +**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
@@ -5555,7 +7902,7 @@ client.inventory.update(
-**inventory_type:** `InventoryUpdateRequestInventoryType` — infinite or finite +**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
@@ -5563,7 +7910,7 @@ client.inventory.update(
-**update_quantity:** `typing.Optional[float]` — Adds this quantity to currently store quantity. Can be negative. +**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
@@ -5571,7 +7918,7 @@ client.inventory.update(
-**quantity:** `typing.Optional[float]` — Immediately sets quantity to this value. +**name:** `typing.Optional[str]` — Filter by the exact name of the item(s)
@@ -5579,75 +7926,47 @@ client.inventory.update(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**slug:** `typing.Optional[str]` — Filter by the exact slug of the item
- -
+
+
+**created_on:** `typing.Optional[ItemsListItemsRequestCreatedOn]` — Filter by the creation date of the item(s) +
-
-## Ecommerce -
client.ecommerce.get_settings(...) -> EcommerceSettings
-#### 📝 Description - -
-
+**last_published:** `typing.Optional[ItemsListItemsRequestLastPublished]` — Filter by the last published date of the item(s) + +
+
-Retrieve ecommerce settings for a site. - -Required scope | `ecommerce:read` -
-
+**last_updated:** `typing.Optional[ItemsListItemsRequestLastUpdated]` — Filter by the last updated date of the item(s) +
-#### 🔌 Usage - -
-
-
-```python -from webflow import Webflow -from webflow.environment import WebflowEnvironment - -client = Webflow( - access_token="", - environment=WebflowEnvironment.DATA_API, -) - -client.ecommerce.get_settings( - site_id="580e63e98c9a982ac9b8b741", -) - -``` -
-
+**sort_by:** `typing.Optional[ItemsListItemsRequestSortBy]` — Sort results by the provided value +
-#### ⚙️ Parameters - -
-
-
-**site_id:** `str` — Unique identifier for a Site +**sort_order:** `typing.Optional[ItemsListItemsRequestSortOrder]` — Sorts the results by asc or desc
@@ -5667,8 +7986,7 @@ client.ecommerce.get_settings(
-## Collections Fields -
client.collections.fields.create(...) -> FieldCreate +
client.collections.items.create_item(...) -> CollectionItem
@@ -5680,13 +7998,12 @@ client.ecommerce.get_settings(
-Create a custom field in a collection. +Create Item(s) in a Collection. -Field validation is currently not available through the API. -Bulk creation of fields is not supported with this endpoint. To add multiple fields at once, include them when you [create the collection.](/data/v2.0.0/reference/cms/collections/create) +To create items across multiple locales, please use [this endpoint.](/data/reference/cms/collection-items/staged-items/create-items) -Required scope | `cms:write` +Required scope | `CMS:write`
@@ -5701,7 +8018,7 @@ Required scope | `cms:write`
```python -from webflow import Webflow, StaticField +from webflow import Webflow, CollectionItemPostSingle, CollectionItemPostSingleFieldData from webflow.environment import WebflowEnvironment client = Webflow( @@ -5709,15 +8026,16 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.fields.create( +client.collections.items.create_item( collection_id="580e63fc8c9a982ac9b8b745", - request=StaticField( - id="562ac0395358780a1f5e6fbc", - is_editable=True, - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + skip_invalid_files=True, + request=CollectionItemPostSingle( + is_archived=False, + is_draft=False, + field_data=CollectionItemPostSingleFieldData( + name="The Hitchhiker\'s Guide to the Galaxy", + slug="hitchhikers-guide-to-the-galaxy", + ), ), ) @@ -5743,7 +8061,15 @@ client.collections.fields.create(
-**request:** `FieldCreate` +**request:** `ItemsCreateItemRequestBody` + +
+
+ +
+
+ +**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid.
@@ -5763,7 +8089,7 @@ client.collections.fields.create(
-
client.collections.fields.delete(...) +
client.collections.items.delete_items(...)
@@ -5775,9 +8101,11 @@ client.collections.fields.create(
-Delete a custom field in a collection. This endpoint does not currently support bulk deletion. +Delete Items from a Collection. -Required scope | `cms:write` +Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request. + +Required scope | `CMS:write`
@@ -5794,15 +8122,20 @@ Required scope | `cms:write` ```python from webflow import Webflow from webflow.environment import WebflowEnvironment +from webflow.collections.items import ItemsDeleteItemsRequestItemsItem client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.collections.fields.delete( +client.collections.items.delete_items( collection_id="580e63fc8c9a982ac9b8b745", - field_id="580e63fc8c9a982ac9b8b745", + items=[ + ItemsDeleteItemsRequestItemsItem( + id="580e64008c9a982ac9b8b754", + ) + ], ) ``` @@ -5827,7 +8160,7 @@ client.collections.fields.delete(
-**field_id:** `str` — Unique identifier for a Field in a collection +**items:** `typing.List[ItemsDeleteItemsRequestItemsItem]`
@@ -5847,7 +8180,7 @@ client.collections.fields.delete(
-
client.collections.fields.update(...) -> Field +
client.collections.items.update_items(...) -> ItemsUpdateItemsResponse
@@ -5859,9 +8192,13 @@ client.collections.fields.delete(
-Update a custom field in a collection. +Update a single item or multiple items in a Collection. -Required scope | `cms:write` +The limit for this endpoint is 100 items. + +Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. + +Required scope | `CMS:write`
@@ -5876,7 +8213,7 @@ Required scope | `cms:write`
```python -from webflow import Webflow +from webflow import Webflow, CollectionItemWithIdInput, CollectionItemWithIdInputFieldData from webflow.environment import WebflowEnvironment client = Webflow( @@ -5884,12 +8221,43 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.fields.update( +client.collections.items.update_items( collection_id="580e63fc8c9a982ac9b8b745", - field_id="580e63fc8c9a982ac9b8b745", - is_required=False, - display_name="Post Body", - help_text="Add the body of your post here", + skip_invalid_files=True, + items=[ + CollectionItemWithIdInput( + id="66f6ed9576ddacf3149d5ea6", + cms_locale_id="66f6e966c9e1dc700a857ca5", + field_data=CollectionItemWithIdInputFieldData( + name="Ne Paniquez Pas", + slug="ne-paniquez-pas", + ), + ), + CollectionItemWithIdInput( + id="66f6ed9576ddacf3149d5ea6", + cms_locale_id="66f6e966c9e1dc700a857ca4", + field_data=CollectionItemWithIdInputFieldData( + name="No Entrar en Pánico", + slug="no-entrar-en-panico", + ), + ), + CollectionItemWithIdInput( + id="66f6ed9576ddacf3149d5eaa", + cms_locale_id="66f6e966c9e1dc700a857ca5", + field_data=CollectionItemWithIdInputFieldData( + name="Au Revoir et Merci pour Tous les Poissons", + slug="au-revoir-et-merci", + ), + ), + CollectionItemWithIdInput( + id="66f6ed9576ddacf3149d5eaa", + cms_locale_id="66f6e966c9e1dc700a857ca4", + field_data=CollectionItemWithIdInputFieldData( + name="Hasta Luego y Gracias por Todo el Pescado", + slug="hasta-luego-y-gracias", + ), + ) + ], ) ``` @@ -5914,23 +8282,7 @@ client.collections.fields.update(
-**field_id:** `str` — Unique identifier for a Field in a collection - -
-
- -
-
- -**is_required:** `typing.Optional[bool]` — Define whether a field is required in a collection - -
-
- -
-
- -**display_name:** `typing.Optional[str]` — The name of a field +**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid.
@@ -5938,7 +8290,7 @@ client.collections.fields.update(
-**help_text:** `typing.Optional[str]` — Additional text to help anyone filling out this field +**items:** `typing.Optional[typing.List[CollectionItemWithIdInput]]`
@@ -5957,9 +8309,8 @@ client.collections.fields.update(
- -## Collections Items -
client.collections.items.list_items(...) -> CollectionItemList + +
client.collections.items.list_items_live(...) -> CollectionItemList
@@ -5971,7 +8322,11 @@ client.collections.fields.update(
-List of all Items within a Collection. +List all published items in a collection. + + + Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations. + Required scope | `CMS:read`
@@ -5996,14 +8351,14 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.items.list_items( +client.collections.items.list_items_live( collection_id="580e63fc8c9a982ac9b8b745", cms_locale_id="cmsLocaleId", offset=1, limit=1, name="name", slug="slug", - sort_by="lastPublished", + sort_by="createdOn", sort_order="asc", ) @@ -6069,7 +8424,7 @@ client.collections.items.list_items(
-**last_published:** `typing.Optional[ItemsListItemsRequestLastPublished]` — Filter by the last published date of the item(s) +**created_on:** `typing.Optional[ItemsListItemsLiveRequestCreatedOn]` — Filter by the creation date of the item(s)
@@ -6077,7 +8432,7 @@ client.collections.items.list_items(
-**sort_by:** `typing.Optional[ItemsListItemsRequestSortBy]` — Sort results by the provided value +**last_published:** `typing.Optional[ItemsListItemsLiveRequestLastPublished]` — Filter by the last published date of the item(s)
@@ -6085,7 +8440,23 @@ client.collections.items.list_items(
-**sort_order:** `typing.Optional[ItemsListItemsRequestSortOrder]` — Sorts the results by asc or desc +**last_updated:** `typing.Optional[ItemsListItemsLiveRequestLastUpdated]` — Filter by the last updated date of the item(s) + +
+
+ +
+
+ +**sort_by:** `typing.Optional[ItemsListItemsLiveRequestSortBy]` — Sort results by the provided value + +
+
+ +
+
+ +**sort_order:** `typing.Optional[ItemsListItemsLiveRequestSortOrder]` — Sorts the results by asc or desc
@@ -6105,7 +8476,7 @@ client.collections.items.list_items(
-
client.collections.items.create_item(...) -> CollectionItem +
client.collections.items.create_item_live(...) -> CollectionItem
@@ -6117,10 +8488,11 @@ client.collections.items.list_items(
-Create Item(s) in a Collection. +Create item(s) in a collection that will be immediately published to the live site. -To create items across multiple locales, please use [this endpoint.](/data/reference/cms/collection-items/staged-items/create-items) +To create items across multiple locales, [please use this endpoint.](/data/reference/cms/collection-items/staged-items/create-items) + Required scope | `CMS:write`
@@ -6137,7 +8509,7 @@ Required scope | `CMS:write`
```python -from webflow import Webflow, CollectionItemPostSingle, CollectionItemPostSingleFieldData +from webflow import Webflow, CollectionItem, CollectionItemFieldData from webflow.environment import WebflowEnvironment client = Webflow( @@ -6145,13 +8517,13 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.items.create_item( +client.collections.items.create_item_live( collection_id="580e63fc8c9a982ac9b8b745", skip_invalid_files=True, - request=CollectionItemPostSingle( + request=CollectionItem( is_archived=False, is_draft=False, - field_data=CollectionItemPostSingleFieldData( + field_data=CollectionItemFieldData( name="The Hitchhiker\'s Guide to the Galaxy", slug="hitchhikers-guide-to-the-galaxy", ), @@ -6180,7 +8552,7 @@ client.collections.items.create_item(
-**request:** `ItemsCreateItemRequestBody` +**request:** `ItemsCreateItemLiveRequestBody`
@@ -6208,7 +8580,7 @@ client.collections.items.create_item(
-
client.collections.items.delete_items(...) +
client.collections.items.delete_items_live(...)
@@ -6220,9 +8592,9 @@ client.collections.items.create_item(
-Delete Items from a Collection. +Unpublish up to 100 items from the live site and set the `isDraft` property to `true`. -Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request. +Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write`
@@ -6241,17 +8613,17 @@ Required scope | `CMS:write` ```python from webflow import Webflow from webflow.environment import WebflowEnvironment -from webflow.collections.items import ItemsDeleteItemsRequestItemsItem +from webflow.collections.items import ItemsDeleteItemsLiveRequestItemsItem client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.collections.items.delete_items( +client.collections.items.delete_items_live( collection_id="580e63fc8c9a982ac9b8b745", items=[ - ItemsDeleteItemsRequestItemsItem( + ItemsDeleteItemsLiveRequestItemsItem( id="580e64008c9a982ac9b8b754", ) ], @@ -6279,7 +8651,7 @@ client.collections.items.delete_items(
-**items:** `typing.List[ItemsDeleteItemsRequestItemsItem]` +**items:** `typing.List[ItemsDeleteItemsLiveRequestItemsItem]`
@@ -6299,7 +8671,7 @@ client.collections.items.delete_items(
-
client.collections.items.update_items(...) -> ItemsUpdateItemsResponse +
client.collections.items.update_items_live(...) -> CollectionItemListNoPagination
@@ -6311,9 +8683,7 @@ client.collections.items.delete_items(
-Update a single item or multiple items in a Collection. - -The limit for this endpoint is 100 items. +Update a single published item or multiple published items (up to 100) in a Collection Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. @@ -6340,7 +8710,7 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.items.update_items( +client.collections.items.update_items_live( collection_id="580e63fc8c9a982ac9b8b745", skip_invalid_files=True, items=[ @@ -6429,7 +8799,7 @@ client.collections.items.update_items(
-
client.collections.items.list_items_live(...) -> CollectionItemList +
client.collections.items.create_items(...) -> BulkCollectionItem
@@ -6441,13 +8811,14 @@ client.collections.items.update_items(
-List all published items in a collection. +Create an item or multiple items in a CMS Collection across multiple corresponding locales. - - Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations. - + + - This endpoint can create up to 100 items in a request. + - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale. + -Required scope | `CMS:read` +Required scope | `CMS:write`
@@ -6464,21 +8835,27 @@ Required scope | `CMS:read` ```python from webflow import Webflow from webflow.environment import WebflowEnvironment +from webflow.collections.items import SingleCmsItem client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.collections.items.list_items_live( +client.collections.items.create_items( collection_id="580e63fc8c9a982ac9b8b745", - cms_locale_id="cmsLocaleId", - offset=1, - limit=1, - name="name", - slug="slug", - sort_by="lastPublished", - sort_order="asc", + skip_invalid_files=True, + cms_locale_ids=[ + "66f6e966c9e1dc700a857ca3", + "66f6e966c9e1dc700a857ca4", + "66f6e966c9e1dc700a857ca5" + ], + is_archived=False, + is_draft=False, + field_data=SingleCmsItem( + name="Don’t Panic", + slug="dont-panic", + ), ) ``` @@ -6503,31 +8880,7 @@ client.collections.items.list_items_live(
-**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string. - -
-
- -
-
- -**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100) - -
-
- -
-
- -**name:** `typing.Optional[str]` — Filter by the exact name of the item(s) +**field_data:** `CreateBulkCollectionItemRequestBodyFieldData`
@@ -6535,7 +8888,7 @@ client.collections.items.list_items_live(
-**slug:** `typing.Optional[str]` — Filter by the exact slug of the item +**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid.
@@ -6543,7 +8896,7 @@ client.collections.items.list_items_live(
-**last_published:** `typing.Optional[ItemsListItemsLiveRequestLastPublished]` — Filter by the last published date of the item(s) +**cms_locale_ids:** `typing.Optional[typing.List[str]]` — Array of identifiers for the locales where the item will be created
@@ -6551,7 +8904,7 @@ client.collections.items.list_items_live(
-**sort_by:** `typing.Optional[ItemsListItemsLiveRequestSortBy]` — Sort results by the provided value +**is_archived:** `typing.Optional[bool]` — Indicates whether the item is archived.
@@ -6559,7 +8912,7 @@ client.collections.items.list_items_live(
-**sort_order:** `typing.Optional[ItemsListItemsLiveRequestSortOrder]` — Sorts the results by asc or desc +**is_draft:** `typing.Optional[bool]` — Indicates whether the item is in draft state.
@@ -6579,7 +8932,7 @@ client.collections.items.list_items_live(
-
client.collections.items.create_item_live(...) -> CollectionItem +
client.collections.items.get_item(...) -> CollectionItem
@@ -6591,13 +8944,9 @@ client.collections.items.list_items_live(
-Create item(s) in a collection that will be immediately published to the live site. - - -To create items across multiple locales, [please use this endpoint.](/data/reference/cms/collection-items/staged-items/create-items) - +Get details of a selected Collection Item. -Required scope | `CMS:write` +Required scope | `CMS:read`
@@ -6612,7 +8961,7 @@ Required scope | `CMS:write`
```python -from webflow import Webflow, CollectionItem, CollectionItemFieldData +from webflow import Webflow from webflow.environment import WebflowEnvironment client = Webflow( @@ -6620,17 +8969,10 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.items.create_item_live( +client.collections.items.get_item( collection_id="580e63fc8c9a982ac9b8b745", - skip_invalid_files=True, - request=CollectionItem( - is_archived=False, - is_draft=False, - field_data=CollectionItemFieldData( - name="The Hitchhiker\'s Guide to the Galaxy", - slug="hitchhikers-guide-to-the-galaxy", - ), - ), + item_id="580e64008c9a982ac9b8b754", + cms_locale_id="cmsLocaleId", ) ``` @@ -6655,98 +8997,7 @@ client.collections.items.create_item_live(
-**request:** `ItemsCreateItemLiveRequestBody` - -
-
- -
-
- -**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - - - -
- -
client.collections.items.delete_items_live(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Unpublish up to 100 items from the live site and set the `isDraft` property to `true`. - -Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request. - -Required scope | `CMS:write` -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from webflow import Webflow -from webflow.environment import WebflowEnvironment -from webflow.collections.items import ItemsDeleteItemsLiveRequestItemsItem - -client = Webflow( - access_token="", - environment=WebflowEnvironment.DATA_API, -) - -client.collections.items.delete_items_live( - collection_id="580e63fc8c9a982ac9b8b745", - items=[ - ItemsDeleteItemsLiveRequestItemsItem( - id="580e64008c9a982ac9b8b754", - ) - ], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**collection_id:** `str` — Unique identifier for a Collection +**item_id:** `str` — Unique identifier for an Item
@@ -6754,7 +9005,7 @@ client.collections.items.delete_items_live(
-**items:** `typing.List[ItemsDeleteItemsLiveRequestItemsItem]` +**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
@@ -6774,7 +9025,7 @@ client.collections.items.delete_items_live(
-
client.collections.items.update_items_live(...) -> CollectionItemListNoPagination +
client.collections.items.delete_item(...)
@@ -6786,9 +9037,7 @@ client.collections.items.delete_items_live(
-Update a single published item or multiple published items (up to 100) in a Collection - -Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. +Delete an item from a collection. Required scope | `CMS:write`
@@ -6805,7 +9054,7 @@ Required scope | `CMS:write`
```python -from webflow import Webflow, CollectionItemWithIdInput, CollectionItemWithIdInputFieldData +from webflow import Webflow from webflow.environment import WebflowEnvironment client = Webflow( @@ -6813,43 +9062,10 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.items.update_items_live( +client.collections.items.delete_item( collection_id="580e63fc8c9a982ac9b8b745", - skip_invalid_files=True, - items=[ - CollectionItemWithIdInput( - id="66f6ed9576ddacf3149d5ea6", - cms_locale_id="66f6e966c9e1dc700a857ca5", - field_data=CollectionItemWithIdInputFieldData( - name="Ne Paniquez Pas", - slug="ne-paniquez-pas", - ), - ), - CollectionItemWithIdInput( - id="66f6ed9576ddacf3149d5ea6", - cms_locale_id="66f6e966c9e1dc700a857ca4", - field_data=CollectionItemWithIdInputFieldData( - name="No Entrar en Pánico", - slug="no-entrar-en-panico", - ), - ), - CollectionItemWithIdInput( - id="66f6ed9576ddacf3149d5eaa", - cms_locale_id="66f6e966c9e1dc700a857ca5", - field_data=CollectionItemWithIdInputFieldData( - name="Au Revoir et Merci pour Tous les Poissons", - slug="au-revoir-et-merci", - ), - ), - CollectionItemWithIdInput( - id="66f6ed9576ddacf3149d5eaa", - cms_locale_id="66f6e966c9e1dc700a857ca4", - field_data=CollectionItemWithIdInputFieldData( - name="Hasta Luego y Gracias por Todo el Pescado", - slug="hasta-luego-y-gracias", - ), - ) - ], + item_id="580e64008c9a982ac9b8b754", + cms_locale_id="cmsLocaleId", ) ``` @@ -6874,7 +9090,7 @@ client.collections.items.update_items_live(
-**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid. +**item_id:** `str` — Unique identifier for an Item
@@ -6882,7 +9098,7 @@ client.collections.items.update_items_live(
-**items:** `typing.Optional[typing.List[CollectionItemWithIdInput]]` +**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
@@ -6902,7 +9118,7 @@ client.collections.items.update_items_live(
-
client.collections.items.create_items(...) -> BulkCollectionItem +
client.collections.items.update_item(...) -> CollectionItem
@@ -6914,12 +9130,7 @@ client.collections.items.update_items_live(
-Create an item or multiple items in a CMS Collection across multiple corresponding locales. - - - - This endpoint can create up to 100 items in a request. - - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale. - +Update a selected Item in a Collection. Required scope | `CMS:write`
@@ -6936,28 +9147,23 @@ Required scope | `CMS:write`
```python -from webflow import Webflow +from webflow import Webflow, CollectionItemPatchSingleFieldData from webflow.environment import WebflowEnvironment -from webflow.collections.items import SingleCmsItem client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.collections.items.create_items( +client.collections.items.update_item( collection_id="580e63fc8c9a982ac9b8b745", + item_id="580e64008c9a982ac9b8b754", skip_invalid_files=True, - cms_locale_ids=[ - "66f6e966c9e1dc700a857ca3", - "66f6e966c9e1dc700a857ca4", - "66f6e966c9e1dc700a857ca5" - ], is_archived=False, is_draft=False, - field_data=SingleCmsItem( - name="Don’t Panic", - slug="dont-panic", + field_data=CollectionItemPatchSingleFieldData( + name="The Hitchhiker\'s Guide to the Galaxy", + slug="hitchhikers-guide-to-the-galaxy", ), ) @@ -6983,23 +9189,7 @@ client.collections.items.create_items(
-**field_data:** `CreateBulkCollectionItemRequestBodyFieldData` - -
-
- -
-
- -**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid. - -
-
- -
-
- -**cms_locale_ids:** `typing.Optional[typing.List[str]]` — Array of identifiers for the locales where the item will be created +**item_id:** `str` — Unique identifier for an Item
@@ -7007,7 +9197,7 @@ client.collections.items.create_items(
-**is_archived:** `typing.Optional[bool]` — Indicates whether the item is archived. +**request:** `CollectionItemPatchSingle`
@@ -7015,7 +9205,7 @@ client.collections.items.create_items(
-**is_draft:** `typing.Optional[bool]` — Indicates whether the item is in draft state. +**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid.
@@ -7035,7 +9225,7 @@ client.collections.items.create_items(
-
client.collections.items.get_item(...) -> CollectionItem +
client.collections.items.get_item_live(...) -> CollectionItem
@@ -7047,7 +9237,11 @@ client.collections.items.create_items(
-Get details of a selected Collection Item. +Get details of a selected Collection live Item. + + + Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations. + Required scope | `CMS:read`
@@ -7072,7 +9266,7 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.items.get_item( +client.collections.items.get_item_live( collection_id="580e63fc8c9a982ac9b8b745", item_id="580e64008c9a982ac9b8b754", cms_locale_id="cmsLocaleId", @@ -7128,7 +9322,7 @@ client.collections.items.get_item(
-
client.collections.items.delete_item(...) +
client.collections.items.delete_item_live(...)
@@ -7140,7 +9334,9 @@ client.collections.items.get_item(
-Delete an item from a collection. +Unpublish a live item from the site and set the `isDraft` property to `true`. + +For bulk unpublishing, please use [this endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live) Required scope | `CMS:write`
@@ -7165,7 +9361,7 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.items.delete_item( +client.collections.items.delete_item_live( collection_id="580e63fc8c9a982ac9b8b745", item_id="580e64008c9a982ac9b8b754", cms_locale_id="cmsLocaleId", @@ -7221,7 +9417,7 @@ client.collections.items.delete_item(
-
client.collections.items.update_item(...) -> CollectionItem +
client.collections.items.update_item_live(...) -> CollectionItem
@@ -7233,7 +9429,7 @@ client.collections.items.delete_item(
-Update a selected Item in a Collection. +Update a selected live Item in a Collection. The updates for this Item will be published to the live site. Required scope | `CMS:write`
@@ -7258,7 +9454,7 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.items.update_item( +client.collections.items.update_item_live( collection_id="580e63fc8c9a982ac9b8b745", item_id="580e64008c9a982ac9b8b754", skip_invalid_files=True, @@ -7328,7 +9524,7 @@ client.collections.items.update_item(
-
client.collections.items.get_item_live(...) -> CollectionItem +
client.collections.items.publish_item(...) -> ItemsPublishItemResponse
@@ -7340,13 +9536,9 @@ client.collections.items.update_item(
-Get details of a selected Collection live Item. - - - Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations. - +Publish an item or multiple items. -Required scope | `CMS:read` +Required scope | `cms:write`
@@ -7363,16 +9555,22 @@ Required scope | `CMS:read` ```python from webflow import Webflow from webflow.environment import WebflowEnvironment +from webflow.collections.items import ItemIDs client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.collections.items.get_item_live( +client.collections.items.publish_item( collection_id="580e63fc8c9a982ac9b8b745", - item_id="580e64008c9a982ac9b8b754", - cms_locale_id="cmsLocaleId", + request=ItemIDs( + item_ids=[ + "643fd856d66b6528195ee2ca", + "643fd856d66b6528195ee2cb", + "643fd856d66b6528195ee2cc" + ], + ), ) ``` @@ -7397,7 +9595,7 @@ client.collections.items.get_item_live(
-**item_id:** `str` — Unique identifier for an Item +**request:** `ItemsPublishItemRequest`
@@ -7405,7 +9603,77 @@ client.collections.items.get_item_live(
-**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string. +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ +
+ + + + +
+ +## Pages Scripts +
client.pages.scripts.get_custom_code(...) -> ScriptApplyList +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get all scripts applied to a page. + +Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + +Required scope | `custom_code:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow +from webflow.environment import WebflowEnvironment + +client = Webflow( + access_token="", + environment=WebflowEnvironment.DATA_API, +) + +client.pages.scripts.get_custom_code( + page_id="63c720f9347c2139b248e552", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**page_id:** `str` — Unique identifier for a Page
@@ -7425,7 +9693,7 @@ client.collections.items.get_item_live(
-
client.collections.items.delete_item_live(...) +
client.pages.scripts.upsert_custom_code(...) -> ScriptApplyList
@@ -7437,11 +9705,15 @@ client.collections.items.get_item_live(
-Unpublish a live item from the site and set the `isDraft` property to `true`. +Apply registered scripts to a page. If you have multiple scripts your App needs to apply or maintain on a page, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body. -For bulk unpublishing, please use [this endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live) + + To apply a script to a page, the script must first be registered to a Site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + -Required scope | `CMS:write` +Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + +Required scope | `custom_code:write`
@@ -7456,7 +9728,7 @@ Required scope | `CMS:write`
```python -from webflow import Webflow +from webflow import Webflow, ScriptApply from webflow.environment import WebflowEnvironment client = Webflow( @@ -7464,10 +9736,23 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.items.delete_item_live( - collection_id="580e63fc8c9a982ac9b8b745", - item_id="580e64008c9a982ac9b8b754", - cms_locale_id="cmsLocaleId", +client.pages.scripts.upsert_custom_code( + page_id="63c720f9347c2139b248e552", + scripts=[ + ScriptApply( + id="cms_slider", + location="header", + version="1.0.0", + attributes={ + "my-attribute": "some-value" + }, + ), + ScriptApply( + id="alert", + location="header", + version="0.0.1", + ) + ], ) ``` @@ -7484,15 +9769,7 @@ client.collections.items.delete_item_live(
-**collection_id:** `str` — Unique identifier for a Collection - -
-
- -
-
- -**item_id:** `str` — Unique identifier for an Item +**page_id:** `str` — Unique identifier for a Page
@@ -7500,7 +9777,7 @@ client.collections.items.delete_item_live(
-**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string. +**request:** `ScriptApplyList`
@@ -7520,7 +9797,7 @@ client.collections.items.delete_item_live(
-
client.collections.items.update_item_live(...) -> CollectionItem +
client.pages.scripts.delete_custom_code(...)
@@ -7532,9 +9809,13 @@ client.collections.items.delete_item_live(
-Update a selected live Item in a Collection. The updates for this Item will be published to the live site. +Remove all scripts from a page applied by the App. This endpoint will not remove scripts from the site's registered scripts. -Required scope | `CMS:write` +To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-pages/upsert-custom-code) endpoint. + +Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + +Required scope | `custom_code:write`
@@ -7549,7 +9830,7 @@ Required scope | `CMS:write`
```python -from webflow import Webflow, CollectionItemPatchSingleFieldData +from webflow import Webflow from webflow.environment import WebflowEnvironment client = Webflow( @@ -7557,16 +9838,8 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.collections.items.update_item_live( - collection_id="580e63fc8c9a982ac9b8b745", - item_id="580e64008c9a982ac9b8b754", - skip_invalid_files=True, - is_archived=False, - is_draft=False, - field_data=CollectionItemPatchSingleFieldData( - name="The Hitchhiker\'s Guide to the Galaxy", - slug="hitchhikers-guide-to-the-galaxy", - ), +client.pages.scripts.delete_custom_code( + page_id="63c720f9347c2139b248e552", ) ``` @@ -7583,31 +9856,7 @@ client.collections.items.update_item_live(
-**collection_id:** `str` — Unique identifier for a Collection - -
-
- -
-
- -**item_id:** `str` — Unique identifier for an Item - -
-
- -
-
- -**request:** `CollectionItemPatchSingle` - -
-
- -
-
- -**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid. +**page_id:** `str` — Unique identifier for a Page
@@ -7627,7 +9876,8 @@ client.collections.items.update_item_live(
-
client.collections.items.publish_item(...) -> ItemsPublishItemResponse +## Sites Redirects +
client.sites.redirects.list(...) -> Redirects
@@ -7639,9 +9889,13 @@ client.collections.items.update_item_live(
-Publish an item or multiple items. +Fetch a list of all 301 redirect rules configured for a specific site. -Required scope | `cms:write` +Use this endpoint to review, audit, or manage the redirection rules that control how traffic is rerouted on your site. + +This endpoint requires an Enterprise workspace. + +Required scope: `sites:read`
@@ -7658,22 +9912,14 @@ Required scope | `cms:write` ```python from webflow import Webflow from webflow.environment import WebflowEnvironment -from webflow.collections.items import ItemIDs client = Webflow( access_token="", environment=WebflowEnvironment.DATA_API, ) -client.collections.items.publish_item( - collection_id="580e63fc8c9a982ac9b8b745", - request=ItemIDs( - item_ids=[ - "643fd856d66b6528195ee2ca", - "643fd856d66b6528195ee2cb", - "643fd856d66b6528195ee2cc" - ], - ), +client.sites.redirects.list( + site_id="580e63e98c9a982ac9b8b741", ) ``` @@ -7690,15 +9936,7 @@ client.collections.items.publish_item(
-**collection_id:** `str` — Unique identifier for a Collection - -
-
- -
-
- -**request:** `ItemsPublishItemRequest` +**site_id:** `str` — Unique identifier for a Site
@@ -7718,8 +9956,7 @@ client.collections.items.publish_item(
-## Pages Scripts -
client.pages.scripts.get_custom_code(...) -> ScriptApplyList +
client.sites.redirects.create(...) -> Redirect
@@ -7731,9 +9968,13 @@ client.collections.items.publish_item(
-Get all scripts applied to a page. +Add a new 301 redirection rule to a site. -Required scope | `custom_code:read` +This endpoint allows you to define a source path (`fromUrl`) and its corresponding destination path (`toUrl`), which will dictate how traffic is rerouted on your site. This is useful for managing site changes, restructuring URLs, or handling outdated links. + +This endpoint requires an Enterprise workspace. + +Required scope: `sites:write`
@@ -7756,8 +9997,11 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.pages.scripts.get_custom_code( - page_id="63c720f9347c2139b248e552", +client.sites.redirects.create( + site_id="580e63e98c9a982ac9b8b741", + id="42e1a2b7aa1a13f768a0042a", + from_url="/mostly-harmless", + to_url="/earth", ) ``` @@ -7774,7 +10018,15 @@ client.pages.scripts.get_custom_code(
-**page_id:** `str` — Unique identifier for a Page +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**request:** `Redirect`
@@ -7794,7 +10046,7 @@ client.pages.scripts.get_custom_code(
-
client.pages.scripts.upsert_custom_code(...) -> ScriptApplyList +
client.sites.redirects.delete(...) -> Redirects
@@ -7806,13 +10058,13 @@ client.pages.scripts.get_custom_code(
-Apply registered scripts to a page. If you have multiple scripts your App needs to apply or maintain on a page, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body. +Remove a 301 redirection rule from a site. - - To apply a script to a page, the script must first be registered to a Site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. - +This is useful for cleaning up outdated or unnecessary redirects, ensuring that your site's routing behavior remains efficient and up-to-date. -Required scope | `custom_code:write` +This endpoint requires an Enterprise workspace. + +Required scope: `sites:write`
@@ -7827,7 +10079,7 @@ Required scope | `custom_code:write`
```python -from webflow import Webflow, ScriptApply +from webflow import Webflow from webflow.environment import WebflowEnvironment client = Webflow( @@ -7835,23 +10087,9 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.pages.scripts.upsert_custom_code( - page_id="63c720f9347c2139b248e552", - scripts=[ - ScriptApply( - id="cms_slider", - location="header", - version="1.0.0", - attributes={ - "my-attribute": "some-value" - }, - ), - ScriptApply( - id="alert", - location="header", - version="0.0.1", - ) - ], +client.sites.redirects.delete( + site_id="580e63e98c9a982ac9b8b741", + redirect_id="66c4cb9a20cac35ed19500e6", ) ``` @@ -7868,7 +10106,7 @@ client.pages.scripts.upsert_custom_code(
-**page_id:** `str` — Unique identifier for a Page +**site_id:** `str` — Unique identifier for a Site
@@ -7876,7 +10114,7 @@ client.pages.scripts.upsert_custom_code(
-**request:** `ScriptApplyList` +**redirect_id:** `str` — Unique identifier site redirect
@@ -7896,7 +10134,7 @@ client.pages.scripts.upsert_custom_code(
-
client.pages.scripts.delete_custom_code(...) +
client.sites.redirects.update(...) -> Redirect
@@ -7908,13 +10146,11 @@ client.pages.scripts.upsert_custom_code(
-Remove all scripts from a page applied by the App. This endpoint will not remove scripts from the site's registered scripts. - -To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-pages/upsert-custom-code) endpoint. +Update a 301 redirection rule from a site. -Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). +This endpoint requires an Enterprise workspace. -Required scope | `custom_code:write` +Required scope: `sites:write`
@@ -7937,8 +10173,12 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.pages.scripts.delete_custom_code( - page_id="63c720f9347c2139b248e552", +client.sites.redirects.update( + site_id="580e63e98c9a982ac9b8b741", + redirect_id="66c4cb9a20cac35ed19500e6", + id="42e1a2b7aa1a13f768a0042a", + from_url="/mostly-harmless", + to_url="/earth", ) ``` @@ -7955,7 +10195,23 @@ client.pages.scripts.delete_custom_code(
-**page_id:** `str` — Unique identifier for a Page +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**redirect_id:** `str` — Unique identifier site redirect + +
+
+ +
+
+ +**request:** `Redirect`
@@ -7975,8 +10231,8 @@ client.pages.scripts.delete_custom_code(
-## Sites Redirects -
client.sites.redirects.list(...) -> Redirects +## Sites Plans +
client.sites.plans.get_site_plan(...) -> SitePlan
@@ -7988,13 +10244,11 @@ client.pages.scripts.delete_custom_code(
-Fetch a list of all 301 redirect rules configured for a specific site. - -Use this endpoint to review, audit, or manage the redirection rules that control how traffic is rerouted on your site. +Get site plan details for the specified Site. This endpoint requires an Enterprise workspace. -Required scope: `sites:read` +Required scope | `sites:read`
@@ -8017,7 +10271,7 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.redirects.list( +client.sites.plans.get_site_plan( site_id="580e63e98c9a982ac9b8b741", ) @@ -8055,7 +10309,8 @@ client.sites.redirects.list(
-
client.sites.redirects.create(...) -> Redirect +## Sites RobotsTxt +
client.sites.robots_txt.get(...) -> Robots
@@ -8067,13 +10322,11 @@ client.sites.redirects.list(
-Add a new 301 redirection rule to a site. - -This endpoint allows you to define a source path (`fromUrl`) and its corresponding destination path (`toUrl`), which will dictate how traffic is rerouted on your site. This is useful for managing site changes, restructuring URLs, or handling outdated links. +Retrieve the robots.txt configuration for various user agents. This endpoint requires an Enterprise workspace. -Required scope: `sites:write` +Required scope: `site_config:read`
@@ -8096,11 +10349,8 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.redirects.create( +client.sites.robots_txt.get( site_id="580e63e98c9a982ac9b8b741", - id="42e1a2b7aa1a13f768a0042a", - from_url="/mostly-harmless", - to_url="/earth", ) ``` @@ -8125,14 +10375,6 @@ client.sites.redirects.create(
-**request:** `Redirect` - -
-
- -
-
- **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -8145,7 +10387,7 @@ client.sites.redirects.create(
-
client.sites.redirects.delete(...) -> Redirects +
client.sites.robots_txt.put(...) -> Robots
@@ -8157,13 +10399,11 @@ client.sites.redirects.create(
-Remove a 301 redirection rule from a site. - -This is useful for cleaning up outdated or unnecessary redirects, ensuring that your site's routing behavior remains efficient and up-to-date. +Replace the `robots.txt` configuration for various user agents. This endpoint requires an Enterprise workspace. -Required scope: `sites:write` +Required scope | `site_config:write`
@@ -8178,7 +10418,7 @@ Required scope: `sites:write`
```python -from webflow import Webflow +from webflow import Webflow, RobotsRulesItem from webflow.environment import WebflowEnvironment client = Webflow( @@ -8186,9 +10426,21 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.redirects.delete( +client.sites.robots_txt.put( site_id="580e63e98c9a982ac9b8b741", - redirect_id="66c4cb9a20cac35ed19500e6", + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=[ + "/public" + ], + disallows=[ + "/vogon-poetry", + "/total-perspective-vortex" + ], + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", ) ``` @@ -8213,7 +10465,7 @@ client.sites.redirects.delete(
-**redirect_id:** `str` — Unique identifier site redirect +**request:** `Robots`
@@ -8233,7 +10485,7 @@ client.sites.redirects.delete(
-
client.sites.redirects.update(...) -> Redirect +
client.sites.robots_txt.delete(...) -> Robots
@@ -8245,11 +10497,13 @@ client.sites.redirects.delete(
-Update a 301 redirection rule from a site. +Remove specific rules for a user-agent in your `robots.txt` file. To delete all rules for a user-agent, provide an empty rule set. This will remove the user-agent's entry entirely, leaving it subject to your site's default crawling behavior. + +**Note:** Deleting a user-agent with no rules will make the user-agent's access unrestricted unless other directives apply. This endpoint requires an Enterprise workspace. -Required scope: `sites:write` +Required scope: `site_config:write`
@@ -8264,7 +10518,7 @@ Required scope: `sites:write`
```python -from webflow import Webflow +from webflow import Webflow, RobotsRulesItem from webflow.environment import WebflowEnvironment client = Webflow( @@ -8272,12 +10526,19 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.redirects.update( +client.sites.robots_txt.delete( site_id="580e63e98c9a982ac9b8b741", - redirect_id="66c4cb9a20cac35ed19500e6", - id="42e1a2b7aa1a13f768a0042a", - from_url="/mostly-harmless", - to_url="/earth", + rules=[ + RobotsRulesItem( + user_agent="*", + allows=[ + "/public" + ], + disallows=[ + "/bubbles" + ], + ) + ], ) ``` @@ -8302,15 +10563,7 @@ client.sites.redirects.update(
-**redirect_id:** `str` — Unique identifier site redirect - -
-
- -
-
- -**request:** `Redirect` +**request:** `Robots`
@@ -8330,8 +10583,7 @@ client.sites.redirects.update(
-## Sites Plans -
client.sites.plans.get_site_plan(...) -> SitePlan +
client.sites.robots_txt.patch(...) -> Robots
@@ -8343,11 +10595,11 @@ client.sites.redirects.update(
-Get site plan details for the specified Site. +Update the `robots.txt` configuration for various user agents. This endpoint requires an Enterprise workspace. -Required scope | `sites:read` +Required scope | `site_config:write`
@@ -8362,7 +10614,7 @@ Required scope | `sites:read`
```python -from webflow import Webflow +from webflow import Webflow, RobotsRulesItem from webflow.environment import WebflowEnvironment client = Webflow( @@ -8370,8 +10622,21 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.plans.get_site_plan( +client.sites.robots_txt.patch( site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=[ + "/public" + ], + disallows=[ + "/vogon-poetry", + "/total-perspective-vortex" + ], + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", ) ``` @@ -8396,6 +10661,14 @@ client.sites.plans.get_site_plan(
+**request:** `Robots` + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -8408,8 +10681,8 @@ client.sites.plans.get_site_plan(
-## Sites RobotsTxt -
client.sites.robots_txt.get(...) -> Robots +## Sites WellKnown +
client.sites.well_known.put(...)
@@ -8421,11 +10694,20 @@ client.sites.plans.get_site_plan(
-Retrieve the robots.txt configuration for various user agents. +Upload a supported well-known file to a site. + +The current restrictions on well-known files are as follows: + - Each file must be smaller than 100kb + - Less than 30 total files + - Have one of the following file extensions (or no extension): `.txt`, `.json`, `.noext` + + + `.noext` is a special file extension that removes other extensions. For example, `apple-app-site-association.noext.txt` will be uploaded as `apple-app-site-association`. Use this extension for tools that have trouble uploading extensionless files. + This endpoint requires an Enterprise workspace. -Required scope: `site_config:read` +Required scope: `site_config:write`
@@ -8448,8 +10730,11 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.robots_txt.get( +client.sites.well_known.put( site_id="580e63e98c9a982ac9b8b741", + file_name="apple-app-site-association.txt", + file_data="{\n \"applinks\": {\n \"apps\": [],\n \"details\": [\n {\n \"appID\": \"ABCDE12345.com.example.app\",\n \"paths\": [ \"/*\", \"/some/path/*\" ]\n }\n ]\n }\n}\n", + content_type="application/json", ) ``` @@ -8474,6 +10759,30 @@ client.sites.robots_txt.get(
+**file_name:** `str` — The name of the file + +
+
+ +
+
+ +**file_data:** `str` — The contents of the file + +
+
+ +
+
+ +**content_type:** `typing.Optional[WellKnownFileContentType]` — The content type of the file. Defaults to application/json + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -8486,7 +10795,7 @@ client.sites.robots_txt.get(
-
client.sites.robots_txt.put(...) -> Robots +
client.sites.well_known.delete(...)
@@ -8498,11 +10807,11 @@ client.sites.robots_txt.get(
-Replace the `robots.txt` configuration for various user agents. +Delete existing well-known files from a site. This endpoint requires an Enterprise workspace. -Required scope | `site_config:write` +Required scope: `site_config:write`
@@ -8517,7 +10826,7 @@ Required scope | `site_config:write`
```python -from webflow import Webflow, RobotsRulesItem +from webflow import Webflow from webflow.environment import WebflowEnvironment client = Webflow( @@ -8525,21 +10834,8 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.robots_txt.put( +client.sites.well_known.delete( site_id="580e63e98c9a982ac9b8b741", - rules=[ - RobotsRulesItem( - user_agent="googlebot", - allows=[ - "/public" - ], - disallows=[ - "/vogon-poetry", - "/total-perspective-vortex" - ], - ) - ], - sitemap="https://heartofgold.ship/sitemap.xml", ) ``` @@ -8564,7 +10860,7 @@ client.sites.robots_txt.put(
-**request:** `Robots` +**file_names:** `typing.Optional[typing.List[str]]` — A list of file names to delete
@@ -8584,7 +10880,8 @@ client.sites.robots_txt.put(
-
client.sites.robots_txt.delete(...) -> Robots +## Sites GoogleTag +
client.sites.google_tag.list(...) -> GoogleTagIds
@@ -8596,13 +10893,9 @@ client.sites.robots_txt.put(
-Remove specific rules for a user-agent in your `robots.txt` file. To delete all rules for a user-agent, provide an empty rule set. This will remove the user-agent's entry entirely, leaving it subject to your site's default crawling behavior. - -**Note:** Deleting a user-agent with no rules will make the user-agent's access unrestricted unless other directives apply. - -This endpoint requires an Enterprise workspace. +List all Google Tag IDs configured for a site, sorted by order. -Required scope: `site_config:write` +Required scope: `sites:read`
@@ -8617,7 +10910,7 @@ Required scope: `site_config:write`
```python -from webflow import Webflow, RobotsRulesItem +from webflow import Webflow from webflow.environment import WebflowEnvironment client = Webflow( @@ -8625,19 +10918,8 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.robots_txt.delete( +client.sites.google_tag.list( site_id="580e63e98c9a982ac9b8b741", - rules=[ - RobotsRulesItem( - user_agent="*", - allows=[ - "/public" - ], - disallows=[ - "/bubbles" - ], - ) - ], ) ``` @@ -8662,14 +10944,6 @@ client.sites.robots_txt.delete(
-**request:** `Robots` - -
-
- -
-
- **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -8682,7 +10956,7 @@ client.sites.robots_txt.delete(
-
client.sites.robots_txt.patch(...) -> Robots +
client.sites.google_tag.delete_all(...)
@@ -8694,11 +10968,9 @@ client.sites.robots_txt.delete(
-Update the `robots.txt` configuration for various user agents. - -This endpoint requires an Enterprise workspace. +Delete all Google Tag IDs from a site. -Required scope | `site_config:write` +Required scope: `sites:write`
@@ -8713,7 +10985,7 @@ Required scope | `site_config:write`
```python -from webflow import Webflow, RobotsRulesItem +from webflow import Webflow from webflow.environment import WebflowEnvironment client = Webflow( @@ -8721,21 +10993,8 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.robots_txt.patch( +client.sites.google_tag.delete_all( site_id="580e63e98c9a982ac9b8b741", - rules=[ - RobotsRulesItem( - user_agent="googlebot", - allows=[ - "/public" - ], - disallows=[ - "/vogon-poetry", - "/total-perspective-vortex" - ], - ) - ], - sitemap="https://heartofgold.ship/sitemap.xml", ) ``` @@ -8760,14 +11019,6 @@ client.sites.robots_txt.patch(
-**request:** `Robots` - -
-
- -
-
- **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -8780,8 +11031,7 @@ client.sites.robots_txt.patch(
-## Sites WellKnown -
client.sites.well_known.put(...) +
client.sites.google_tag.upsert(...) -> GoogleTagIds
@@ -8793,20 +11043,11 @@ client.sites.robots_txt.patch(
-Upload a supported well-known file to a site. - -The current restrictions on well-known files are as follows: - - Each file must be smaller than 100kb - - Less than 30 total files - - Have one of the following file extensions (or no extension): `.txt`, `.json`, `.noext` - - - `.noext` is a special file extension that removes other extensions. For example, `apple-app-site-association.noext.txt` will be uploaded as `apple-app-site-association`. Use this extension for tools that have trouble uploading extensionless files. - +Add or update Google Tag IDs for a site. Existing tags not referenced in the request are preserved. A site may have a maximum of 25 tags total. -This endpoint requires an Enterprise workspace. +`order` is optional on input — it is auto-assigned for new tags and returned on all tags in the response. -Required scope: `site_config:write` +Required scope: `sites:write`
@@ -8821,7 +11062,7 @@ Required scope: `site_config:write`
```python -from webflow import Webflow +from webflow import Webflow, GoogleTagId from webflow.environment import WebflowEnvironment client = Webflow( @@ -8829,11 +11070,15 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.well_known.put( +client.sites.google_tag.upsert( site_id="580e63e98c9a982ac9b8b741", - file_name="apple-app-site-association.txt", - file_data="{\n \"applinks\": {\n \"apps\": [],\n \"details\": [\n {\n \"appID\": \"ABCDE12345.com.example.app\",\n \"paths\": [ \"/*\", \"/some/path/*\" ]\n }\n ]\n }\n}\n", - content_type="application/json", + google_tag_ids=[ + GoogleTagId( + order=0, + display_name="Main Analytics Tag", + tag_id="G-1234567890", + ) + ], ) ``` @@ -8858,23 +11103,7 @@ client.sites.well_known.put(
-**file_name:** `str` — The name of the file - -
-
- -
-
- -**file_data:** `str` — The contents of the file - -
-
- -
-
- -**content_type:** `typing.Optional[WellKnownFileContentType]` — The content type of the file. Defaults to application/json +**request:** `GoogleTagIds`
@@ -8894,7 +11123,7 @@ client.sites.well_known.put(
-
client.sites.well_known.delete(...) +
client.sites.google_tag.delete(...) -> GoogleTagIds
@@ -8906,11 +11135,9 @@ client.sites.well_known.put(
-Delete existing well-known files from a site. - -This endpoint requires an Enterprise workspace. +Delete a single Google Tag ID from a site. The `order` values of the remaining tags are renormalized after deletion. -Required scope: `site_config:write` +Required scope: `sites:write`
@@ -8933,8 +11160,9 @@ client = Webflow( environment=WebflowEnvironment.DATA_API, ) -client.sites.well_known.delete( +client.sites.google_tag.delete( site_id="580e63e98c9a982ac9b8b741", + tag_id="G-XXXXXXXXXX", ) ``` @@ -8959,7 +11187,7 @@ client.sites.well_known.delete(
-**file_names:** `typing.Optional[typing.List[str]]` — A list of file names to delete +**tag_id:** `str` — The Google Tag ID (e.g. G-XXXXXXXXXX)
@@ -9152,7 +11380,7 @@ client.sites.comments.list_comment_threads( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization)
@@ -9289,7 +11517,7 @@ client.sites.comments.get_comment_thread( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) @@ -9426,7 +11654,7 @@ client.sites.comments.list_comment_replies( Unique identifier for a specific Locale. -[Lear more about localization.](/data/v2.0.0/docs/working-with-localization) +[Learn more about localization.](/data/v2.0.0/docs/working-with-localization) @@ -9497,6 +11725,8 @@ Get all scripts applied to a site by the App. To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. +Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` @@ -9576,6 +11806,8 @@ Apply registered scripts to a site. If you have multiple scripts your App needs To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. +Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` @@ -9759,6 +11991,8 @@ Get a list of scripts that have been applied to a site and/or individual pages. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. +Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` diff --git a/src/webflow/__init__.py b/src/webflow/__init__.py index 48d0673..641b8e8 100644 --- a/src/webflow/__init__.py +++ b/src/webflow/__init__.py @@ -7,6 +7,12 @@ if typing.TYPE_CHECKING: from .types import ( + AnalyzeBucketTimeZone, + AnalyzeDailyBucketing, + AnalyzeDailyTimeseriesQuery, + AnalyzeFilterOperators, + AnalyzeTimeOnPageBucketing, + AnalyzeWindow, Application, Asset, AssetFolder, @@ -67,12 +73,24 @@ ComponentNode, ComponentProperties, ComponentProperty, - ComponentPropertyType, + ComponentPropertyText, + ComponentPropertyTextType, Conflict, CustomCodeBlock, CustomCodeBlockType, CustomCodeHostedResponse, CustomCodeInlineResponse, + CustomFont, + CustomFontAxis, + CustomFontBatchDeleteResponse, + CustomFontBatchDeleteResponseDeletedItem, + CustomFontBatchDeleteResponseFailedItem, + CustomFontCreateResponse, + CustomFontFontDisplay, + CustomFontFormat, + CustomFontUpload, + CustomFontUploadFields, + CustomFonts, CustomRole, CustomRoleAuditLogItem, CustomRoleAuditLogItemEventSubType, @@ -87,7 +105,6 @@ FieldType, FieldValidations, FieldValidationsAdditionalProperties, - FieldValidationsAdditionalPropertiesAdditionalProperties, ForbiddenErrorBody, Form, FormField, @@ -101,14 +118,20 @@ FormSubmissionTriggerPayload, FormSubmissionTriggerPayloadSchemaItem, FormSubmissionTriggerPayloadSchemaItemFieldType, + GoogleTagId, + GoogleTagIds, ImageNode, ImageNodeImage, InvalidDomain, InvalidScopes, InventoryItem, InventoryItemInventoryType, + ItemsListItemsLiveRequestCreatedOn, ItemsListItemsLiveRequestLastPublished, + ItemsListItemsLiveRequestLastUpdated, + ItemsListItemsRequestCreatedOn, ItemsListItemsRequestLastPublished, + ItemsListItemsRequestLastUpdated, ListCustomCodeBlocks, Locale, Locales, @@ -196,8 +219,10 @@ SingleLocaleCreatedPayloadFieldData, Site, SiteActivityLogItem, + SiteActivityLogItemActorType, SiteActivityLogItemEvent, SiteActivityLogItemResourceOperation, + SiteActivityLogItemSource, SiteActivityLogItemUser, SiteActivityLogResponse, SiteDataCollectionType, @@ -209,6 +234,7 @@ SitePlanName, SitePublish, SitePublishPayload, + SitePublishPayloadPublishScope, Sites, Sku, SkuFieldData, @@ -236,6 +262,32 @@ TextNode, TextNodeText, TextNodeWrite, + TimeOnPageDataPoint, + TimeOnPageFilter, + TimeOnPageGranularityPeriod, + TimeOnPageMetricScope, + TimeOnPageResponse, + TimeOnPageTimeseriesQuery, + TopDimensionsDimension, + TopDimensionsFilter, + TopDimensionsMetricScope, + TopDimensionsResponse, + TopDimensionsRow, + TopEventsCmsContextEntry, + TopEventsComponentContextEntry, + TopEventsFilter, + TopEventsResponse, + TopEventsRow, + TopEventsTimeseriesPoint, + TopPagesFilter, + TopPagesResponse, + TopPagesRow, + TopPagesSortBy, + TopPagesTimeseriesPoint, + TrafficDataPoint, + TrafficFilter, + TrafficMetricScope, + TrafficResponse, TriggerType, UpdatedOrder, UserAccess, @@ -281,6 +333,7 @@ ForbiddenError, InternalServerError, NotFoundError, + ServiceUnavailableError, TooManyRequestsError, UnauthorizedError, ) @@ -289,6 +342,11 @@ ComponentPropertiesWritePropertiesItem, ComponentsUpdateContentResponse, ComponentsUpdatePropertiesResponse, + CustomFontBatchDeleteRequestItemsItem, + CustomFontsCreateRequestFontDisplay, + CustomFontsGetResponse, + CustomFontsUpdateRequestFontDisplay, + CustomFontsUpdateResponse, EcommInventoryChangedPayload, InventoryUpdateRequestInventoryType, OrdersListRequestStatus, @@ -300,10 +358,13 @@ ProductSkuCreateSku, ProductsCreateSkuResponse, SitesPublishResponse, + SitesPublishResponsePublishScope, UpdateStaticContentResponse, + analyze, assets, collections, components, + custom_fonts, ecommerce, forms, inventory, @@ -320,6 +381,12 @@ from .environment import WebflowEnvironment from .version import __version__ _dynamic_imports: typing.Dict[str, str] = { + "AnalyzeBucketTimeZone": ".types", + "AnalyzeDailyBucketing": ".types", + "AnalyzeDailyTimeseriesQuery": ".types", + "AnalyzeFilterOperators": ".types", + "AnalyzeTimeOnPageBucketing": ".types", + "AnalyzeWindow": ".types", "Application": ".types", "Asset": ".types", "AssetFolder": ".types", @@ -384,7 +451,8 @@ "ComponentProperties": ".types", "ComponentPropertiesWritePropertiesItem": ".resources", "ComponentProperty": ".types", - "ComponentPropertyType": ".types", + "ComponentPropertyText": ".types", + "ComponentPropertyTextType": ".types", "ComponentsUpdateContentResponse": ".resources", "ComponentsUpdatePropertiesResponse": ".resources", "Conflict": ".types", @@ -393,6 +461,22 @@ "CustomCodeBlockType": ".types", "CustomCodeHostedResponse": ".types", "CustomCodeInlineResponse": ".types", + "CustomFont": ".types", + "CustomFontAxis": ".types", + "CustomFontBatchDeleteRequestItemsItem": ".resources", + "CustomFontBatchDeleteResponse": ".types", + "CustomFontBatchDeleteResponseDeletedItem": ".types", + "CustomFontBatchDeleteResponseFailedItem": ".types", + "CustomFontCreateResponse": ".types", + "CustomFontFontDisplay": ".types", + "CustomFontFormat": ".types", + "CustomFontUpload": ".types", + "CustomFontUploadFields": ".types", + "CustomFonts": ".types", + "CustomFontsCreateRequestFontDisplay": ".resources", + "CustomFontsGetResponse": ".resources", + "CustomFontsUpdateRequestFontDisplay": ".resources", + "CustomFontsUpdateResponse": ".resources", "CustomRole": ".types", "CustomRoleAuditLogItem": ".types", "CustomRoleAuditLogItemEventSubType": ".types", @@ -408,7 +492,6 @@ "FieldType": ".types", "FieldValidations": ".types", "FieldValidationsAdditionalProperties": ".types", - "FieldValidationsAdditionalPropertiesAdditionalProperties": ".types", "ForbiddenError": ".errors", "ForbiddenErrorBody": ".types", "Form": ".types", @@ -423,6 +506,8 @@ "FormSubmissionTriggerPayload": ".types", "FormSubmissionTriggerPayloadSchemaItem": ".types", "FormSubmissionTriggerPayloadSchemaItemFieldType": ".types", + "GoogleTagId": ".types", + "GoogleTagIds": ".types", "ImageNode": ".types", "ImageNodeImage": ".types", "InternalServerError": ".errors", @@ -431,8 +516,12 @@ "InventoryItem": ".types", "InventoryItemInventoryType": ".types", "InventoryUpdateRequestInventoryType": ".resources", + "ItemsListItemsLiveRequestCreatedOn": ".types", "ItemsListItemsLiveRequestLastPublished": ".types", + "ItemsListItemsLiveRequestLastUpdated": ".types", + "ItemsListItemsRequestCreatedOn": ".types", "ItemsListItemsRequestLastPublished": ".types", + "ItemsListItemsRequestLastUpdated": ".types", "ListCustomCodeBlocks": ".types", "Locale": ".types", "Locales": ".types", @@ -523,14 +612,17 @@ "SelectNode": ".types", "SelectNodeChoicesItem": ".types", "SelectNodeWriteChoicesItem": ".types", + "ServiceUnavailableError": ".errors", "SettingChange": ".types", "SettingChangeAuditLogItem": ".types", "SingleLocaleCreatedPayload": ".types", "SingleLocaleCreatedPayloadFieldData": ".types", "Site": ".types", "SiteActivityLogItem": ".types", + "SiteActivityLogItemActorType": ".types", "SiteActivityLogItemEvent": ".types", "SiteActivityLogItemResourceOperation": ".types", + "SiteActivityLogItemSource": ".types", "SiteActivityLogItemUser": ".types", "SiteActivityLogResponse": ".types", "SiteDataCollectionType": ".types", @@ -542,8 +634,10 @@ "SitePlanName": ".types", "SitePublish": ".types", "SitePublishPayload": ".types", + "SitePublishPayloadPublishScope": ".types", "Sites": ".types", "SitesPublishResponse": ".resources", + "SitesPublishResponsePublishScope": ".resources", "Sku": ".types", "SkuFieldData": ".types", "SkuFieldDataCompareAtPrice": ".types", @@ -570,7 +664,33 @@ "TextNode": ".types", "TextNodeText": ".types", "TextNodeWrite": ".types", + "TimeOnPageDataPoint": ".types", + "TimeOnPageFilter": ".types", + "TimeOnPageGranularityPeriod": ".types", + "TimeOnPageMetricScope": ".types", + "TimeOnPageResponse": ".types", + "TimeOnPageTimeseriesQuery": ".types", "TooManyRequestsError": ".errors", + "TopDimensionsDimension": ".types", + "TopDimensionsFilter": ".types", + "TopDimensionsMetricScope": ".types", + "TopDimensionsResponse": ".types", + "TopDimensionsRow": ".types", + "TopEventsCmsContextEntry": ".types", + "TopEventsComponentContextEntry": ".types", + "TopEventsFilter": ".types", + "TopEventsResponse": ".types", + "TopEventsRow": ".types", + "TopEventsTimeseriesPoint": ".types", + "TopPagesFilter": ".types", + "TopPagesResponse": ".types", + "TopPagesRow": ".types", + "TopPagesSortBy": ".types", + "TopPagesTimeseriesPoint": ".types", + "TrafficDataPoint": ".types", + "TrafficFilter": ".types", + "TrafficMetricScope": ".types", + "TrafficResponse": ".types", "TriggerType": ".types", "UnauthorizedError": ".errors", "UpdateStaticContentResponse": ".resources", @@ -614,9 +734,11 @@ "WorkspaceMembershipAuditLogItem": ".types", "WorkspaceMembershipAuditLogItemEventSubType": ".types", "__version__": ".version", + "analyze": ".resources", "assets": ".resources", "collections": ".resources", "components": ".resources", + "custom_fonts": ".resources", "ecommerce": ".resources", "forms": ".resources", "inventory": ".resources", @@ -653,6 +775,12 @@ def __dir__(): __all__ = [ + "AnalyzeBucketTimeZone", + "AnalyzeDailyBucketing", + "AnalyzeDailyTimeseriesQuery", + "AnalyzeFilterOperators", + "AnalyzeTimeOnPageBucketing", + "AnalyzeWindow", "Application", "Asset", "AssetFolder", @@ -717,7 +845,8 @@ def __dir__(): "ComponentProperties", "ComponentPropertiesWritePropertiesItem", "ComponentProperty", - "ComponentPropertyType", + "ComponentPropertyText", + "ComponentPropertyTextType", "ComponentsUpdateContentResponse", "ComponentsUpdatePropertiesResponse", "Conflict", @@ -726,6 +855,22 @@ def __dir__(): "CustomCodeBlockType", "CustomCodeHostedResponse", "CustomCodeInlineResponse", + "CustomFont", + "CustomFontAxis", + "CustomFontBatchDeleteRequestItemsItem", + "CustomFontBatchDeleteResponse", + "CustomFontBatchDeleteResponseDeletedItem", + "CustomFontBatchDeleteResponseFailedItem", + "CustomFontCreateResponse", + "CustomFontFontDisplay", + "CustomFontFormat", + "CustomFontUpload", + "CustomFontUploadFields", + "CustomFonts", + "CustomFontsCreateRequestFontDisplay", + "CustomFontsGetResponse", + "CustomFontsUpdateRequestFontDisplay", + "CustomFontsUpdateResponse", "CustomRole", "CustomRoleAuditLogItem", "CustomRoleAuditLogItemEventSubType", @@ -741,7 +886,6 @@ def __dir__(): "FieldType", "FieldValidations", "FieldValidationsAdditionalProperties", - "FieldValidationsAdditionalPropertiesAdditionalProperties", "ForbiddenError", "ForbiddenErrorBody", "Form", @@ -756,6 +900,8 @@ def __dir__(): "FormSubmissionTriggerPayload", "FormSubmissionTriggerPayloadSchemaItem", "FormSubmissionTriggerPayloadSchemaItemFieldType", + "GoogleTagId", + "GoogleTagIds", "ImageNode", "ImageNodeImage", "InternalServerError", @@ -764,8 +910,12 @@ def __dir__(): "InventoryItem", "InventoryItemInventoryType", "InventoryUpdateRequestInventoryType", + "ItemsListItemsLiveRequestCreatedOn", "ItemsListItemsLiveRequestLastPublished", + "ItemsListItemsLiveRequestLastUpdated", + "ItemsListItemsRequestCreatedOn", "ItemsListItemsRequestLastPublished", + "ItemsListItemsRequestLastUpdated", "ListCustomCodeBlocks", "Locale", "Locales", @@ -856,14 +1006,17 @@ def __dir__(): "SelectNode", "SelectNodeChoicesItem", "SelectNodeWriteChoicesItem", + "ServiceUnavailableError", "SettingChange", "SettingChangeAuditLogItem", "SingleLocaleCreatedPayload", "SingleLocaleCreatedPayloadFieldData", "Site", "SiteActivityLogItem", + "SiteActivityLogItemActorType", "SiteActivityLogItemEvent", "SiteActivityLogItemResourceOperation", + "SiteActivityLogItemSource", "SiteActivityLogItemUser", "SiteActivityLogResponse", "SiteDataCollectionType", @@ -875,8 +1028,10 @@ def __dir__(): "SitePlanName", "SitePublish", "SitePublishPayload", + "SitePublishPayloadPublishScope", "Sites", "SitesPublishResponse", + "SitesPublishResponsePublishScope", "Sku", "SkuFieldData", "SkuFieldDataCompareAtPrice", @@ -903,7 +1058,33 @@ def __dir__(): "TextNode", "TextNodeText", "TextNodeWrite", + "TimeOnPageDataPoint", + "TimeOnPageFilter", + "TimeOnPageGranularityPeriod", + "TimeOnPageMetricScope", + "TimeOnPageResponse", + "TimeOnPageTimeseriesQuery", "TooManyRequestsError", + "TopDimensionsDimension", + "TopDimensionsFilter", + "TopDimensionsMetricScope", + "TopDimensionsResponse", + "TopDimensionsRow", + "TopEventsCmsContextEntry", + "TopEventsComponentContextEntry", + "TopEventsFilter", + "TopEventsResponse", + "TopEventsRow", + "TopEventsTimeseriesPoint", + "TopPagesFilter", + "TopPagesResponse", + "TopPagesRow", + "TopPagesSortBy", + "TopPagesTimeseriesPoint", + "TrafficDataPoint", + "TrafficFilter", + "TrafficMetricScope", + "TrafficResponse", "TriggerType", "UnauthorizedError", "UpdateStaticContentResponse", @@ -947,9 +1128,11 @@ def __dir__(): "WorkspaceMembershipAuditLogItem", "WorkspaceMembershipAuditLogItemEventSubType", "__version__", + "analyze", "assets", "collections", "components", + "custom_fonts", "ecommerce", "forms", "inventory", diff --git a/src/webflow/client.py b/src/webflow/client.py index bc75156..b137323 100644 --- a/src/webflow/client.py +++ b/src/webflow/client.py @@ -10,9 +10,11 @@ from .environment import WebflowEnvironment if typing.TYPE_CHECKING: + from .resources.analyze.client import AnalyzeClient, AsyncAnalyzeClient from .resources.assets.client import AssetsClient, AsyncAssetsClient from .resources.collections.client import AsyncCollectionsClient, CollectionsClient from .resources.components.client import AsyncComponentsClient, ComponentsClient + from .resources.custom_fonts.client import AsyncCustomFontsClient, CustomFontsClient from .resources.ecommerce.client import AsyncEcommerceClient, EcommerceClient from .resources.forms.client import AsyncFormsClient, FormsClient from .resources.inventory.client import AsyncInventoryClient, InventoryClient @@ -99,12 +101,14 @@ def __init__( self._components: typing.Optional[ComponentsClient] = None self._scripts: typing.Optional[ScriptsClient] = None self._assets: typing.Optional[AssetsClient] = None + self._custom_fonts: typing.Optional[CustomFontsClient] = None self._webhooks: typing.Optional[WebhooksClient] = None self._forms: typing.Optional[FormsClient] = None self._products: typing.Optional[ProductsClient] = None self._orders: typing.Optional[OrdersClient] = None self._inventory: typing.Optional[InventoryClient] = None self._ecommerce: typing.Optional[EcommerceClient] = None + self._analyze: typing.Optional[AnalyzeClient] = None self._workspaces: typing.Optional[WorkspacesClient] = None @property @@ -163,6 +167,14 @@ def assets(self): self._assets = AssetsClient(client_wrapper=self._client_wrapper) return self._assets + @property + def custom_fonts(self): + if self._custom_fonts is None: + from .resources.custom_fonts.client import CustomFontsClient # noqa: E402 + + self._custom_fonts = CustomFontsClient(client_wrapper=self._client_wrapper) + return self._custom_fonts + @property def webhooks(self): if self._webhooks is None: @@ -211,6 +223,14 @@ def ecommerce(self): self._ecommerce = EcommerceClient(client_wrapper=self._client_wrapper) return self._ecommerce + @property + def analyze(self): + if self._analyze is None: + from .resources.analyze.client import AnalyzeClient # noqa: E402 + + self._analyze = AnalyzeClient(client_wrapper=self._client_wrapper) + return self._analyze + @property def workspaces(self): if self._workspaces is None: @@ -293,12 +313,14 @@ def __init__( self._components: typing.Optional[AsyncComponentsClient] = None self._scripts: typing.Optional[AsyncScriptsClient] = None self._assets: typing.Optional[AsyncAssetsClient] = None + self._custom_fonts: typing.Optional[AsyncCustomFontsClient] = None self._webhooks: typing.Optional[AsyncWebhooksClient] = None self._forms: typing.Optional[AsyncFormsClient] = None self._products: typing.Optional[AsyncProductsClient] = None self._orders: typing.Optional[AsyncOrdersClient] = None self._inventory: typing.Optional[AsyncInventoryClient] = None self._ecommerce: typing.Optional[AsyncEcommerceClient] = None + self._analyze: typing.Optional[AsyncAnalyzeClient] = None self._workspaces: typing.Optional[AsyncWorkspacesClient] = None @property @@ -357,6 +379,14 @@ def assets(self): self._assets = AsyncAssetsClient(client_wrapper=self._client_wrapper) return self._assets + @property + def custom_fonts(self): + if self._custom_fonts is None: + from .resources.custom_fonts.client import AsyncCustomFontsClient # noqa: E402 + + self._custom_fonts = AsyncCustomFontsClient(client_wrapper=self._client_wrapper) + return self._custom_fonts + @property def webhooks(self): if self._webhooks is None: @@ -405,6 +435,14 @@ def ecommerce(self): self._ecommerce = AsyncEcommerceClient(client_wrapper=self._client_wrapper) return self._ecommerce + @property + def analyze(self): + if self._analyze is None: + from .resources.analyze.client import AsyncAnalyzeClient # noqa: E402 + + self._analyze = AsyncAnalyzeClient(client_wrapper=self._client_wrapper) + return self._analyze + @property def workspaces(self): if self._workspaces is None: diff --git a/src/webflow/core/client_wrapper.py b/src/webflow/core/client_wrapper.py index 7f6db17..3839879 100644 --- a/src/webflow/core/client_wrapper.py +++ b/src/webflow/core/client_wrapper.py @@ -28,12 +28,12 @@ def get_headers(self) -> typing.Dict[str, str]: import platform headers: typing.Dict[str, str] = { - "User-Agent": "webflow/2.0.0", + "User-Agent": "webflow/2.0.1", "X-Fern-Language": "Python", "X-Fern-Runtime": f"python/{platform.python_version()}", "X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}", "X-Fern-SDK-Name": "webflow", - "X-Fern-SDK-Version": "2.0.0", + "X-Fern-SDK-Version": "2.0.1", **(self.get_custom_headers() or {}), } headers["Authorization"] = f"Bearer {self._get_access_token()}" diff --git a/src/webflow/errors/__init__.py b/src/webflow/errors/__init__.py index bd5f618..14374f1 100644 --- a/src/webflow/errors/__init__.py +++ b/src/webflow/errors/__init__.py @@ -11,6 +11,7 @@ from .forbidden_error import ForbiddenError from .internal_server_error import InternalServerError from .not_found_error import NotFoundError + from .service_unavailable_error import ServiceUnavailableError from .too_many_requests_error import TooManyRequestsError from .unauthorized_error import UnauthorizedError _dynamic_imports: typing.Dict[str, str] = { @@ -19,6 +20,7 @@ "ForbiddenError": ".forbidden_error", "InternalServerError": ".internal_server_error", "NotFoundError": ".not_found_error", + "ServiceUnavailableError": ".service_unavailable_error", "TooManyRequestsError": ".too_many_requests_error", "UnauthorizedError": ".unauthorized_error", } @@ -51,6 +53,7 @@ def __dir__(): "ForbiddenError", "InternalServerError", "NotFoundError", + "ServiceUnavailableError", "TooManyRequestsError", "UnauthorizedError", ] diff --git a/src/webflow/errors/service_unavailable_error.py b/src/webflow/errors/service_unavailable_error.py new file mode 100644 index 0000000..50e2d01 --- /dev/null +++ b/src/webflow/errors/service_unavailable_error.py @@ -0,0 +1,11 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..core.api_error import ApiError +from ..types.error import Error + + +class ServiceUnavailableError(ApiError): + def __init__(self, body: Error, headers: typing.Optional[typing.Dict[str, str]] = None): + super().__init__(status_code=503, headers=headers, body=body) diff --git a/src/webflow/resources/__init__.py b/src/webflow/resources/__init__.py index 7eea249..2bb2a9f 100644 --- a/src/webflow/resources/__init__.py +++ b/src/webflow/resources/__init__.py @@ -7,9 +7,11 @@ if typing.TYPE_CHECKING: from . import ( + analyze, assets, collections, components, + custom_fonts, ecommerce, forms, inventory, @@ -28,6 +30,13 @@ ComponentsUpdateContentResponse, ComponentsUpdatePropertiesResponse, ) + from .custom_fonts import ( + CustomFontBatchDeleteRequestItemsItem, + CustomFontsCreateRequestFontDisplay, + CustomFontsGetResponse, + CustomFontsUpdateRequestFontDisplay, + CustomFontsUpdateResponse, + ) from .inventory import EcommInventoryChangedPayload, InventoryUpdateRequestInventoryType from .orders import OrdersListRequestStatus, OrdersRefundRequestReason from .pages import ( @@ -37,12 +46,17 @@ UpdateStaticContentResponse, ) from .products import ProductSkuCreateProduct, ProductSkuCreateSku, ProductsCreateSkuResponse - from .sites import SitesPublishResponse + from .sites import SitesPublishResponse, SitesPublishResponsePublishScope _dynamic_imports: typing.Dict[str, str] = { "ComponentDomWriteNodesItem": ".components", "ComponentPropertiesWritePropertiesItem": ".components", "ComponentsUpdateContentResponse": ".components", "ComponentsUpdatePropertiesResponse": ".components", + "CustomFontBatchDeleteRequestItemsItem": ".custom_fonts", + "CustomFontsCreateRequestFontDisplay": ".custom_fonts", + "CustomFontsGetResponse": ".custom_fonts", + "CustomFontsUpdateRequestFontDisplay": ".custom_fonts", + "CustomFontsUpdateResponse": ".custom_fonts", "EcommInventoryChangedPayload": ".inventory", "InventoryUpdateRequestInventoryType": ".inventory", "OrdersListRequestStatus": ".orders", @@ -54,10 +68,13 @@ "ProductSkuCreateSku": ".products", "ProductsCreateSkuResponse": ".products", "SitesPublishResponse": ".sites", + "SitesPublishResponsePublishScope": ".sites", "UpdateStaticContentResponse": ".pages", + "analyze": ".analyze", "assets": ".assets", "collections": ".collections", "components": ".components", + "custom_fonts": ".custom_fonts", "ecommerce": ".ecommerce", "forms": ".forms", "inventory": ".inventory", @@ -98,6 +115,11 @@ def __dir__(): "ComponentPropertiesWritePropertiesItem", "ComponentsUpdateContentResponse", "ComponentsUpdatePropertiesResponse", + "CustomFontBatchDeleteRequestItemsItem", + "CustomFontsCreateRequestFontDisplay", + "CustomFontsGetResponse", + "CustomFontsUpdateRequestFontDisplay", + "CustomFontsUpdateResponse", "EcommInventoryChangedPayload", "InventoryUpdateRequestInventoryType", "OrdersListRequestStatus", @@ -109,10 +131,13 @@ def __dir__(): "ProductSkuCreateSku", "ProductsCreateSkuResponse", "SitesPublishResponse", + "SitesPublishResponsePublishScope", "UpdateStaticContentResponse", + "analyze", "assets", "collections", "components", + "custom_fonts", "ecommerce", "forms", "inventory", diff --git a/src/webflow/resources/analyze/__init__.py b/src/webflow/resources/analyze/__init__.py new file mode 100644 index 0000000..10adfa6 --- /dev/null +++ b/src/webflow/resources/analyze/__init__.py @@ -0,0 +1,55 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .resources import ( + ReportsTimeOnPageRequestDeviceType, + ReportsTopDimensionsRequestDeviceType, + ReportsTopEventsRequestDeviceType, + ReportsTopPagesRequestDeviceType, + ReportsTrafficRequestDeviceType, + reports, + ) +_dynamic_imports: typing.Dict[str, str] = { + "ReportsTimeOnPageRequestDeviceType": ".resources", + "ReportsTopDimensionsRequestDeviceType": ".resources", + "ReportsTopEventsRequestDeviceType": ".resources", + "ReportsTopPagesRequestDeviceType": ".resources", + "ReportsTrafficRequestDeviceType": ".resources", + "reports": ".resources", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "ReportsTimeOnPageRequestDeviceType", + "ReportsTopDimensionsRequestDeviceType", + "ReportsTopEventsRequestDeviceType", + "ReportsTopPagesRequestDeviceType", + "ReportsTrafficRequestDeviceType", + "reports", +] diff --git a/src/webflow/resources/analyze/client.py b/src/webflow/resources/analyze/client.py new file mode 100644 index 0000000..cad363d --- /dev/null +++ b/src/webflow/resources/analyze/client.py @@ -0,0 +1,63 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations + +import typing + +from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from .raw_client import AsyncRawAnalyzeClient, RawAnalyzeClient + +if typing.TYPE_CHECKING: + from .resources.reports.client import AsyncReportsClient, ReportsClient + + +class AnalyzeClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawAnalyzeClient(client_wrapper=client_wrapper) + self._client_wrapper = client_wrapper + self._reports: typing.Optional[ReportsClient] = None + + @property + def with_raw_response(self) -> RawAnalyzeClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawAnalyzeClient + """ + return self._raw_client + + @property + def reports(self): + if self._reports is None: + from .resources.reports.client import ReportsClient # noqa: E402 + + self._reports = ReportsClient(client_wrapper=self._client_wrapper) + return self._reports + + +class AsyncAnalyzeClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawAnalyzeClient(client_wrapper=client_wrapper) + self._client_wrapper = client_wrapper + self._reports: typing.Optional[AsyncReportsClient] = None + + @property + def with_raw_response(self) -> AsyncRawAnalyzeClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawAnalyzeClient + """ + return self._raw_client + + @property + def reports(self): + if self._reports is None: + from .resources.reports.client import AsyncReportsClient # noqa: E402 + + self._reports = AsyncReportsClient(client_wrapper=self._client_wrapper) + return self._reports diff --git a/src/webflow/resources/analyze/raw_client.py b/src/webflow/resources/analyze/raw_client.py new file mode 100644 index 0000000..a4bd105 --- /dev/null +++ b/src/webflow/resources/analyze/raw_client.py @@ -0,0 +1,13 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper + + +class RawAnalyzeClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + +class AsyncRawAnalyzeClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper diff --git a/src/webflow/resources/analyze/resources/__init__.py b/src/webflow/resources/analyze/resources/__init__.py new file mode 100644 index 0000000..47cdf72 --- /dev/null +++ b/src/webflow/resources/analyze/resources/__init__.py @@ -0,0 +1,55 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from . import reports + from .reports import ( + ReportsTimeOnPageRequestDeviceType, + ReportsTopDimensionsRequestDeviceType, + ReportsTopEventsRequestDeviceType, + ReportsTopPagesRequestDeviceType, + ReportsTrafficRequestDeviceType, + ) +_dynamic_imports: typing.Dict[str, str] = { + "ReportsTimeOnPageRequestDeviceType": ".reports", + "ReportsTopDimensionsRequestDeviceType": ".reports", + "ReportsTopEventsRequestDeviceType": ".reports", + "ReportsTopPagesRequestDeviceType": ".reports", + "ReportsTrafficRequestDeviceType": ".reports", + "reports": ".reports", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "ReportsTimeOnPageRequestDeviceType", + "ReportsTopDimensionsRequestDeviceType", + "ReportsTopEventsRequestDeviceType", + "ReportsTopPagesRequestDeviceType", + "ReportsTrafficRequestDeviceType", + "reports", +] diff --git a/src/webflow/resources/analyze/resources/reports/__init__.py b/src/webflow/resources/analyze/resources/reports/__init__.py new file mode 100644 index 0000000..4e58957 --- /dev/null +++ b/src/webflow/resources/analyze/resources/reports/__init__.py @@ -0,0 +1,52 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + ReportsTimeOnPageRequestDeviceType, + ReportsTopDimensionsRequestDeviceType, + ReportsTopEventsRequestDeviceType, + ReportsTopPagesRequestDeviceType, + ReportsTrafficRequestDeviceType, + ) +_dynamic_imports: typing.Dict[str, str] = { + "ReportsTimeOnPageRequestDeviceType": ".types", + "ReportsTopDimensionsRequestDeviceType": ".types", + "ReportsTopEventsRequestDeviceType": ".types", + "ReportsTopPagesRequestDeviceType": ".types", + "ReportsTrafficRequestDeviceType": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "ReportsTimeOnPageRequestDeviceType", + "ReportsTopDimensionsRequestDeviceType", + "ReportsTopEventsRequestDeviceType", + "ReportsTopPagesRequestDeviceType", + "ReportsTrafficRequestDeviceType", +] diff --git a/src/webflow/resources/analyze/resources/reports/client.py b/src/webflow/resources/analyze/resources/reports/client.py new file mode 100644 index 0000000..5c386f1 --- /dev/null +++ b/src/webflow/resources/analyze/resources/reports/client.py @@ -0,0 +1,1482 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from .....core.request_options import RequestOptions +from .....types.analyze_bucket_time_zone import AnalyzeBucketTimeZone +from .....types.analyze_daily_timeseries_query import AnalyzeDailyTimeseriesQuery +from .....types.time_on_page_filter import TimeOnPageFilter +from .....types.time_on_page_metric_scope import TimeOnPageMetricScope +from .....types.time_on_page_response import TimeOnPageResponse +from .....types.time_on_page_timeseries_query import TimeOnPageTimeseriesQuery +from .....types.top_dimensions_dimension import TopDimensionsDimension +from .....types.top_dimensions_filter import TopDimensionsFilter +from .....types.top_dimensions_metric_scope import TopDimensionsMetricScope +from .....types.top_dimensions_response import TopDimensionsResponse +from .....types.top_events_filter import TopEventsFilter +from .....types.top_events_response import TopEventsResponse +from .....types.top_pages_filter import TopPagesFilter +from .....types.top_pages_response import TopPagesResponse +from .....types.top_pages_sort_by import TopPagesSortBy +from .....types.traffic_filter import TrafficFilter +from .....types.traffic_metric_scope import TrafficMetricScope +from .....types.traffic_response import TrafficResponse +from .raw_client import AsyncRawReportsClient, RawReportsClient +from .types.reports_time_on_page_request_device_type import ReportsTimeOnPageRequestDeviceType +from .types.reports_top_dimensions_request_device_type import ReportsTopDimensionsRequestDeviceType +from .types.reports_top_events_request_device_type import ReportsTopEventsRequestDeviceType +from .types.reports_top_pages_request_device_type import ReportsTopPagesRequestDeviceType +from .types.reports_traffic_request_device_type import ReportsTrafficRequestDeviceType + + +class ReportsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawReportsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawReportsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawReportsClient + """ + return self._raw_client + + def traffic( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + metric_scope: TrafficMetricScope, + bucket_time_zone: AnalyzeBucketTimeZone, + device_type: typing.Optional[ReportsTrafficRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TrafficFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> TrafficResponse: + """ + Returns a daily time series of a single metric — sessions, users, or pageviews — over a time window. + + Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + metric_scope : TrafficMetricScope + The unit each `count` data point is measured in. + + bucket_time_zone : AnalyzeBucketTimeZone + IANA time zone used to align daily bucket boundaries. + + device_type : typing.Optional[ReportsTrafficRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TrafficFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TrafficFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TrafficResponse + Time-series traffic report for the requested window and filters. + + Examples + -------- + import datetime + + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.analyze.reports.traffic( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat( + "2026-04-01 00:00:00+00:00", + ), + end_time=datetime.datetime.fromisoformat( + "2026-04-08 00:00:00+00:00", + ), + metric_scope="session", + bucket_time_zone="America/New_York", + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", + ) + """ + _response = self._raw_client.traffic( + site_id, + start_time=start_time, + end_time=end_time, + metric_scope=metric_scope, + bucket_time_zone=bucket_time_zone, + device_type=device_type, + country=country, + page_path=page_path, + traffic_source=traffic_source, + referrer=referrer, + browser=browser, + utm_campaign=utm_campaign, + utm_medium=utm_medium, + utm_source=utm_source, + filter=filter, + request_options=request_options, + ) + return _response.data + + def top_pages( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + sort_by: typing.Optional[TopPagesSortBy] = None, + limit: typing.Optional[int] = None, + timeseries: typing.Optional[AnalyzeDailyTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTopPagesRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopPagesFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> TopPagesResponse: + """ + Returns the most-visited pages over a time window, ranked by `sortBy` (sessions, users, or pageviews). + + Each row carries all three scope counts; `sortBy` only governs ordering. Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + Set `timeseries[bucketTimeZone]` to attach a daily pageview `timeseries` to each row. Bucket counts are always pageviews regardless of `sortBy` — row-level counts honor the requested sort; the timeseries does not. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + sort_by : typing.Optional[TopPagesSortBy] + Metric used to rank rows in the response, descending. Defaults to `session`. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `250`. + + timeseries : typing.Optional[AnalyzeDailyTimeseriesQuery] + Include a daily pageview `timeseries` for each row, bucketed in the supplied IANA time zone. Omit this parameter to return ranked rows without per-page timeseries data. + + device_type : typing.Optional[ReportsTopPagesRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopPagesFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopPagesFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TopPagesResponse + Pages ranked by `sortBy` for the requested window and filters. + + Examples + -------- + import datetime + + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.analyze.reports.top_pages( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat( + "2026-04-01 00:00:00+00:00", + ), + end_time=datetime.datetime.fromisoformat( + "2026-04-08 00:00:00+00:00", + ), + sort_by="session", + limit=1, + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", + ) + """ + _response = self._raw_client.top_pages( + site_id, + start_time=start_time, + end_time=end_time, + sort_by=sort_by, + limit=limit, + timeseries=timeseries, + device_type=device_type, + country=country, + page_path=page_path, + traffic_source=traffic_source, + referrer=referrer, + browser=browser, + utm_campaign=utm_campaign, + utm_medium=utm_medium, + utm_source=utm_source, + filter=filter, + request_options=request_options, + ) + return _response.data + + def top_dimensions( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + dimension: TopDimensionsDimension, + metric_scope: TopDimensionsMetricScope, + limit: typing.Optional[int] = None, + device_type: typing.Optional[ReportsTopDimensionsRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopDimensionsFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> TopDimensionsResponse: + """ + Returns the top values within a chosen `dimension` — top countries, top traffic sources, top campaigns, top audiences, and so on — over a time window, ranked by sessions or users. + + Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + dimension : TopDimensionsDimension + The dimension whose top values are ranked. See `TopDimensionsDimension` for the supported values. + + metric_scope : TopDimensionsMetricScope + The unit each row's `count` is measured in — sessions or users. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `100`. + + device_type : typing.Optional[ReportsTopDimensionsRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopDimensionsFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopDimensionsFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TopDimensionsResponse + Dimension values ranked by `count` for the requested window and filters. + + Examples + -------- + import datetime + + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.analyze.reports.top_dimensions( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat( + "2026-04-01 00:00:00+00:00", + ), + end_time=datetime.datetime.fromisoformat( + "2026-04-08 00:00:00+00:00", + ), + dimension="country", + metric_scope="session", + limit=1, + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", + ) + """ + _response = self._raw_client.top_dimensions( + site_id, + start_time=start_time, + end_time=end_time, + dimension=dimension, + metric_scope=metric_scope, + limit=limit, + device_type=device_type, + country=country, + page_path=page_path, + traffic_source=traffic_source, + referrer=referrer, + browser=browser, + utm_campaign=utm_campaign, + utm_medium=utm_medium, + utm_source=utm_source, + filter=filter, + request_options=request_options, + ) + return _response.data + + def top_events( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + limit: typing.Optional[int] = None, + timeseries: typing.Optional[AnalyzeDailyTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTopEventsRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopEventsFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> TopEventsResponse: + """ + Returns the top events over a time window, ranked by how often they occurred. + + Events are counted individually, not rolled up into sessions, users, or pageviews — so this report has no `metricScope`. Each row's `count` is how many times the event occurred. Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + Set `timeseries[bucketTimeZone]` to attach a daily event count `timeseries` to each row. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `250`. + + timeseries : typing.Optional[AnalyzeDailyTimeseriesQuery] + Include a daily event count `timeseries` for each row, bucketed in the supplied IANA time zone. Omit this parameter to return ranked rows without per-event timeseries data. + + device_type : typing.Optional[ReportsTopEventsRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopEventsFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopEventsFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TopEventsResponse + Events ranked by how frequently they occurred, for the requested window and filters. + + Examples + -------- + import datetime + + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.analyze.reports.top_events( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat( + "2026-04-01 00:00:00+00:00", + ), + end_time=datetime.datetime.fromisoformat( + "2026-04-08 00:00:00+00:00", + ), + limit=1, + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", + ) + """ + _response = self._raw_client.top_events( + site_id, + start_time=start_time, + end_time=end_time, + limit=limit, + timeseries=timeseries, + device_type=device_type, + country=country, + page_path=page_path, + traffic_source=traffic_source, + browser=browser, + utm_campaign=utm_campaign, + utm_medium=utm_medium, + utm_source=utm_source, + filter=filter, + request_options=request_options, + ) + return _response.data + + def time_on_page( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + metric_scope: TimeOnPageMetricScope, + timeseries: typing.Optional[TimeOnPageTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTimeOnPageRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TimeOnPageFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> TimeOnPageResponse: + """ + Returns the average time on page over a time window — as a single aggregate value, or bucketed by day or week when `timeseries` is supplied. + + Choose how the average is computed with `metricScope` (per session, user, or pageview). Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + metric_scope : TimeOnPageMetricScope + How the average time on page is computed — per session, user, or pageview. + + timeseries : typing.Optional[TimeOnPageTimeseriesQuery] + Include bucketed average time data using the supplied granularity and IANA time zone. Omit this parameter to return a single aggregate value for the requested window. + + device_type : typing.Optional[ReportsTimeOnPageRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TimeOnPageFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TimeOnPageFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TimeOnPageResponse + Average time on page for the requested window and filters. + + Examples + -------- + import datetime + + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.analyze.reports.time_on_page( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat( + "2026-04-01 00:00:00+00:00", + ), + end_time=datetime.datetime.fromisoformat( + "2026-04-08 00:00:00+00:00", + ), + metric_scope="session", + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", + ) + """ + _response = self._raw_client.time_on_page( + site_id, + start_time=start_time, + end_time=end_time, + metric_scope=metric_scope, + timeseries=timeseries, + device_type=device_type, + country=country, + page_path=page_path, + traffic_source=traffic_source, + referrer=referrer, + browser=browser, + utm_campaign=utm_campaign, + utm_medium=utm_medium, + utm_source=utm_source, + filter=filter, + request_options=request_options, + ) + return _response.data + + +class AsyncReportsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawReportsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawReportsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawReportsClient + """ + return self._raw_client + + async def traffic( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + metric_scope: TrafficMetricScope, + bucket_time_zone: AnalyzeBucketTimeZone, + device_type: typing.Optional[ReportsTrafficRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TrafficFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> TrafficResponse: + """ + Returns a daily time series of a single metric — sessions, users, or pageviews — over a time window. + + Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + metric_scope : TrafficMetricScope + The unit each `count` data point is measured in. + + bucket_time_zone : AnalyzeBucketTimeZone + IANA time zone used to align daily bucket boundaries. + + device_type : typing.Optional[ReportsTrafficRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TrafficFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TrafficFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TrafficResponse + Time-series traffic report for the requested window and filters. + + Examples + -------- + import asyncio + import datetime + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.analyze.reports.traffic( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat( + "2026-04-01 00:00:00+00:00", + ), + end_time=datetime.datetime.fromisoformat( + "2026-04-08 00:00:00+00:00", + ), + metric_scope="session", + bucket_time_zone="America/New_York", + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.traffic( + site_id, + start_time=start_time, + end_time=end_time, + metric_scope=metric_scope, + bucket_time_zone=bucket_time_zone, + device_type=device_type, + country=country, + page_path=page_path, + traffic_source=traffic_source, + referrer=referrer, + browser=browser, + utm_campaign=utm_campaign, + utm_medium=utm_medium, + utm_source=utm_source, + filter=filter, + request_options=request_options, + ) + return _response.data + + async def top_pages( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + sort_by: typing.Optional[TopPagesSortBy] = None, + limit: typing.Optional[int] = None, + timeseries: typing.Optional[AnalyzeDailyTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTopPagesRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopPagesFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> TopPagesResponse: + """ + Returns the most-visited pages over a time window, ranked by `sortBy` (sessions, users, or pageviews). + + Each row carries all three scope counts; `sortBy` only governs ordering. Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + Set `timeseries[bucketTimeZone]` to attach a daily pageview `timeseries` to each row. Bucket counts are always pageviews regardless of `sortBy` — row-level counts honor the requested sort; the timeseries does not. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + sort_by : typing.Optional[TopPagesSortBy] + Metric used to rank rows in the response, descending. Defaults to `session`. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `250`. + + timeseries : typing.Optional[AnalyzeDailyTimeseriesQuery] + Include a daily pageview `timeseries` for each row, bucketed in the supplied IANA time zone. Omit this parameter to return ranked rows without per-page timeseries data. + + device_type : typing.Optional[ReportsTopPagesRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopPagesFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopPagesFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TopPagesResponse + Pages ranked by `sortBy` for the requested window and filters. + + Examples + -------- + import asyncio + import datetime + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.analyze.reports.top_pages( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat( + "2026-04-01 00:00:00+00:00", + ), + end_time=datetime.datetime.fromisoformat( + "2026-04-08 00:00:00+00:00", + ), + sort_by="session", + limit=1, + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.top_pages( + site_id, + start_time=start_time, + end_time=end_time, + sort_by=sort_by, + limit=limit, + timeseries=timeseries, + device_type=device_type, + country=country, + page_path=page_path, + traffic_source=traffic_source, + referrer=referrer, + browser=browser, + utm_campaign=utm_campaign, + utm_medium=utm_medium, + utm_source=utm_source, + filter=filter, + request_options=request_options, + ) + return _response.data + + async def top_dimensions( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + dimension: TopDimensionsDimension, + metric_scope: TopDimensionsMetricScope, + limit: typing.Optional[int] = None, + device_type: typing.Optional[ReportsTopDimensionsRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopDimensionsFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> TopDimensionsResponse: + """ + Returns the top values within a chosen `dimension` — top countries, top traffic sources, top campaigns, top audiences, and so on — over a time window, ranked by sessions or users. + + Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + dimension : TopDimensionsDimension + The dimension whose top values are ranked. See `TopDimensionsDimension` for the supported values. + + metric_scope : TopDimensionsMetricScope + The unit each row's `count` is measured in — sessions or users. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `100`. + + device_type : typing.Optional[ReportsTopDimensionsRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopDimensionsFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopDimensionsFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TopDimensionsResponse + Dimension values ranked by `count` for the requested window and filters. + + Examples + -------- + import asyncio + import datetime + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.analyze.reports.top_dimensions( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat( + "2026-04-01 00:00:00+00:00", + ), + end_time=datetime.datetime.fromisoformat( + "2026-04-08 00:00:00+00:00", + ), + dimension="country", + metric_scope="session", + limit=1, + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.top_dimensions( + site_id, + start_time=start_time, + end_time=end_time, + dimension=dimension, + metric_scope=metric_scope, + limit=limit, + device_type=device_type, + country=country, + page_path=page_path, + traffic_source=traffic_source, + referrer=referrer, + browser=browser, + utm_campaign=utm_campaign, + utm_medium=utm_medium, + utm_source=utm_source, + filter=filter, + request_options=request_options, + ) + return _response.data + + async def top_events( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + limit: typing.Optional[int] = None, + timeseries: typing.Optional[AnalyzeDailyTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTopEventsRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopEventsFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> TopEventsResponse: + """ + Returns the top events over a time window, ranked by how often they occurred. + + Events are counted individually, not rolled up into sessions, users, or pageviews — so this report has no `metricScope`. Each row's `count` is how many times the event occurred. Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + Set `timeseries[bucketTimeZone]` to attach a daily event count `timeseries` to each row. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `250`. + + timeseries : typing.Optional[AnalyzeDailyTimeseriesQuery] + Include a daily event count `timeseries` for each row, bucketed in the supplied IANA time zone. Omit this parameter to return ranked rows without per-event timeseries data. + + device_type : typing.Optional[ReportsTopEventsRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopEventsFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopEventsFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TopEventsResponse + Events ranked by how frequently they occurred, for the requested window and filters. + + Examples + -------- + import asyncio + import datetime + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.analyze.reports.top_events( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat( + "2026-04-01 00:00:00+00:00", + ), + end_time=datetime.datetime.fromisoformat( + "2026-04-08 00:00:00+00:00", + ), + limit=1, + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.top_events( + site_id, + start_time=start_time, + end_time=end_time, + limit=limit, + timeseries=timeseries, + device_type=device_type, + country=country, + page_path=page_path, + traffic_source=traffic_source, + browser=browser, + utm_campaign=utm_campaign, + utm_medium=utm_medium, + utm_source=utm_source, + filter=filter, + request_options=request_options, + ) + return _response.data + + async def time_on_page( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + metric_scope: TimeOnPageMetricScope, + timeseries: typing.Optional[TimeOnPageTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTimeOnPageRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TimeOnPageFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> TimeOnPageResponse: + """ + Returns the average time on page over a time window — as a single aggregate value, or bucketed by day or week when `timeseries` is supplied. + + Choose how the average is computed with `metricScope` (per session, user, or pageview). Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + metric_scope : TimeOnPageMetricScope + How the average time on page is computed — per session, user, or pageview. + + timeseries : typing.Optional[TimeOnPageTimeseriesQuery] + Include bucketed average time data using the supplied granularity and IANA time zone. Omit this parameter to return a single aggregate value for the requested window. + + device_type : typing.Optional[ReportsTimeOnPageRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TimeOnPageFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TimeOnPageFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TimeOnPageResponse + Average time on page for the requested window and filters. + + Examples + -------- + import asyncio + import datetime + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.analyze.reports.time_on_page( + site_id="580e63e98c9a982ac9b8b741", + start_time=datetime.datetime.fromisoformat( + "2026-04-01 00:00:00+00:00", + ), + end_time=datetime.datetime.fromisoformat( + "2026-04-08 00:00:00+00:00", + ), + metric_scope="session", + device_type="desktop", + country="US", + page_path="/towels", + traffic_source="SO", + referrer="google.com", + browser="Chrome", + utm_campaign="dont-panic-2026", + utm_medium="email", + utm_source="hitchhikers-guide", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.time_on_page( + site_id, + start_time=start_time, + end_time=end_time, + metric_scope=metric_scope, + timeseries=timeseries, + device_type=device_type, + country=country, + page_path=page_path, + traffic_source=traffic_source, + referrer=referrer, + browser=browser, + utm_campaign=utm_campaign, + utm_medium=utm_medium, + utm_source=utm_source, + filter=filter, + request_options=request_options, + ) + return _response.data diff --git a/src/webflow/resources/analyze/resources/reports/raw_client.py b/src/webflow/resources/analyze/resources/reports/raw_client.py new file mode 100644 index 0000000..4bd62cb --- /dev/null +++ b/src/webflow/resources/analyze/resources/reports/raw_client.py @@ -0,0 +1,2046 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing +from json.decoder import JSONDecodeError + +from .....core.api_error import ApiError +from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from .....core.datetime_utils import serialize_datetime +from .....core.http_response import AsyncHttpResponse, HttpResponse +from .....core.jsonable_encoder import jsonable_encoder +from .....core.parse_error import ParsingError +from .....core.pydantic_utilities import parse_obj_as +from .....core.request_options import RequestOptions +from .....core.serialization import convert_and_respect_annotation_metadata +from .....errors.bad_request_error import BadRequestError +from .....errors.forbidden_error import ForbiddenError +from .....errors.internal_server_error import InternalServerError +from .....errors.not_found_error import NotFoundError +from .....errors.too_many_requests_error import TooManyRequestsError +from .....errors.unauthorized_error import UnauthorizedError +from .....types.analyze_bucket_time_zone import AnalyzeBucketTimeZone +from .....types.analyze_daily_timeseries_query import AnalyzeDailyTimeseriesQuery +from .....types.error import Error +from .....types.time_on_page_filter import TimeOnPageFilter +from .....types.time_on_page_metric_scope import TimeOnPageMetricScope +from .....types.time_on_page_response import TimeOnPageResponse +from .....types.time_on_page_timeseries_query import TimeOnPageTimeseriesQuery +from .....types.top_dimensions_dimension import TopDimensionsDimension +from .....types.top_dimensions_filter import TopDimensionsFilter +from .....types.top_dimensions_metric_scope import TopDimensionsMetricScope +from .....types.top_dimensions_response import TopDimensionsResponse +from .....types.top_events_filter import TopEventsFilter +from .....types.top_events_response import TopEventsResponse +from .....types.top_pages_filter import TopPagesFilter +from .....types.top_pages_response import TopPagesResponse +from .....types.top_pages_sort_by import TopPagesSortBy +from .....types.traffic_filter import TrafficFilter +from .....types.traffic_metric_scope import TrafficMetricScope +from .....types.traffic_response import TrafficResponse +from .types.reports_time_on_page_request_device_type import ReportsTimeOnPageRequestDeviceType +from .types.reports_top_dimensions_request_device_type import ReportsTopDimensionsRequestDeviceType +from .types.reports_top_events_request_device_type import ReportsTopEventsRequestDeviceType +from .types.reports_top_pages_request_device_type import ReportsTopPagesRequestDeviceType +from .types.reports_traffic_request_device_type import ReportsTrafficRequestDeviceType +from pydantic import ValidationError + + +class RawReportsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def traffic( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + metric_scope: TrafficMetricScope, + bucket_time_zone: AnalyzeBucketTimeZone, + device_type: typing.Optional[ReportsTrafficRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TrafficFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[TrafficResponse]: + """ + Returns a daily time series of a single metric — sessions, users, or pageviews — over a time window. + + Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + metric_scope : TrafficMetricScope + The unit each `count` data point is measured in. + + bucket_time_zone : AnalyzeBucketTimeZone + IANA time zone used to align daily bucket boundaries. + + device_type : typing.Optional[ReportsTrafficRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TrafficFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TrafficFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[TrafficResponse] + Time-series traffic report for the requested window and filters. + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/analyze/reports/traffic", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "startTime": serialize_datetime(start_time), + "endTime": serialize_datetime(end_time), + "metricScope": metric_scope, + "bucketTimeZone": bucket_time_zone, + "deviceType": device_type, + "country": country, + "pagePath": page_path, + "trafficSource": traffic_source, + "referrer": referrer, + "browser": browser, + "utmCampaign": utm_campaign, + "utmMedium": utm_medium, + "utmSource": utm_source, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=TrafficFilter, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TrafficResponse, + parse_obj_as( + type_=TrafficResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def top_pages( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + sort_by: typing.Optional[TopPagesSortBy] = None, + limit: typing.Optional[int] = None, + timeseries: typing.Optional[AnalyzeDailyTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTopPagesRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopPagesFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[TopPagesResponse]: + """ + Returns the most-visited pages over a time window, ranked by `sortBy` (sessions, users, or pageviews). + + Each row carries all three scope counts; `sortBy` only governs ordering. Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + Set `timeseries[bucketTimeZone]` to attach a daily pageview `timeseries` to each row. Bucket counts are always pageviews regardless of `sortBy` — row-level counts honor the requested sort; the timeseries does not. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + sort_by : typing.Optional[TopPagesSortBy] + Metric used to rank rows in the response, descending. Defaults to `session`. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `250`. + + timeseries : typing.Optional[AnalyzeDailyTimeseriesQuery] + Include a daily pageview `timeseries` for each row, bucketed in the supplied IANA time zone. Omit this parameter to return ranked rows without per-page timeseries data. + + device_type : typing.Optional[ReportsTopPagesRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopPagesFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopPagesFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[TopPagesResponse] + Pages ranked by `sortBy` for the requested window and filters. + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/analyze/reports/top_pages", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "startTime": serialize_datetime(start_time), + "endTime": serialize_datetime(end_time), + "sortBy": sort_by, + "limit": limit, + "timeseries": convert_and_respect_annotation_metadata( + object_=timeseries, annotation=AnalyzeDailyTimeseriesQuery, direction="write" + ), + "deviceType": device_type, + "country": country, + "pagePath": page_path, + "trafficSource": traffic_source, + "referrer": referrer, + "browser": browser, + "utmCampaign": utm_campaign, + "utmMedium": utm_medium, + "utmSource": utm_source, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=TopPagesFilter, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TopPagesResponse, + parse_obj_as( + type_=TopPagesResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def top_dimensions( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + dimension: TopDimensionsDimension, + metric_scope: TopDimensionsMetricScope, + limit: typing.Optional[int] = None, + device_type: typing.Optional[ReportsTopDimensionsRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopDimensionsFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[TopDimensionsResponse]: + """ + Returns the top values within a chosen `dimension` — top countries, top traffic sources, top campaigns, top audiences, and so on — over a time window, ranked by sessions or users. + + Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + dimension : TopDimensionsDimension + The dimension whose top values are ranked. See `TopDimensionsDimension` for the supported values. + + metric_scope : TopDimensionsMetricScope + The unit each row's `count` is measured in — sessions or users. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `100`. + + device_type : typing.Optional[ReportsTopDimensionsRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopDimensionsFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopDimensionsFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[TopDimensionsResponse] + Dimension values ranked by `count` for the requested window and filters. + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/analyze/reports/top_dimensions", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "startTime": serialize_datetime(start_time), + "endTime": serialize_datetime(end_time), + "dimension": dimension, + "metricScope": metric_scope, + "limit": limit, + "deviceType": device_type, + "country": country, + "pagePath": page_path, + "trafficSource": traffic_source, + "referrer": referrer, + "browser": browser, + "utmCampaign": utm_campaign, + "utmMedium": utm_medium, + "utmSource": utm_source, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=TopDimensionsFilter, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TopDimensionsResponse, + parse_obj_as( + type_=TopDimensionsResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def top_events( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + limit: typing.Optional[int] = None, + timeseries: typing.Optional[AnalyzeDailyTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTopEventsRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopEventsFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[TopEventsResponse]: + """ + Returns the top events over a time window, ranked by how often they occurred. + + Events are counted individually, not rolled up into sessions, users, or pageviews — so this report has no `metricScope`. Each row's `count` is how many times the event occurred. Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + Set `timeseries[bucketTimeZone]` to attach a daily event count `timeseries` to each row. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `250`. + + timeseries : typing.Optional[AnalyzeDailyTimeseriesQuery] + Include a daily event count `timeseries` for each row, bucketed in the supplied IANA time zone. Omit this parameter to return ranked rows without per-event timeseries data. + + device_type : typing.Optional[ReportsTopEventsRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopEventsFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopEventsFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[TopEventsResponse] + Events ranked by how frequently they occurred, for the requested window and filters. + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/analyze/reports/top_events", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "startTime": serialize_datetime(start_time), + "endTime": serialize_datetime(end_time), + "limit": limit, + "timeseries": convert_and_respect_annotation_metadata( + object_=timeseries, annotation=AnalyzeDailyTimeseriesQuery, direction="write" + ), + "deviceType": device_type, + "country": country, + "pagePath": page_path, + "trafficSource": traffic_source, + "browser": browser, + "utmCampaign": utm_campaign, + "utmMedium": utm_medium, + "utmSource": utm_source, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=TopEventsFilter, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TopEventsResponse, + parse_obj_as( + type_=TopEventsResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def time_on_page( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + metric_scope: TimeOnPageMetricScope, + timeseries: typing.Optional[TimeOnPageTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTimeOnPageRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TimeOnPageFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[TimeOnPageResponse]: + """ + Returns the average time on page over a time window — as a single aggregate value, or bucketed by day or week when `timeseries` is supplied. + + Choose how the average is computed with `metricScope` (per session, user, or pageview). Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + metric_scope : TimeOnPageMetricScope + How the average time on page is computed — per session, user, or pageview. + + timeseries : typing.Optional[TimeOnPageTimeseriesQuery] + Include bucketed average time data using the supplied granularity and IANA time zone. Omit this parameter to return a single aggregate value for the requested window. + + device_type : typing.Optional[ReportsTimeOnPageRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TimeOnPageFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TimeOnPageFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[TimeOnPageResponse] + Average time on page for the requested window and filters. + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/analyze/reports/time_on_page", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "startTime": serialize_datetime(start_time), + "endTime": serialize_datetime(end_time), + "metricScope": metric_scope, + "timeseries": convert_and_respect_annotation_metadata( + object_=timeseries, annotation=TimeOnPageTimeseriesQuery, direction="write" + ), + "deviceType": device_type, + "country": country, + "pagePath": page_path, + "trafficSource": traffic_source, + "referrer": referrer, + "browser": browser, + "utmCampaign": utm_campaign, + "utmMedium": utm_medium, + "utmSource": utm_source, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=TimeOnPageFilter, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TimeOnPageResponse, + parse_obj_as( + type_=TimeOnPageResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + +class AsyncRawReportsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def traffic( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + metric_scope: TrafficMetricScope, + bucket_time_zone: AnalyzeBucketTimeZone, + device_type: typing.Optional[ReportsTrafficRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TrafficFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[TrafficResponse]: + """ + Returns a daily time series of a single metric — sessions, users, or pageviews — over a time window. + + Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + metric_scope : TrafficMetricScope + The unit each `count` data point is measured in. + + bucket_time_zone : AnalyzeBucketTimeZone + IANA time zone used to align daily bucket boundaries. + + device_type : typing.Optional[ReportsTrafficRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TrafficFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TrafficFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[TrafficResponse] + Time-series traffic report for the requested window and filters. + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/analyze/reports/traffic", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "startTime": serialize_datetime(start_time), + "endTime": serialize_datetime(end_time), + "metricScope": metric_scope, + "bucketTimeZone": bucket_time_zone, + "deviceType": device_type, + "country": country, + "pagePath": page_path, + "trafficSource": traffic_source, + "referrer": referrer, + "browser": browser, + "utmCampaign": utm_campaign, + "utmMedium": utm_medium, + "utmSource": utm_source, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=TrafficFilter, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TrafficResponse, + parse_obj_as( + type_=TrafficResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def top_pages( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + sort_by: typing.Optional[TopPagesSortBy] = None, + limit: typing.Optional[int] = None, + timeseries: typing.Optional[AnalyzeDailyTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTopPagesRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopPagesFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[TopPagesResponse]: + """ + Returns the most-visited pages over a time window, ranked by `sortBy` (sessions, users, or pageviews). + + Each row carries all three scope counts; `sortBy` only governs ordering. Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + Set `timeseries[bucketTimeZone]` to attach a daily pageview `timeseries` to each row. Bucket counts are always pageviews regardless of `sortBy` — row-level counts honor the requested sort; the timeseries does not. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + sort_by : typing.Optional[TopPagesSortBy] + Metric used to rank rows in the response, descending. Defaults to `session`. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `250`. + + timeseries : typing.Optional[AnalyzeDailyTimeseriesQuery] + Include a daily pageview `timeseries` for each row, bucketed in the supplied IANA time zone. Omit this parameter to return ranked rows without per-page timeseries data. + + device_type : typing.Optional[ReportsTopPagesRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopPagesFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopPagesFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[TopPagesResponse] + Pages ranked by `sortBy` for the requested window and filters. + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/analyze/reports/top_pages", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "startTime": serialize_datetime(start_time), + "endTime": serialize_datetime(end_time), + "sortBy": sort_by, + "limit": limit, + "timeseries": convert_and_respect_annotation_metadata( + object_=timeseries, annotation=AnalyzeDailyTimeseriesQuery, direction="write" + ), + "deviceType": device_type, + "country": country, + "pagePath": page_path, + "trafficSource": traffic_source, + "referrer": referrer, + "browser": browser, + "utmCampaign": utm_campaign, + "utmMedium": utm_medium, + "utmSource": utm_source, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=TopPagesFilter, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TopPagesResponse, + parse_obj_as( + type_=TopPagesResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def top_dimensions( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + dimension: TopDimensionsDimension, + metric_scope: TopDimensionsMetricScope, + limit: typing.Optional[int] = None, + device_type: typing.Optional[ReportsTopDimensionsRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopDimensionsFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[TopDimensionsResponse]: + """ + Returns the top values within a chosen `dimension` — top countries, top traffic sources, top campaigns, top audiences, and so on — over a time window, ranked by sessions or users. + + Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + dimension : TopDimensionsDimension + The dimension whose top values are ranked. See `TopDimensionsDimension` for the supported values. + + metric_scope : TopDimensionsMetricScope + The unit each row's `count` is measured in — sessions or users. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `100`. + + device_type : typing.Optional[ReportsTopDimensionsRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopDimensionsFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopDimensionsFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[TopDimensionsResponse] + Dimension values ranked by `count` for the requested window and filters. + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/analyze/reports/top_dimensions", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "startTime": serialize_datetime(start_time), + "endTime": serialize_datetime(end_time), + "dimension": dimension, + "metricScope": metric_scope, + "limit": limit, + "deviceType": device_type, + "country": country, + "pagePath": page_path, + "trafficSource": traffic_source, + "referrer": referrer, + "browser": browser, + "utmCampaign": utm_campaign, + "utmMedium": utm_medium, + "utmSource": utm_source, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=TopDimensionsFilter, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TopDimensionsResponse, + parse_obj_as( + type_=TopDimensionsResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def top_events( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + limit: typing.Optional[int] = None, + timeseries: typing.Optional[AnalyzeDailyTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTopEventsRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TopEventsFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[TopEventsResponse]: + """ + Returns the top events over a time window, ranked by how often they occurred. + + Events are counted individually, not rolled up into sessions, users, or pageviews — so this report has no `metricScope`. Each row's `count` is how many times the event occurred. Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + Set `timeseries[bucketTimeZone]` to attach a daily event count `timeseries` to each row. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + limit : typing.Optional[int] + Maximum number of rows to return. Defaults to `25`, up to a maximum of `250`. + + timeseries : typing.Optional[AnalyzeDailyTimeseriesQuery] + Include a daily event count `timeseries` for each row, bucketed in the supplied IANA time zone. Omit this parameter to return ranked rows without per-event timeseries data. + + device_type : typing.Optional[ReportsTopEventsRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TopEventsFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TopEventsFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[TopEventsResponse] + Events ranked by how frequently they occurred, for the requested window and filters. + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/analyze/reports/top_events", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "startTime": serialize_datetime(start_time), + "endTime": serialize_datetime(end_time), + "limit": limit, + "timeseries": convert_and_respect_annotation_metadata( + object_=timeseries, annotation=AnalyzeDailyTimeseriesQuery, direction="write" + ), + "deviceType": device_type, + "country": country, + "pagePath": page_path, + "trafficSource": traffic_source, + "browser": browser, + "utmCampaign": utm_campaign, + "utmMedium": utm_medium, + "utmSource": utm_source, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=TopEventsFilter, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TopEventsResponse, + parse_obj_as( + type_=TopEventsResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def time_on_page( + self, + site_id: str, + *, + start_time: dt.datetime, + end_time: dt.datetime, + metric_scope: TimeOnPageMetricScope, + timeseries: typing.Optional[TimeOnPageTimeseriesQuery] = None, + device_type: typing.Optional[ReportsTimeOnPageRequestDeviceType] = None, + country: typing.Optional[str] = None, + page_path: typing.Optional[str] = None, + traffic_source: typing.Optional[str] = None, + referrer: typing.Optional[str] = None, + browser: typing.Optional[str] = None, + utm_campaign: typing.Optional[str] = None, + utm_medium: typing.Optional[str] = None, + utm_source: typing.Optional[str] = None, + filter: typing.Optional[TimeOnPageFilter] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[TimeOnPageResponse]: + """ + Returns the average time on page over a time window — as a single aggregate value, or bucketed by day or week when `timeseries` is supplied. + + Choose how the average is computed with `metricScope` (per session, user, or pageview). Filter the report with top-level query parameters (`country`, `deviceType`, `pagePath`, etc.) or via the `filter` parameter for multi-value and negation matching. + + This endpoint requires a workspace with the Analyze add-on. + + Each access token can have one Analyze request in flight at a time, across all Analyze endpoints. Additional concurrent requests return `429 Too Many Requests`; wait for your in-flight request to finish, or for the `Retry-After` interval, then retry. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + start_time : dt.datetime + Inclusive start of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-01T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be on or after `2025-04-09T00:00:00Z`. + + end_time : dt.datetime + Exclusive end of the reporting window. Must be a UTC timestamp in ISO 8601 / RFC 3339 format ending in `Z` (for example, `2026-04-08T00:00:00Z`); numeric offsets such as `-04:00` or `+00:00` are not accepted. Must be greater than `startTime` and within 100 days of it. + + metric_scope : TimeOnPageMetricScope + How the average time on page is computed — per session, user, or pageview. + + timeseries : typing.Optional[TimeOnPageTimeseriesQuery] + Include bucketed average time data using the supplied granularity and IANA time zone. Omit this parameter to return a single aggregate value for the requested window. + + device_type : typing.Optional[ReportsTimeOnPageRequestDeviceType] + Restrict the report to a single device type. + + country : typing.Optional[str] + Restrict the report to a single country. ISO 3166-1 alpha-2 (two letters, normalized to uppercase). + + page_path : typing.Optional[str] + Restrict the report to a single page path. + + traffic_source : typing.Optional[str] + Restrict the report to a single traffic source code (for example, `SO` for Organic Search). + + referrer : typing.Optional[str] + Restrict the report to a single referrer domain. + + browser : typing.Optional[str] + Restrict the report to a single browser. + + utm_campaign : typing.Optional[str] + Restrict the report to a single `utm_campaign` value. + + utm_medium : typing.Optional[str] + Restrict the report to a single `utm_medium` value. + + utm_source : typing.Optional[str] + Restrict the report to a single `utm_source` value. + + filter : typing.Optional[TimeOnPageFilter] + Filter the report by dimension. Use bracket notation. Scalars take a single value (`filter[country][eq]=US`, `filter[country][ne]=US`). Arrays use indexed brackets (`filter[country][in][0]=US&filter[country][in][1]=CA`, `filter[country][nin][0]=US&filter[country][nin][1]=CA`). + Each dimension entry takes at least one of `eq`, `in`, `ne`, or `nin`. Filter a given dimension in one place — either a top-level query parameter or a `filter` entry. See the `TimeOnPageFilter` schema for the full list of supported dimensions. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[TimeOnPageResponse] + Average time on page for the requested window and filters. + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/analyze/reports/time_on_page", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "startTime": serialize_datetime(start_time), + "endTime": serialize_datetime(end_time), + "metricScope": metric_scope, + "timeseries": convert_and_respect_annotation_metadata( + object_=timeseries, annotation=TimeOnPageTimeseriesQuery, direction="write" + ), + "deviceType": device_type, + "country": country, + "pagePath": page_path, + "trafficSource": traffic_source, + "referrer": referrer, + "browser": browser, + "utmCampaign": utm_campaign, + "utmMedium": utm_medium, + "utmSource": utm_source, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=TimeOnPageFilter, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TimeOnPageResponse, + parse_obj_as( + type_=TimeOnPageResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) diff --git a/src/webflow/resources/analyze/resources/reports/types/__init__.py b/src/webflow/resources/analyze/resources/reports/types/__init__.py new file mode 100644 index 0000000..7418236 --- /dev/null +++ b/src/webflow/resources/analyze/resources/reports/types/__init__.py @@ -0,0 +1,50 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .reports_time_on_page_request_device_type import ReportsTimeOnPageRequestDeviceType + from .reports_top_dimensions_request_device_type import ReportsTopDimensionsRequestDeviceType + from .reports_top_events_request_device_type import ReportsTopEventsRequestDeviceType + from .reports_top_pages_request_device_type import ReportsTopPagesRequestDeviceType + from .reports_traffic_request_device_type import ReportsTrafficRequestDeviceType +_dynamic_imports: typing.Dict[str, str] = { + "ReportsTimeOnPageRequestDeviceType": ".reports_time_on_page_request_device_type", + "ReportsTopDimensionsRequestDeviceType": ".reports_top_dimensions_request_device_type", + "ReportsTopEventsRequestDeviceType": ".reports_top_events_request_device_type", + "ReportsTopPagesRequestDeviceType": ".reports_top_pages_request_device_type", + "ReportsTrafficRequestDeviceType": ".reports_traffic_request_device_type", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "ReportsTimeOnPageRequestDeviceType", + "ReportsTopDimensionsRequestDeviceType", + "ReportsTopEventsRequestDeviceType", + "ReportsTopPagesRequestDeviceType", + "ReportsTrafficRequestDeviceType", +] diff --git a/src/webflow/resources/analyze/resources/reports/types/reports_time_on_page_request_device_type.py b/src/webflow/resources/analyze/resources/reports/types/reports_time_on_page_request_device_type.py new file mode 100644 index 0000000..26062d3 --- /dev/null +++ b/src/webflow/resources/analyze/resources/reports/types/reports_time_on_page_request_device_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ReportsTimeOnPageRequestDeviceType = typing.Union[typing.Literal["desktop", "mobile", "tablet"], typing.Any] diff --git a/src/webflow/resources/analyze/resources/reports/types/reports_top_dimensions_request_device_type.py b/src/webflow/resources/analyze/resources/reports/types/reports_top_dimensions_request_device_type.py new file mode 100644 index 0000000..be53022 --- /dev/null +++ b/src/webflow/resources/analyze/resources/reports/types/reports_top_dimensions_request_device_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ReportsTopDimensionsRequestDeviceType = typing.Union[typing.Literal["desktop", "mobile", "tablet"], typing.Any] diff --git a/src/webflow/resources/analyze/resources/reports/types/reports_top_events_request_device_type.py b/src/webflow/resources/analyze/resources/reports/types/reports_top_events_request_device_type.py new file mode 100644 index 0000000..05592a4 --- /dev/null +++ b/src/webflow/resources/analyze/resources/reports/types/reports_top_events_request_device_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ReportsTopEventsRequestDeviceType = typing.Union[typing.Literal["desktop", "mobile", "tablet"], typing.Any] diff --git a/src/webflow/resources/analyze/resources/reports/types/reports_top_pages_request_device_type.py b/src/webflow/resources/analyze/resources/reports/types/reports_top_pages_request_device_type.py new file mode 100644 index 0000000..e9a70a5 --- /dev/null +++ b/src/webflow/resources/analyze/resources/reports/types/reports_top_pages_request_device_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ReportsTopPagesRequestDeviceType = typing.Union[typing.Literal["desktop", "mobile", "tablet"], typing.Any] diff --git a/src/webflow/resources/analyze/resources/reports/types/reports_traffic_request_device_type.py b/src/webflow/resources/analyze/resources/reports/types/reports_traffic_request_device_type.py new file mode 100644 index 0000000..0b1fd97 --- /dev/null +++ b/src/webflow/resources/analyze/resources/reports/types/reports_traffic_request_device_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ReportsTrafficRequestDeviceType = typing.Union[typing.Literal["desktop", "mobile", "tablet"], typing.Any] diff --git a/src/webflow/resources/assets/client.py b/src/webflow/resources/assets/client.py index ae22ab4..9f533e4 100644 --- a/src/webflow/resources/assets/client.py +++ b/src/webflow/resources/assets/client.py @@ -34,8 +34,10 @@ def list( self, site_id: str, *, + locale_id: typing.Optional[str] = None, offset: typing.Optional[int] = None, limit: typing.Optional[int] = None, + folder_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> Assets: """ @@ -48,12 +50,21 @@ def list( site_id : str Unique identifier for a Site + locale_id : typing.Optional[str] + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + offset : typing.Optional[int] Offset used for pagination if the results have more than limit records limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) + folder_id : typing.Optional[str] + Filter assets to those in the specified folder and all descendant folders. + Must be a 24-character hex ObjectId. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -71,11 +82,20 @@ def list( ) client.assets.list( site_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", offset=1, limit=1, + folder_id="folderId", ) """ - _response = self._raw_client.list(site_id, offset=offset, limit=limit, request_options=request_options) + _response = self._raw_client.list( + site_id, + locale_id=locale_id, + offset=offset, + limit=limit, + folder_id=folder_id, + request_options=request_options, + ) return _response.data def create( @@ -145,7 +165,13 @@ def create( ) return _response.data - def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Asset: + def get( + self, + asset_id: str, + *, + locale_id: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> Asset: """ Get details about an asset @@ -156,6 +182,11 @@ def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] asset_id : str Unique identifier for an Asset on a site + locale_id : typing.Optional[str] + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -173,9 +204,10 @@ def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] ) client.assets.get( asset_id="580e63fc8c9a982ac9b8b745", + locale_id="65427cf400e02b306eaa04a0", ) """ - _response = self._raw_client.get(asset_id, request_options=request_options) + _response = self._raw_client.get(asset_id, locale_id=locale_id, request_options=request_options) return _response.data def delete(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: @@ -214,8 +246,9 @@ def update( self, asset_id: str, *, - locale_id: typing.Optional[str] = OMIT, + locale_id: typing.Optional[str] = None, display_name: typing.Optional[str] = OMIT, + alt_text: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> Asset: """ @@ -229,10 +262,15 @@ def update( Unique identifier for an Asset on a site locale_id : typing.Optional[str] - Unique identifier for a specific locale. Applicable, when using localization. + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) display_name : typing.Optional[str] - A human readable name for the asset + A human readable name for the asset. This value is not localizable. + + alt_text : typing.Optional[str] + Alternate text describing the image request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -251,10 +289,11 @@ def update( ) client.assets.update( asset_id="580e63fc8c9a982ac9b8b745", + locale_id="65427cf400e02b306eaa04a0", ) """ _response = self._raw_client.update( - asset_id, locale_id=locale_id, display_name=display_name, request_options=request_options + asset_id, locale_id=locale_id, display_name=display_name, alt_text=alt_text, request_options=request_options ) return _response.data @@ -395,8 +434,10 @@ async def list( self, site_id: str, *, + locale_id: typing.Optional[str] = None, offset: typing.Optional[int] = None, limit: typing.Optional[int] = None, + folder_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> Assets: """ @@ -409,12 +450,21 @@ async def list( site_id : str Unique identifier for a Site + locale_id : typing.Optional[str] + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + offset : typing.Optional[int] Offset used for pagination if the results have more than limit records limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) + folder_id : typing.Optional[str] + Filter assets to those in the specified folder and all descendant folders. + Must be a 24-character hex ObjectId. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -437,14 +487,23 @@ async def list( async def main() -> None: await client.assets.list( site_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", offset=1, limit=1, + folder_id="folderId", ) asyncio.run(main()) """ - _response = await self._raw_client.list(site_id, offset=offset, limit=limit, request_options=request_options) + _response = await self._raw_client.list( + site_id, + locale_id=locale_id, + offset=offset, + limit=limit, + folder_id=folder_id, + request_options=request_options, + ) return _response.data async def create( @@ -522,7 +581,13 @@ async def main() -> None: ) return _response.data - async def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Asset: + async def get( + self, + asset_id: str, + *, + locale_id: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> Asset: """ Get details about an asset @@ -533,6 +598,11 @@ async def get(self, asset_id: str, *, request_options: typing.Optional[RequestOp asset_id : str Unique identifier for an Asset on a site + locale_id : typing.Optional[str] + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -555,12 +625,13 @@ async def get(self, asset_id: str, *, request_options: typing.Optional[RequestOp async def main() -> None: await client.assets.get( asset_id="580e63fc8c9a982ac9b8b745", + locale_id="65427cf400e02b306eaa04a0", ) asyncio.run(main()) """ - _response = await self._raw_client.get(asset_id, request_options=request_options) + _response = await self._raw_client.get(asset_id, locale_id=locale_id, request_options=request_options) return _response.data async def delete(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: @@ -607,8 +678,9 @@ async def update( self, asset_id: str, *, - locale_id: typing.Optional[str] = OMIT, + locale_id: typing.Optional[str] = None, display_name: typing.Optional[str] = OMIT, + alt_text: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> Asset: """ @@ -622,10 +694,15 @@ async def update( Unique identifier for an Asset on a site locale_id : typing.Optional[str] - Unique identifier for a specific locale. Applicable, when using localization. + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) display_name : typing.Optional[str] - A human readable name for the asset + A human readable name for the asset. This value is not localizable. + + alt_text : typing.Optional[str] + Alternate text describing the image request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -649,13 +726,14 @@ async def update( async def main() -> None: await client.assets.update( asset_id="580e63fc8c9a982ac9b8b745", + locale_id="65427cf400e02b306eaa04a0", ) asyncio.run(main()) """ _response = await self._raw_client.update( - asset_id, locale_id=locale_id, display_name=display_name, request_options=request_options + asset_id, locale_id=locale_id, display_name=display_name, alt_text=alt_text, request_options=request_options ) return _response.data diff --git a/src/webflow/resources/assets/raw_client.py b/src/webflow/resources/assets/raw_client.py index 5c99d98..bb22d65 100644 --- a/src/webflow/resources/assets/raw_client.py +++ b/src/webflow/resources/assets/raw_client.py @@ -35,8 +35,10 @@ def list( self, site_id: str, *, + locale_id: typing.Optional[str] = None, offset: typing.Optional[int] = None, limit: typing.Optional[int] = None, + folder_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[Assets]: """ @@ -49,12 +51,21 @@ def list( site_id : str Unique identifier for a Site + locale_id : typing.Optional[str] + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + offset : typing.Optional[int] Offset used for pagination if the results have more than limit records limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) + folder_id : typing.Optional[str] + Filter assets to those in the specified folder and all descendant folders. + Must be a 24-character hex ObjectId. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -68,8 +79,10 @@ def list( base_url=self._client_wrapper.get_environment().base, method="GET", params={ + "localeId": locale_id, "offset": offset, "limit": limit, + "folderId": folder_id, }, request_options=request_options, ) @@ -281,7 +294,13 @@ def create( ) raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) - def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Asset]: + def get( + self, + asset_id: str, + *, + locale_id: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Asset]: """ Get details about an asset @@ -292,6 +311,11 @@ def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] asset_id : str Unique identifier for an Asset on a site + locale_id : typing.Optional[str] + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -304,6 +328,9 @@ def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] f"assets/{jsonable_encoder(asset_id)}", base_url=self._client_wrapper.get_environment().base, method="GET", + params={ + "localeId": locale_id, + }, request_options=request_options, ) try: @@ -475,8 +502,9 @@ def update( self, asset_id: str, *, - locale_id: typing.Optional[str] = OMIT, + locale_id: typing.Optional[str] = None, display_name: typing.Optional[str] = OMIT, + alt_text: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[Asset]: """ @@ -490,10 +518,15 @@ def update( Unique identifier for an Asset on a site locale_id : typing.Optional[str] - Unique identifier for a specific locale. Applicable, when using localization. + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) display_name : typing.Optional[str] - A human readable name for the asset + A human readable name for the asset. This value is not localizable. + + alt_text : typing.Optional[str] + Alternate text describing the image request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -507,9 +540,12 @@ def update( f"assets/{jsonable_encoder(asset_id)}", base_url=self._client_wrapper.get_environment().base, method="PATCH", - json={ + params={ "localeId": locale_id, + }, + json={ "displayName": display_name, + "altText": alt_text, }, headers={ "content-type": "application/json", @@ -922,8 +958,10 @@ async def list( self, site_id: str, *, + locale_id: typing.Optional[str] = None, offset: typing.Optional[int] = None, limit: typing.Optional[int] = None, + folder_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[Assets]: """ @@ -936,12 +974,21 @@ async def list( site_id : str Unique identifier for a Site + locale_id : typing.Optional[str] + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + offset : typing.Optional[int] Offset used for pagination if the results have more than limit records limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) + folder_id : typing.Optional[str] + Filter assets to those in the specified folder and all descendant folders. + Must be a 24-character hex ObjectId. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -955,8 +1002,10 @@ async def list( base_url=self._client_wrapper.get_environment().base, method="GET", params={ + "localeId": locale_id, "offset": offset, "limit": limit, + "folderId": folder_id, }, request_options=request_options, ) @@ -1169,7 +1218,11 @@ async def create( raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) async def get( - self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None + self, + asset_id: str, + *, + locale_id: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[Asset]: """ Get details about an asset @@ -1181,6 +1234,11 @@ async def get( asset_id : str Unique identifier for an Asset on a site + locale_id : typing.Optional[str] + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1193,6 +1251,9 @@ async def get( f"assets/{jsonable_encoder(asset_id)}", base_url=self._client_wrapper.get_environment().base, method="GET", + params={ + "localeId": locale_id, + }, request_options=request_options, ) try: @@ -1366,8 +1427,9 @@ async def update( self, asset_id: str, *, - locale_id: typing.Optional[str] = OMIT, + locale_id: typing.Optional[str] = None, display_name: typing.Optional[str] = OMIT, + alt_text: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[Asset]: """ @@ -1381,10 +1443,15 @@ async def update( Unique identifier for an Asset on a site locale_id : typing.Optional[str] - Unique identifier for a specific locale. Applicable, when using localization. + Unique identifier for a specific Locale. + + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) display_name : typing.Optional[str] - A human readable name for the asset + A human readable name for the asset. This value is not localizable. + + alt_text : typing.Optional[str] + Alternate text describing the image request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1398,9 +1465,12 @@ async def update( f"assets/{jsonable_encoder(asset_id)}", base_url=self._client_wrapper.get_environment().base, method="PATCH", - json={ + params={ "localeId": locale_id, + }, + json={ "displayName": display_name, + "altText": alt_text, }, headers={ "content-type": "application/json", diff --git a/src/webflow/resources/collections/resources/fields/raw_client.py b/src/webflow/resources/collections/resources/fields/raw_client.py index 31f26be..cc819d1 100644 --- a/src/webflow/resources/collections/resources/fields/raw_client.py +++ b/src/webflow/resources/collections/resources/fields/raw_client.py @@ -62,9 +62,6 @@ def create( base_url=self._client_wrapper.get_environment().base, method="POST", json=convert_and_respect_annotation_metadata(object_=request, annotation=FieldCreate, direction="write"), - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -415,9 +412,6 @@ async def create( base_url=self._client_wrapper.get_environment().base, method="POST", json=convert_and_respect_annotation_metadata(object_=request, annotation=FieldCreate, direction="write"), - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) diff --git a/src/webflow/resources/collections/resources/items/client.py b/src/webflow/resources/collections/resources/items/client.py index 16f1d5c..4606299 100644 --- a/src/webflow/resources/collections/resources/items/client.py +++ b/src/webflow/resources/collections/resources/items/client.py @@ -10,8 +10,12 @@ from .....types.collection_item_list_no_pagination import CollectionItemListNoPagination from .....types.collection_item_patch_single_field_data import CollectionItemPatchSingleFieldData from .....types.collection_item_with_id_input import CollectionItemWithIdInput +from .....types.items_list_items_live_request_created_on import ItemsListItemsLiveRequestCreatedOn from .....types.items_list_items_live_request_last_published import ItemsListItemsLiveRequestLastPublished +from .....types.items_list_items_live_request_last_updated import ItemsListItemsLiveRequestLastUpdated +from .....types.items_list_items_request_created_on import ItemsListItemsRequestCreatedOn from .....types.items_list_items_request_last_published import ItemsListItemsRequestLastPublished +from .....types.items_list_items_request_last_updated import ItemsListItemsRequestLastUpdated from .raw_client import AsyncRawItemsClient, RawItemsClient from .types.create_bulk_collection_item_request_body_field_data import CreateBulkCollectionItemRequestBodyFieldData from .types.items_create_item_live_request_body import ItemsCreateItemLiveRequestBody @@ -54,7 +58,9 @@ def list_items( limit: typing.Optional[int] = None, name: typing.Optional[str] = None, slug: typing.Optional[str] = None, + created_on: typing.Optional[ItemsListItemsRequestCreatedOn] = None, last_published: typing.Optional[ItemsListItemsRequestLastPublished] = None, + last_updated: typing.Optional[ItemsListItemsRequestLastUpdated] = None, sort_by: typing.Optional[ItemsListItemsRequestSortBy] = None, sort_order: typing.Optional[ItemsListItemsRequestSortOrder] = None, request_options: typing.Optional[RequestOptions] = None, @@ -84,9 +90,15 @@ def list_items( slug : typing.Optional[str] Filter by the exact slug of the item + created_on : typing.Optional[ItemsListItemsRequestCreatedOn] + Filter by the creation date of the item(s) + last_published : typing.Optional[ItemsListItemsRequestLastPublished] Filter by the last published date of the item(s) + last_updated : typing.Optional[ItemsListItemsRequestLastUpdated] + Filter by the last updated date of the item(s) + sort_by : typing.Optional[ItemsListItemsRequestSortBy] Sort results by the provided value @@ -115,7 +127,7 @@ def list_items( limit=1, name="name", slug="slug", - sort_by="lastPublished", + sort_by="createdOn", sort_order="asc", ) """ @@ -126,7 +138,9 @@ def list_items( limit=limit, name=name, slug=slug, + created_on=created_on, last_published=last_published, + last_updated=last_updated, sort_by=sort_by, sort_order=sort_order, request_options=request_options, @@ -345,7 +359,9 @@ def list_items_live( limit: typing.Optional[int] = None, name: typing.Optional[str] = None, slug: typing.Optional[str] = None, + created_on: typing.Optional[ItemsListItemsLiveRequestCreatedOn] = None, last_published: typing.Optional[ItemsListItemsLiveRequestLastPublished] = None, + last_updated: typing.Optional[ItemsListItemsLiveRequestLastUpdated] = None, sort_by: typing.Optional[ItemsListItemsLiveRequestSortBy] = None, sort_order: typing.Optional[ItemsListItemsLiveRequestSortOrder] = None, request_options: typing.Optional[RequestOptions] = None, @@ -379,9 +395,15 @@ def list_items_live( slug : typing.Optional[str] Filter by the exact slug of the item + created_on : typing.Optional[ItemsListItemsLiveRequestCreatedOn] + Filter by the creation date of the item(s) + last_published : typing.Optional[ItemsListItemsLiveRequestLastPublished] Filter by the last published date of the item(s) + last_updated : typing.Optional[ItemsListItemsLiveRequestLastUpdated] + Filter by the last updated date of the item(s) + sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy] Sort results by the provided value @@ -410,7 +432,7 @@ def list_items_live( limit=1, name="name", slug="slug", - sort_by="lastPublished", + sort_by="createdOn", sort_order="asc", ) """ @@ -421,7 +443,9 @@ def list_items_live( limit=limit, name=name, slug=slug, + created_on=created_on, last_published=last_published, + last_updated=last_updated, sort_by=sort_by, sort_order=sort_order, request_options=request_options, @@ -1183,7 +1207,9 @@ async def list_items( limit: typing.Optional[int] = None, name: typing.Optional[str] = None, slug: typing.Optional[str] = None, + created_on: typing.Optional[ItemsListItemsRequestCreatedOn] = None, last_published: typing.Optional[ItemsListItemsRequestLastPublished] = None, + last_updated: typing.Optional[ItemsListItemsRequestLastUpdated] = None, sort_by: typing.Optional[ItemsListItemsRequestSortBy] = None, sort_order: typing.Optional[ItemsListItemsRequestSortOrder] = None, request_options: typing.Optional[RequestOptions] = None, @@ -1213,9 +1239,15 @@ async def list_items( slug : typing.Optional[str] Filter by the exact slug of the item + created_on : typing.Optional[ItemsListItemsRequestCreatedOn] + Filter by the creation date of the item(s) + last_published : typing.Optional[ItemsListItemsRequestLastPublished] Filter by the last published date of the item(s) + last_updated : typing.Optional[ItemsListItemsRequestLastUpdated] + Filter by the last updated date of the item(s) + sort_by : typing.Optional[ItemsListItemsRequestSortBy] Sort results by the provided value @@ -1249,7 +1281,7 @@ async def main() -> None: limit=1, name="name", slug="slug", - sort_by="lastPublished", + sort_by="createdOn", sort_order="asc", ) @@ -1263,7 +1295,9 @@ async def main() -> None: limit=limit, name=name, slug=slug, + created_on=created_on, last_published=last_published, + last_updated=last_updated, sort_by=sort_by, sort_order=sort_order, request_options=request_options, @@ -1506,7 +1540,9 @@ async def list_items_live( limit: typing.Optional[int] = None, name: typing.Optional[str] = None, slug: typing.Optional[str] = None, + created_on: typing.Optional[ItemsListItemsLiveRequestCreatedOn] = None, last_published: typing.Optional[ItemsListItemsLiveRequestLastPublished] = None, + last_updated: typing.Optional[ItemsListItemsLiveRequestLastUpdated] = None, sort_by: typing.Optional[ItemsListItemsLiveRequestSortBy] = None, sort_order: typing.Optional[ItemsListItemsLiveRequestSortOrder] = None, request_options: typing.Optional[RequestOptions] = None, @@ -1540,9 +1576,15 @@ async def list_items_live( slug : typing.Optional[str] Filter by the exact slug of the item + created_on : typing.Optional[ItemsListItemsLiveRequestCreatedOn] + Filter by the creation date of the item(s) + last_published : typing.Optional[ItemsListItemsLiveRequestLastPublished] Filter by the last published date of the item(s) + last_updated : typing.Optional[ItemsListItemsLiveRequestLastUpdated] + Filter by the last updated date of the item(s) + sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy] Sort results by the provided value @@ -1576,7 +1618,7 @@ async def main() -> None: limit=1, name="name", slug="slug", - sort_by="lastPublished", + sort_by="createdOn", sort_order="asc", ) @@ -1590,7 +1632,9 @@ async def main() -> None: limit=limit, name=name, slug=slug, + created_on=created_on, last_published=last_published, + last_updated=last_updated, sort_by=sort_by, sort_order=sort_order, request_options=request_options, diff --git a/src/webflow/resources/collections/resources/items/raw_client.py b/src/webflow/resources/collections/resources/items/raw_client.py index 010bbfd..1051bab 100644 --- a/src/webflow/resources/collections/resources/items/raw_client.py +++ b/src/webflow/resources/collections/resources/items/raw_client.py @@ -24,8 +24,12 @@ from .....types.collection_item_patch_single_field_data import CollectionItemPatchSingleFieldData from .....types.collection_item_with_id_input import CollectionItemWithIdInput from .....types.error import Error +from .....types.items_list_items_live_request_created_on import ItemsListItemsLiveRequestCreatedOn from .....types.items_list_items_live_request_last_published import ItemsListItemsLiveRequestLastPublished +from .....types.items_list_items_live_request_last_updated import ItemsListItemsLiveRequestLastUpdated +from .....types.items_list_items_request_created_on import ItemsListItemsRequestCreatedOn from .....types.items_list_items_request_last_published import ItemsListItemsRequestLastPublished +from .....types.items_list_items_request_last_updated import ItemsListItemsRequestLastUpdated from .types.create_bulk_collection_item_request_body_field_data import CreateBulkCollectionItemRequestBodyFieldData from .types.items_create_item_live_request_body import ItemsCreateItemLiveRequestBody from .types.items_create_item_request_body import ItemsCreateItemRequestBody @@ -57,7 +61,9 @@ def list_items( limit: typing.Optional[int] = None, name: typing.Optional[str] = None, slug: typing.Optional[str] = None, + created_on: typing.Optional[ItemsListItemsRequestCreatedOn] = None, last_published: typing.Optional[ItemsListItemsRequestLastPublished] = None, + last_updated: typing.Optional[ItemsListItemsRequestLastUpdated] = None, sort_by: typing.Optional[ItemsListItemsRequestSortBy] = None, sort_order: typing.Optional[ItemsListItemsRequestSortOrder] = None, request_options: typing.Optional[RequestOptions] = None, @@ -87,9 +93,15 @@ def list_items( slug : typing.Optional[str] Filter by the exact slug of the item + created_on : typing.Optional[ItemsListItemsRequestCreatedOn] + Filter by the creation date of the item(s) + last_published : typing.Optional[ItemsListItemsRequestLastPublished] Filter by the last published date of the item(s) + last_updated : typing.Optional[ItemsListItemsRequestLastUpdated] + Filter by the last updated date of the item(s) + sort_by : typing.Optional[ItemsListItemsRequestSortBy] Sort results by the provided value @@ -114,9 +126,15 @@ def list_items( "limit": limit, "name": name, "slug": slug, + "createdOn": convert_and_respect_annotation_metadata( + object_=created_on, annotation=ItemsListItemsRequestCreatedOn, direction="write" + ), "lastPublished": convert_and_respect_annotation_metadata( object_=last_published, annotation=ItemsListItemsRequestLastPublished, direction="write" ), + "lastUpdated": convert_and_respect_annotation_metadata( + object_=last_updated, annotation=ItemsListItemsRequestLastUpdated, direction="write" + ), "sortBy": sort_by, "sortOrder": sort_order, }, @@ -577,7 +595,9 @@ def list_items_live( limit: typing.Optional[int] = None, name: typing.Optional[str] = None, slug: typing.Optional[str] = None, + created_on: typing.Optional[ItemsListItemsLiveRequestCreatedOn] = None, last_published: typing.Optional[ItemsListItemsLiveRequestLastPublished] = None, + last_updated: typing.Optional[ItemsListItemsLiveRequestLastUpdated] = None, sort_by: typing.Optional[ItemsListItemsLiveRequestSortBy] = None, sort_order: typing.Optional[ItemsListItemsLiveRequestSortOrder] = None, request_options: typing.Optional[RequestOptions] = None, @@ -611,9 +631,15 @@ def list_items_live( slug : typing.Optional[str] Filter by the exact slug of the item + created_on : typing.Optional[ItemsListItemsLiveRequestCreatedOn] + Filter by the creation date of the item(s) + last_published : typing.Optional[ItemsListItemsLiveRequestLastPublished] Filter by the last published date of the item(s) + last_updated : typing.Optional[ItemsListItemsLiveRequestLastUpdated] + Filter by the last updated date of the item(s) + sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy] Sort results by the provided value @@ -638,9 +664,15 @@ def list_items_live( "limit": limit, "name": name, "slug": slug, + "createdOn": convert_and_respect_annotation_metadata( + object_=created_on, annotation=ItemsListItemsLiveRequestCreatedOn, direction="write" + ), "lastPublished": convert_and_respect_annotation_metadata( object_=last_published, annotation=ItemsListItemsLiveRequestLastPublished, direction="write" ), + "lastUpdated": convert_and_respect_annotation_metadata( + object_=last_updated, annotation=ItemsListItemsLiveRequestLastUpdated, direction="write" + ), "sortBy": sort_by, "sortOrder": sort_order, }, @@ -2053,9 +2085,6 @@ def publish_item( json=convert_and_respect_annotation_metadata( object_=request, annotation=ItemsPublishItemRequest, direction="write" ), - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -2158,7 +2187,9 @@ async def list_items( limit: typing.Optional[int] = None, name: typing.Optional[str] = None, slug: typing.Optional[str] = None, + created_on: typing.Optional[ItemsListItemsRequestCreatedOn] = None, last_published: typing.Optional[ItemsListItemsRequestLastPublished] = None, + last_updated: typing.Optional[ItemsListItemsRequestLastUpdated] = None, sort_by: typing.Optional[ItemsListItemsRequestSortBy] = None, sort_order: typing.Optional[ItemsListItemsRequestSortOrder] = None, request_options: typing.Optional[RequestOptions] = None, @@ -2188,9 +2219,15 @@ async def list_items( slug : typing.Optional[str] Filter by the exact slug of the item + created_on : typing.Optional[ItemsListItemsRequestCreatedOn] + Filter by the creation date of the item(s) + last_published : typing.Optional[ItemsListItemsRequestLastPublished] Filter by the last published date of the item(s) + last_updated : typing.Optional[ItemsListItemsRequestLastUpdated] + Filter by the last updated date of the item(s) + sort_by : typing.Optional[ItemsListItemsRequestSortBy] Sort results by the provided value @@ -2215,9 +2252,15 @@ async def list_items( "limit": limit, "name": name, "slug": slug, + "createdOn": convert_and_respect_annotation_metadata( + object_=created_on, annotation=ItemsListItemsRequestCreatedOn, direction="write" + ), "lastPublished": convert_and_respect_annotation_metadata( object_=last_published, annotation=ItemsListItemsRequestLastPublished, direction="write" ), + "lastUpdated": convert_and_respect_annotation_metadata( + object_=last_updated, annotation=ItemsListItemsRequestLastUpdated, direction="write" + ), "sortBy": sort_by, "sortOrder": sort_order, }, @@ -2678,7 +2721,9 @@ async def list_items_live( limit: typing.Optional[int] = None, name: typing.Optional[str] = None, slug: typing.Optional[str] = None, + created_on: typing.Optional[ItemsListItemsLiveRequestCreatedOn] = None, last_published: typing.Optional[ItemsListItemsLiveRequestLastPublished] = None, + last_updated: typing.Optional[ItemsListItemsLiveRequestLastUpdated] = None, sort_by: typing.Optional[ItemsListItemsLiveRequestSortBy] = None, sort_order: typing.Optional[ItemsListItemsLiveRequestSortOrder] = None, request_options: typing.Optional[RequestOptions] = None, @@ -2712,9 +2757,15 @@ async def list_items_live( slug : typing.Optional[str] Filter by the exact slug of the item + created_on : typing.Optional[ItemsListItemsLiveRequestCreatedOn] + Filter by the creation date of the item(s) + last_published : typing.Optional[ItemsListItemsLiveRequestLastPublished] Filter by the last published date of the item(s) + last_updated : typing.Optional[ItemsListItemsLiveRequestLastUpdated] + Filter by the last updated date of the item(s) + sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy] Sort results by the provided value @@ -2739,9 +2790,15 @@ async def list_items_live( "limit": limit, "name": name, "slug": slug, + "createdOn": convert_and_respect_annotation_metadata( + object_=created_on, annotation=ItemsListItemsLiveRequestCreatedOn, direction="write" + ), "lastPublished": convert_and_respect_annotation_metadata( object_=last_published, annotation=ItemsListItemsLiveRequestLastPublished, direction="write" ), + "lastUpdated": convert_and_respect_annotation_metadata( + object_=last_updated, annotation=ItemsListItemsLiveRequestLastUpdated, direction="write" + ), "sortBy": sort_by, "sortOrder": sort_order, }, @@ -4154,9 +4211,6 @@ async def publish_item( json=convert_and_respect_annotation_metadata( object_=request, annotation=ItemsPublishItemRequest, direction="write" ), - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) diff --git a/src/webflow/resources/collections/resources/items/types/items_list_items_live_request_sort_by.py b/src/webflow/resources/collections/resources/items/types/items_list_items_live_request_sort_by.py index 9929480..655f308 100644 --- a/src/webflow/resources/collections/resources/items/types/items_list_items_live_request_sort_by.py +++ b/src/webflow/resources/collections/resources/items/types/items_list_items_live_request_sort_by.py @@ -2,4 +2,6 @@ import typing -ItemsListItemsLiveRequestSortBy = typing.Union[typing.Literal["lastPublished", "name", "slug"], typing.Any] +ItemsListItemsLiveRequestSortBy = typing.Union[ + typing.Literal["createdOn", "lastPublished", "lastUpdated", "name", "slug"], typing.Any +] diff --git a/src/webflow/resources/collections/resources/items/types/items_list_items_request_sort_by.py b/src/webflow/resources/collections/resources/items/types/items_list_items_request_sort_by.py index 222d1ff..1564f0e 100644 --- a/src/webflow/resources/collections/resources/items/types/items_list_items_request_sort_by.py +++ b/src/webflow/resources/collections/resources/items/types/items_list_items_request_sort_by.py @@ -2,4 +2,6 @@ import typing -ItemsListItemsRequestSortBy = typing.Union[typing.Literal["lastPublished", "name", "slug"], typing.Any] +ItemsListItemsRequestSortBy = typing.Union[ + typing.Literal["createdOn", "lastPublished", "lastUpdated", "name", "slug"], typing.Any +] diff --git a/src/webflow/resources/components/client.py b/src/webflow/resources/components/client.py index a9584d8..9658d82 100644 --- a/src/webflow/resources/components/client.py +++ b/src/webflow/resources/components/client.py @@ -117,7 +117,7 @@ def get_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -201,7 +201,7 @@ def update_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -321,7 +321,7 @@ def get_properties( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -402,7 +402,7 @@ def update_properties( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -559,7 +559,7 @@ async def get_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -651,7 +651,7 @@ async def update_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -779,7 +779,7 @@ async def get_properties( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -868,7 +868,7 @@ async def update_properties( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. diff --git a/src/webflow/resources/components/raw_client.py b/src/webflow/resources/components/raw_client.py index caf0799..78f6e7d 100644 --- a/src/webflow/resources/components/raw_client.py +++ b/src/webflow/resources/components/raw_client.py @@ -186,7 +186,7 @@ def get_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -329,7 +329,7 @@ def update_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -475,7 +475,7 @@ def get_properties( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -615,7 +615,7 @@ def update_properties( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -879,7 +879,7 @@ async def get_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -1022,7 +1022,7 @@ async def update_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -1168,7 +1168,7 @@ async def get_properties( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. @@ -1308,7 +1308,7 @@ async def update_properties( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) branch_id : typing.Optional[str] Scope the operation to work on a specific branch. diff --git a/src/webflow/resources/custom_fonts/__init__.py b/src/webflow/resources/custom_fonts/__init__.py new file mode 100644 index 0000000..05a3742 --- /dev/null +++ b/src/webflow/resources/custom_fonts/__init__.py @@ -0,0 +1,52 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + CustomFontBatchDeleteRequestItemsItem, + CustomFontsCreateRequestFontDisplay, + CustomFontsGetResponse, + CustomFontsUpdateRequestFontDisplay, + CustomFontsUpdateResponse, + ) +_dynamic_imports: typing.Dict[str, str] = { + "CustomFontBatchDeleteRequestItemsItem": ".types", + "CustomFontsCreateRequestFontDisplay": ".types", + "CustomFontsGetResponse": ".types", + "CustomFontsUpdateRequestFontDisplay": ".types", + "CustomFontsUpdateResponse": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "CustomFontBatchDeleteRequestItemsItem", + "CustomFontsCreateRequestFontDisplay", + "CustomFontsGetResponse", + "CustomFontsUpdateRequestFontDisplay", + "CustomFontsUpdateResponse", +] diff --git a/src/webflow/resources/custom_fonts/client.py b/src/webflow/resources/custom_fonts/client.py new file mode 100644 index 0000000..5549565 --- /dev/null +++ b/src/webflow/resources/custom_fonts/client.py @@ -0,0 +1,903 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ...core.request_options import RequestOptions +from ...types.custom_font_axis import CustomFontAxis +from ...types.custom_font_batch_delete_response import CustomFontBatchDeleteResponse +from ...types.custom_font_create_response import CustomFontCreateResponse +from ...types.custom_fonts import CustomFonts +from .raw_client import AsyncRawCustomFontsClient, RawCustomFontsClient +from .types.custom_font_batch_delete_request_items_item import CustomFontBatchDeleteRequestItemsItem +from .types.custom_fonts_create_request_font_display import CustomFontsCreateRequestFontDisplay +from .types.custom_fonts_get_response import CustomFontsGetResponse +from .types.custom_fonts_update_request_font_display import CustomFontsUpdateRequestFontDisplay +from .types.custom_fonts_update_response import CustomFontsUpdateResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class CustomFontsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawCustomFontsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawCustomFontsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawCustomFontsClient + """ + return self._raw_client + + def list( + self, + site_id: str, + *, + offset: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CustomFonts: + """ + List the custom fonts uploaded to a site. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + offset : typing.Optional[int] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[int] + Maximum number of records to be returned (max limit: 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFonts + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.custom_fonts.list( + site_id="580e63e98c9a982ac9b8b741", + offset=1, + limit=1, + ) + """ + _response = self._raw_client.list(site_id, offset=offset, limit=limit, request_options=request_options) + return _response.data + + def create( + self, + site_id: str, + *, + file_name: str, + file_hash: str, + font_family: str, + weight: int, + italic: bool, + font_display: CustomFontsCreateRequestFontDisplay, + axes: typing.Optional[typing.Sequence[CustomFontAxis]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> CustomFontCreateResponse: + """ + Register a custom font on a site and get a presigned S3 URL to upload the font binary. + + The response includes a `customFont` object and an `upload` object. Use the `upload.url` and `upload.fields` + to POST the font binary directly to S3 as `multipart/form-data`. The binary must go in a field named `file` + and must be the last field in the form (an AWS S3 requirement). S3 returns `201 Created` on a successful upload. + + To learn more, see [Custom fonts](/data/docs/custom-fonts). + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + file_name : str + File name including extension. Accepted extensions are `.woff2`, `.woff`, `.ttf`, `.otf`, and `.eot`. Maximum 256 characters. + + file_hash : str + Lowercase hex MD5 hash of the font binary (exactly 32 characters) + + font_family : str + The CSS font-family name (1-256 characters). Commas are stripped server-side. + + weight : int + CSS font-weight value (1-1000) + + italic : bool + Whether the font is italic + + font_display : CustomFontsCreateRequestFontDisplay + CSS font-display value + + axes : typing.Optional[typing.Sequence[CustomFontAxis]] + Variable font axes. Omit or pass an empty array for static fonts. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFontCreateResponse + Font registered. Upload the binary to the presigned S3 URL in `upload` to complete the process. + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.custom_fonts.create( + site_id="580e63e98c9a982ac9b8b741", + file_name="AcmeSans-Regular.woff2", + file_hash="3c7d87c9575702bc3b1e991f4d3c638e", + font_family="Acme Sans", + weight=400, + italic=False, + font_display="auto", + ) + """ + _response = self._raw_client.create( + site_id, + file_name=file_name, + file_hash=file_hash, + font_family=font_family, + weight=weight, + italic=italic, + font_display=font_display, + axes=axes, + request_options=request_options, + ) + return _response.data + + def get( + self, site_id: str, font_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> CustomFontsGetResponse: + """ + Get details about a custom font on a site. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFontsGetResponse + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.custom_fonts.get( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", + ) + """ + _response = self._raw_client.get(site_id, font_id, request_options=request_options) + return _response.data + + def delete(self, site_id: str, font_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: + """ + Delete a custom font from a site. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.custom_fonts.delete( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", + ) + """ + _response = self._raw_client.delete(site_id, font_id, request_options=request_options) + return _response.data + + def update( + self, + site_id: str, + font_id: str, + *, + font_family: typing.Optional[str] = OMIT, + weight: typing.Optional[int] = OMIT, + italic: typing.Optional[bool] = OMIT, + font_display: typing.Optional[CustomFontsUpdateRequestFontDisplay] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> CustomFontsUpdateResponse: + """ + Update the metadata of a custom font. The font binary is not changed by this endpoint. + To replace the binary, use [Replace custom font file](#operation/replace-custom-font-file). + + The request body must include at least one of `fontFamily`, `weight`, `italic`, or `fontDisplay`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + font_family : typing.Optional[str] + The CSS font-family name (1-256 characters) + + weight : typing.Optional[int] + CSS font-weight value (1-1000) + + italic : typing.Optional[bool] + Whether the font is italic + + font_display : typing.Optional[CustomFontsUpdateRequestFontDisplay] + CSS font-display value + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFontsUpdateResponse + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.custom_fonts.update( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", + ) + """ + _response = self._raw_client.update( + site_id, + font_id, + font_family=font_family, + weight=weight, + italic=italic, + font_display=font_display, + request_options=request_options, + ) + return _response.data + + def replace_file( + self, + site_id: str, + font_id: str, + *, + file_name: str, + file_hash: str, + axes: typing.Optional[typing.Sequence[CustomFontAxis]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> CustomFontCreateResponse: + """ + Replace the binary of an existing custom font while preserving its ID and any references to it. + The upload handshake is identical to [Create custom font](#operation/create-custom-font). + + If the existing font has a non-empty `axes` array (a variable font), you must include an `axes` field + in the request. Send `axes: []` to declare that the new binary is a static font, or send the new variable + axes to declare it is still variable. Omitting `axes` when the existing font is variable returns `400`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + file_name : str + File name including extension. Accepted extensions are `.woff2`, `.woff`, `.ttf`, `.otf`, and `.eot`. Maximum 256 characters. + + file_hash : str + Lowercase hex MD5 hash of the font binary (exactly 32 characters) + + axes : typing.Optional[typing.Sequence[CustomFontAxis]] + Variable font axes for the replacement binary. Required when the existing font has a non-empty `axes` array. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFontCreateResponse + File replacement initiated. Upload the binary to the presigned S3 URL in `upload` to complete the process. + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.custom_fonts.replace_file( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", + file_name="AcmeSans-Regular-v2.woff2", + file_hash="3c7d87c9575702bc3b1e991f4d3c638e", + ) + """ + _response = self._raw_client.replace_file( + site_id, font_id, file_name=file_name, file_hash=file_hash, axes=axes, request_options=request_options + ) + return _response.data + + def batch_delete( + self, + site_id: str, + *, + items: typing.Sequence[CustomFontBatchDeleteRequestItemsItem], + request_options: typing.Optional[RequestOptions] = None, + ) -> CustomFontBatchDeleteResponse: + """ + Delete 1-100 custom fonts in a single request. The response is always `200 OK` for a valid request body. + Per-font results are reported in the `deleted` and `failed` arrays. + + The endpoint is idempotent: fonts that do not exist appear in `failed` with `name: "NotFound"` rather than + failing the entire request. You can safely retry a partial failure by re-sending only the IDs that did not + appear in `deleted`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + items : typing.Sequence[CustomFontBatchDeleteRequestItemsItem] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFontBatchDeleteResponse + Request was successful. Check `deleted` and `failed` arrays for per-item results. + + Examples + -------- + from webflow import Webflow + from webflow.resources.custom_fonts import CustomFontBatchDeleteRequestItemsItem + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.custom_fonts.batch_delete( + site_id="580e63e98c9a982ac9b8b741", + items=[ + CustomFontBatchDeleteRequestItemsItem( + id="66f3a1b2c4d5e6f7a8b9c0d1", + ) + ], + ) + """ + _response = self._raw_client.batch_delete(site_id, items=items, request_options=request_options) + return _response.data + + +class AsyncCustomFontsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawCustomFontsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawCustomFontsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawCustomFontsClient + """ + return self._raw_client + + async def list( + self, + site_id: str, + *, + offset: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CustomFonts: + """ + List the custom fonts uploaded to a site. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + offset : typing.Optional[int] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[int] + Maximum number of records to be returned (max limit: 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFonts + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.custom_fonts.list( + site_id="580e63e98c9a982ac9b8b741", + offset=1, + limit=1, + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.list(site_id, offset=offset, limit=limit, request_options=request_options) + return _response.data + + async def create( + self, + site_id: str, + *, + file_name: str, + file_hash: str, + font_family: str, + weight: int, + italic: bool, + font_display: CustomFontsCreateRequestFontDisplay, + axes: typing.Optional[typing.Sequence[CustomFontAxis]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> CustomFontCreateResponse: + """ + Register a custom font on a site and get a presigned S3 URL to upload the font binary. + + The response includes a `customFont` object and an `upload` object. Use the `upload.url` and `upload.fields` + to POST the font binary directly to S3 as `multipart/form-data`. The binary must go in a field named `file` + and must be the last field in the form (an AWS S3 requirement). S3 returns `201 Created` on a successful upload. + + To learn more, see [Custom fonts](/data/docs/custom-fonts). + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + file_name : str + File name including extension. Accepted extensions are `.woff2`, `.woff`, `.ttf`, `.otf`, and `.eot`. Maximum 256 characters. + + file_hash : str + Lowercase hex MD5 hash of the font binary (exactly 32 characters) + + font_family : str + The CSS font-family name (1-256 characters). Commas are stripped server-side. + + weight : int + CSS font-weight value (1-1000) + + italic : bool + Whether the font is italic + + font_display : CustomFontsCreateRequestFontDisplay + CSS font-display value + + axes : typing.Optional[typing.Sequence[CustomFontAxis]] + Variable font axes. Omit or pass an empty array for static fonts. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFontCreateResponse + Font registered. Upload the binary to the presigned S3 URL in `upload` to complete the process. + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.custom_fonts.create( + site_id="580e63e98c9a982ac9b8b741", + file_name="AcmeSans-Regular.woff2", + file_hash="3c7d87c9575702bc3b1e991f4d3c638e", + font_family="Acme Sans", + weight=400, + italic=False, + font_display="auto", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + site_id, + file_name=file_name, + file_hash=file_hash, + font_family=font_family, + weight=weight, + italic=italic, + font_display=font_display, + axes=axes, + request_options=request_options, + ) + return _response.data + + async def get( + self, site_id: str, font_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> CustomFontsGetResponse: + """ + Get details about a custom font on a site. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFontsGetResponse + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.custom_fonts.get( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get(site_id, font_id, request_options=request_options) + return _response.data + + async def delete( + self, site_id: str, font_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Delete a custom font from a site. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.custom_fonts.delete( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete(site_id, font_id, request_options=request_options) + return _response.data + + async def update( + self, + site_id: str, + font_id: str, + *, + font_family: typing.Optional[str] = OMIT, + weight: typing.Optional[int] = OMIT, + italic: typing.Optional[bool] = OMIT, + font_display: typing.Optional[CustomFontsUpdateRequestFontDisplay] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> CustomFontsUpdateResponse: + """ + Update the metadata of a custom font. The font binary is not changed by this endpoint. + To replace the binary, use [Replace custom font file](#operation/replace-custom-font-file). + + The request body must include at least one of `fontFamily`, `weight`, `italic`, or `fontDisplay`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + font_family : typing.Optional[str] + The CSS font-family name (1-256 characters) + + weight : typing.Optional[int] + CSS font-weight value (1-1000) + + italic : typing.Optional[bool] + Whether the font is italic + + font_display : typing.Optional[CustomFontsUpdateRequestFontDisplay] + CSS font-display value + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFontsUpdateResponse + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.custom_fonts.update( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.update( + site_id, + font_id, + font_family=font_family, + weight=weight, + italic=italic, + font_display=font_display, + request_options=request_options, + ) + return _response.data + + async def replace_file( + self, + site_id: str, + font_id: str, + *, + file_name: str, + file_hash: str, + axes: typing.Optional[typing.Sequence[CustomFontAxis]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> CustomFontCreateResponse: + """ + Replace the binary of an existing custom font while preserving its ID and any references to it. + The upload handshake is identical to [Create custom font](#operation/create-custom-font). + + If the existing font has a non-empty `axes` array (a variable font), you must include an `axes` field + in the request. Send `axes: []` to declare that the new binary is a static font, or send the new variable + axes to declare it is still variable. Omitting `axes` when the existing font is variable returns `400`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + file_name : str + File name including extension. Accepted extensions are `.woff2`, `.woff`, `.ttf`, `.otf`, and `.eot`. Maximum 256 characters. + + file_hash : str + Lowercase hex MD5 hash of the font binary (exactly 32 characters) + + axes : typing.Optional[typing.Sequence[CustomFontAxis]] + Variable font axes for the replacement binary. Required when the existing font has a non-empty `axes` array. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFontCreateResponse + File replacement initiated. Upload the binary to the presigned S3 URL in `upload` to complete the process. + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.custom_fonts.replace_file( + site_id="580e63e98c9a982ac9b8b741", + font_id="66f3a1b2c4d5e6f7a8b9c0d1", + file_name="AcmeSans-Regular-v2.woff2", + file_hash="3c7d87c9575702bc3b1e991f4d3c638e", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.replace_file( + site_id, font_id, file_name=file_name, file_hash=file_hash, axes=axes, request_options=request_options + ) + return _response.data + + async def batch_delete( + self, + site_id: str, + *, + items: typing.Sequence[CustomFontBatchDeleteRequestItemsItem], + request_options: typing.Optional[RequestOptions] = None, + ) -> CustomFontBatchDeleteResponse: + """ + Delete 1-100 custom fonts in a single request. The response is always `200 OK` for a valid request body. + Per-font results are reported in the `deleted` and `failed` arrays. + + The endpoint is idempotent: fonts that do not exist appear in `failed` with `name: "NotFound"` rather than + failing the entire request. You can safely retry a partial failure by re-sending only the IDs that did not + appear in `deleted`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + items : typing.Sequence[CustomFontBatchDeleteRequestItemsItem] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CustomFontBatchDeleteResponse + Request was successful. Check `deleted` and `failed` arrays for per-item results. + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + from webflow.resources.custom_fonts import CustomFontBatchDeleteRequestItemsItem + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.custom_fonts.batch_delete( + site_id="580e63e98c9a982ac9b8b741", + items=[ + CustomFontBatchDeleteRequestItemsItem( + id="66f3a1b2c4d5e6f7a8b9c0d1", + ) + ], + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.batch_delete(site_id, items=items, request_options=request_options) + return _response.data diff --git a/src/webflow/resources/custom_fonts/raw_client.py b/src/webflow/resources/custom_fonts/raw_client.py new file mode 100644 index 0000000..f55a3e0 --- /dev/null +++ b/src/webflow/resources/custom_fonts/raw_client.py @@ -0,0 +1,1969 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ...core.api_error import ApiError +from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ...core.http_response import AsyncHttpResponse, HttpResponse +from ...core.jsonable_encoder import jsonable_encoder +from ...core.parse_error import ParsingError +from ...core.pydantic_utilities import parse_obj_as +from ...core.request_options import RequestOptions +from ...core.serialization import convert_and_respect_annotation_metadata +from ...errors.bad_request_error import BadRequestError +from ...errors.conflict_error import ConflictError +from ...errors.forbidden_error import ForbiddenError +from ...errors.internal_server_error import InternalServerError +from ...errors.not_found_error import NotFoundError +from ...errors.service_unavailable_error import ServiceUnavailableError +from ...errors.too_many_requests_error import TooManyRequestsError +from ...errors.unauthorized_error import UnauthorizedError +from ...types.custom_font_axis import CustomFontAxis +from ...types.custom_font_batch_delete_response import CustomFontBatchDeleteResponse +from ...types.custom_font_create_response import CustomFontCreateResponse +from ...types.custom_fonts import CustomFonts +from ...types.error import Error +from .types.custom_font_batch_delete_request_items_item import CustomFontBatchDeleteRequestItemsItem +from .types.custom_fonts_create_request_font_display import CustomFontsCreateRequestFontDisplay +from .types.custom_fonts_get_response import CustomFontsGetResponse +from .types.custom_fonts_update_request_font_display import CustomFontsUpdateRequestFontDisplay +from .types.custom_fonts_update_response import CustomFontsUpdateResponse +from pydantic import ValidationError + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawCustomFontsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def list( + self, + site_id: str, + *, + offset: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[CustomFonts]: + """ + List the custom fonts uploaded to a site. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + offset : typing.Optional[int] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[int] + Maximum number of records to be returned (max limit: 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[CustomFonts] + Request was successful + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "offset": offset, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFonts, + parse_obj_as( + type_=CustomFonts, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def create( + self, + site_id: str, + *, + file_name: str, + file_hash: str, + font_family: str, + weight: int, + italic: bool, + font_display: CustomFontsCreateRequestFontDisplay, + axes: typing.Optional[typing.Sequence[CustomFontAxis]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[CustomFontCreateResponse]: + """ + Register a custom font on a site and get a presigned S3 URL to upload the font binary. + + The response includes a `customFont` object and an `upload` object. Use the `upload.url` and `upload.fields` + to POST the font binary directly to S3 as `multipart/form-data`. The binary must go in a field named `file` + and must be the last field in the form (an AWS S3 requirement). S3 returns `201 Created` on a successful upload. + + To learn more, see [Custom fonts](/data/docs/custom-fonts). + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + file_name : str + File name including extension. Accepted extensions are `.woff2`, `.woff`, `.ttf`, `.otf`, and `.eot`. Maximum 256 characters. + + file_hash : str + Lowercase hex MD5 hash of the font binary (exactly 32 characters) + + font_family : str + The CSS font-family name (1-256 characters). Commas are stripped server-side. + + weight : int + CSS font-weight value (1-1000) + + italic : bool + Whether the font is italic + + font_display : CustomFontsCreateRequestFontDisplay + CSS font-display value + + axes : typing.Optional[typing.Sequence[CustomFontAxis]] + Variable font axes. Omit or pass an empty array for static fonts. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[CustomFontCreateResponse] + Font registered. Upload the binary to the presigned S3 URL in `upload` to complete the process. + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts", + base_url=self._client_wrapper.get_environment().base, + method="POST", + json={ + "fileName": file_name, + "fileHash": file_hash, + "fontFamily": font_family, + "weight": weight, + "italic": italic, + "fontDisplay": font_display, + "axes": convert_and_respect_annotation_metadata( + object_=axes, annotation=typing.Sequence[CustomFontAxis], direction="write" + ), + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFontCreateResponse, + parse_obj_as( + type_=CustomFontCreateResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 409: + raise ConflictError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 503: + raise ServiceUnavailableError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def get( + self, site_id: str, font_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[CustomFontsGetResponse]: + """ + Get details about a custom font on a site. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[CustomFontsGetResponse] + Request was successful + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts/{jsonable_encoder(font_id)}", + base_url=self._client_wrapper.get_environment().base, + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFontsGetResponse, + parse_obj_as( + type_=CustomFontsGetResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def delete( + self, site_id: str, font_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[None]: + """ + Delete a custom font from a site. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[None] + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts/{jsonable_encoder(font_id)}", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return HttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def update( + self, + site_id: str, + font_id: str, + *, + font_family: typing.Optional[str] = OMIT, + weight: typing.Optional[int] = OMIT, + italic: typing.Optional[bool] = OMIT, + font_display: typing.Optional[CustomFontsUpdateRequestFontDisplay] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[CustomFontsUpdateResponse]: + """ + Update the metadata of a custom font. The font binary is not changed by this endpoint. + To replace the binary, use [Replace custom font file](#operation/replace-custom-font-file). + + The request body must include at least one of `fontFamily`, `weight`, `italic`, or `fontDisplay`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + font_family : typing.Optional[str] + The CSS font-family name (1-256 characters) + + weight : typing.Optional[int] + CSS font-weight value (1-1000) + + italic : typing.Optional[bool] + Whether the font is italic + + font_display : typing.Optional[CustomFontsUpdateRequestFontDisplay] + CSS font-display value + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[CustomFontsUpdateResponse] + Request was successful + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts/{jsonable_encoder(font_id)}", + base_url=self._client_wrapper.get_environment().base, + method="PATCH", + json={ + "fontFamily": font_family, + "weight": weight, + "italic": italic, + "fontDisplay": font_display, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFontsUpdateResponse, + parse_obj_as( + type_=CustomFontsUpdateResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def replace_file( + self, + site_id: str, + font_id: str, + *, + file_name: str, + file_hash: str, + axes: typing.Optional[typing.Sequence[CustomFontAxis]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[CustomFontCreateResponse]: + """ + Replace the binary of an existing custom font while preserving its ID and any references to it. + The upload handshake is identical to [Create custom font](#operation/create-custom-font). + + If the existing font has a non-empty `axes` array (a variable font), you must include an `axes` field + in the request. Send `axes: []` to declare that the new binary is a static font, or send the new variable + axes to declare it is still variable. Omitting `axes` when the existing font is variable returns `400`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + file_name : str + File name including extension. Accepted extensions are `.woff2`, `.woff`, `.ttf`, `.otf`, and `.eot`. Maximum 256 characters. + + file_hash : str + Lowercase hex MD5 hash of the font binary (exactly 32 characters) + + axes : typing.Optional[typing.Sequence[CustomFontAxis]] + Variable font axes for the replacement binary. Required when the existing font has a non-empty `axes` array. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[CustomFontCreateResponse] + File replacement initiated. Upload the binary to the presigned S3 URL in `upload` to complete the process. + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts/{jsonable_encoder(font_id)}/file", + base_url=self._client_wrapper.get_environment().base, + method="PUT", + json={ + "fileName": file_name, + "fileHash": file_hash, + "axes": convert_and_respect_annotation_metadata( + object_=axes, annotation=typing.Sequence[CustomFontAxis], direction="write" + ), + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFontCreateResponse, + parse_obj_as( + type_=CustomFontCreateResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def batch_delete( + self, + site_id: str, + *, + items: typing.Sequence[CustomFontBatchDeleteRequestItemsItem], + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[CustomFontBatchDeleteResponse]: + """ + Delete 1-100 custom fonts in a single request. The response is always `200 OK` for a valid request body. + Per-font results are reported in the `deleted` and `failed` arrays. + + The endpoint is idempotent: fonts that do not exist appear in `failed` with `name: "NotFound"` rather than + failing the entire request. You can safely retry a partial failure by re-sending only the IDs that did not + appear in `deleted`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + items : typing.Sequence[CustomFontBatchDeleteRequestItemsItem] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[CustomFontBatchDeleteResponse] + Request was successful. Check `deleted` and `failed` arrays for per-item results. + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts/batchDelete", + base_url=self._client_wrapper.get_environment().base, + method="POST", + json={ + "items": convert_and_respect_annotation_metadata( + object_=items, annotation=typing.Sequence[CustomFontBatchDeleteRequestItemsItem], direction="write" + ), + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFontBatchDeleteResponse, + parse_obj_as( + type_=CustomFontBatchDeleteResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + +class AsyncRawCustomFontsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list( + self, + site_id: str, + *, + offset: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[CustomFonts]: + """ + List the custom fonts uploaded to a site. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + offset : typing.Optional[int] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[int] + Maximum number of records to be returned (max limit: 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[CustomFonts] + Request was successful + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "offset": offset, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFonts, + parse_obj_as( + type_=CustomFonts, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def create( + self, + site_id: str, + *, + file_name: str, + file_hash: str, + font_family: str, + weight: int, + italic: bool, + font_display: CustomFontsCreateRequestFontDisplay, + axes: typing.Optional[typing.Sequence[CustomFontAxis]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[CustomFontCreateResponse]: + """ + Register a custom font on a site and get a presigned S3 URL to upload the font binary. + + The response includes a `customFont` object and an `upload` object. Use the `upload.url` and `upload.fields` + to POST the font binary directly to S3 as `multipart/form-data`. The binary must go in a field named `file` + and must be the last field in the form (an AWS S3 requirement). S3 returns `201 Created` on a successful upload. + + To learn more, see [Custom fonts](/data/docs/custom-fonts). + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + file_name : str + File name including extension. Accepted extensions are `.woff2`, `.woff`, `.ttf`, `.otf`, and `.eot`. Maximum 256 characters. + + file_hash : str + Lowercase hex MD5 hash of the font binary (exactly 32 characters) + + font_family : str + The CSS font-family name (1-256 characters). Commas are stripped server-side. + + weight : int + CSS font-weight value (1-1000) + + italic : bool + Whether the font is italic + + font_display : CustomFontsCreateRequestFontDisplay + CSS font-display value + + axes : typing.Optional[typing.Sequence[CustomFontAxis]] + Variable font axes. Omit or pass an empty array for static fonts. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[CustomFontCreateResponse] + Font registered. Upload the binary to the presigned S3 URL in `upload` to complete the process. + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts", + base_url=self._client_wrapper.get_environment().base, + method="POST", + json={ + "fileName": file_name, + "fileHash": file_hash, + "fontFamily": font_family, + "weight": weight, + "italic": italic, + "fontDisplay": font_display, + "axes": convert_and_respect_annotation_metadata( + object_=axes, annotation=typing.Sequence[CustomFontAxis], direction="write" + ), + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFontCreateResponse, + parse_obj_as( + type_=CustomFontCreateResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 409: + raise ConflictError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 503: + raise ServiceUnavailableError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def get( + self, site_id: str, font_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[CustomFontsGetResponse]: + """ + Get details about a custom font on a site. + + Required scope | `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[CustomFontsGetResponse] + Request was successful + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts/{jsonable_encoder(font_id)}", + base_url=self._client_wrapper.get_environment().base, + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFontsGetResponse, + parse_obj_as( + type_=CustomFontsGetResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def delete( + self, site_id: str, font_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[None]: + """ + Delete a custom font from a site. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[None] + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts/{jsonable_encoder(font_id)}", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def update( + self, + site_id: str, + font_id: str, + *, + font_family: typing.Optional[str] = OMIT, + weight: typing.Optional[int] = OMIT, + italic: typing.Optional[bool] = OMIT, + font_display: typing.Optional[CustomFontsUpdateRequestFontDisplay] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[CustomFontsUpdateResponse]: + """ + Update the metadata of a custom font. The font binary is not changed by this endpoint. + To replace the binary, use [Replace custom font file](#operation/replace-custom-font-file). + + The request body must include at least one of `fontFamily`, `weight`, `italic`, or `fontDisplay`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + font_family : typing.Optional[str] + The CSS font-family name (1-256 characters) + + weight : typing.Optional[int] + CSS font-weight value (1-1000) + + italic : typing.Optional[bool] + Whether the font is italic + + font_display : typing.Optional[CustomFontsUpdateRequestFontDisplay] + CSS font-display value + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[CustomFontsUpdateResponse] + Request was successful + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts/{jsonable_encoder(font_id)}", + base_url=self._client_wrapper.get_environment().base, + method="PATCH", + json={ + "fontFamily": font_family, + "weight": weight, + "italic": italic, + "fontDisplay": font_display, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFontsUpdateResponse, + parse_obj_as( + type_=CustomFontsUpdateResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def replace_file( + self, + site_id: str, + font_id: str, + *, + file_name: str, + file_hash: str, + axes: typing.Optional[typing.Sequence[CustomFontAxis]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[CustomFontCreateResponse]: + """ + Replace the binary of an existing custom font while preserving its ID and any references to it. + The upload handshake is identical to [Create custom font](#operation/create-custom-font). + + If the existing font has a non-empty `axes` array (a variable font), you must include an `axes` field + in the request. Send `axes: []` to declare that the new binary is a static font, or send the new variable + axes to declare it is still variable. Omitting `axes` when the existing font is variable returns `400`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + font_id : str + Unique identifier for a custom font on a site + + file_name : str + File name including extension. Accepted extensions are `.woff2`, `.woff`, `.ttf`, `.otf`, and `.eot`. Maximum 256 characters. + + file_hash : str + Lowercase hex MD5 hash of the font binary (exactly 32 characters) + + axes : typing.Optional[typing.Sequence[CustomFontAxis]] + Variable font axes for the replacement binary. Required when the existing font has a non-empty `axes` array. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[CustomFontCreateResponse] + File replacement initiated. Upload the binary to the presigned S3 URL in `upload` to complete the process. + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts/{jsonable_encoder(font_id)}/file", + base_url=self._client_wrapper.get_environment().base, + method="PUT", + json={ + "fileName": file_name, + "fileHash": file_hash, + "axes": convert_and_respect_annotation_metadata( + object_=axes, annotation=typing.Sequence[CustomFontAxis], direction="write" + ), + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFontCreateResponse, + parse_obj_as( + type_=CustomFontCreateResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def batch_delete( + self, + site_id: str, + *, + items: typing.Sequence[CustomFontBatchDeleteRequestItemsItem], + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[CustomFontBatchDeleteResponse]: + """ + Delete 1-100 custom fonts in a single request. The response is always `200 OK` for a valid request body. + Per-font results are reported in the `deleted` and `failed` arrays. + + The endpoint is idempotent: fonts that do not exist appear in `failed` with `name: "NotFound"` rather than + failing the entire request. You can safely retry a partial failure by re-sending only the IDs that did not + appear in `deleted`. + + Required scope | `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + items : typing.Sequence[CustomFontBatchDeleteRequestItemsItem] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[CustomFontBatchDeleteResponse] + Request was successful. Check `deleted` and `failed` arrays for per-item results. + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/custom_fonts/batchDelete", + base_url=self._client_wrapper.get_environment().base, + method="POST", + json={ + "items": convert_and_respect_annotation_metadata( + object_=items, annotation=typing.Sequence[CustomFontBatchDeleteRequestItemsItem], direction="write" + ), + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CustomFontBatchDeleteResponse, + parse_obj_as( + type_=CustomFontBatchDeleteResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) diff --git a/src/webflow/resources/custom_fonts/types/__init__.py b/src/webflow/resources/custom_fonts/types/__init__.py new file mode 100644 index 0000000..d57b127 --- /dev/null +++ b/src/webflow/resources/custom_fonts/types/__init__.py @@ -0,0 +1,50 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .custom_font_batch_delete_request_items_item import CustomFontBatchDeleteRequestItemsItem + from .custom_fonts_create_request_font_display import CustomFontsCreateRequestFontDisplay + from .custom_fonts_get_response import CustomFontsGetResponse + from .custom_fonts_update_request_font_display import CustomFontsUpdateRequestFontDisplay + from .custom_fonts_update_response import CustomFontsUpdateResponse +_dynamic_imports: typing.Dict[str, str] = { + "CustomFontBatchDeleteRequestItemsItem": ".custom_font_batch_delete_request_items_item", + "CustomFontsCreateRequestFontDisplay": ".custom_fonts_create_request_font_display", + "CustomFontsGetResponse": ".custom_fonts_get_response", + "CustomFontsUpdateRequestFontDisplay": ".custom_fonts_update_request_font_display", + "CustomFontsUpdateResponse": ".custom_fonts_update_response", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}") + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e + except AttributeError as e: + raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "CustomFontBatchDeleteRequestItemsItem", + "CustomFontsCreateRequestFontDisplay", + "CustomFontsGetResponse", + "CustomFontsUpdateRequestFontDisplay", + "CustomFontsUpdateResponse", +] diff --git a/src/webflow/resources/custom_fonts/types/custom_font_batch_delete_request_items_item.py b/src/webflow/resources/custom_fonts/types/custom_font_batch_delete_request_items_item.py new file mode 100644 index 0000000..09eaf87 --- /dev/null +++ b/src/webflow/resources/custom_fonts/types/custom_font_batch_delete_request_items_item.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class CustomFontBatchDeleteRequestItemsItem(UniversalBaseModel): + id: str = pydantic.Field() + """ + The ID of the custom font to delete + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/resources/custom_fonts/types/custom_fonts_create_request_font_display.py b/src/webflow/resources/custom_fonts/types/custom_fonts_create_request_font_display.py new file mode 100644 index 0000000..b403d84 --- /dev/null +++ b/src/webflow/resources/custom_fonts/types/custom_fonts_create_request_font_display.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CustomFontsCreateRequestFontDisplay = typing.Union[ + typing.Literal["auto", "block", "swap", "fallback", "optional"], typing.Any +] diff --git a/src/webflow/resources/custom_fonts/types/custom_fonts_get_response.py b/src/webflow/resources/custom_fonts/types/custom_fonts_get_response.py new file mode 100644 index 0000000..a2a2d6d --- /dev/null +++ b/src/webflow/resources/custom_fonts/types/custom_fonts_get_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ....core.serialization import FieldMetadata +from ....types.custom_font import CustomFont + + +class CustomFontsGetResponse(UniversalBaseModel): + custom_font: typing_extensions.Annotated[ + CustomFont, FieldMetadata(alias="customFont"), pydantic.Field(alias="customFont") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/resources/custom_fonts/types/custom_fonts_update_request_font_display.py b/src/webflow/resources/custom_fonts/types/custom_fonts_update_request_font_display.py new file mode 100644 index 0000000..82fc2df --- /dev/null +++ b/src/webflow/resources/custom_fonts/types/custom_fonts_update_request_font_display.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CustomFontsUpdateRequestFontDisplay = typing.Union[ + typing.Literal["auto", "block", "swap", "fallback", "optional"], typing.Any +] diff --git a/src/webflow/resources/custom_fonts/types/custom_fonts_update_response.py b/src/webflow/resources/custom_fonts/types/custom_fonts_update_response.py new file mode 100644 index 0000000..c8bc1a8 --- /dev/null +++ b/src/webflow/resources/custom_fonts/types/custom_fonts_update_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ....core.serialization import FieldMetadata +from ....types.custom_font import CustomFont + + +class CustomFontsUpdateResponse(UniversalBaseModel): + custom_font: typing_extensions.Annotated[ + CustomFont, FieldMetadata(alias="customFont"), pydantic.Field(alias="customFont") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/resources/pages/client.py b/src/webflow/resources/pages/client.py index 9f6f980..30cf6be 100644 --- a/src/webflow/resources/pages/client.py +++ b/src/webflow/resources/pages/client.py @@ -60,7 +60,7 @@ def list( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) @@ -115,7 +115,7 @@ def get_metadata( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -164,7 +164,7 @@ def update_page_settings( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) title : typing.Optional[str] Title for the page @@ -172,8 +172,9 @@ def update_page_settings( slug : typing.Optional[str] Slug for the page. - - **Note:** Updating slugs in secondary locales is only supported in Advanced and Enterprise localization add-on plans. + **Note:** The slug field is ignored in the following cases — all other fields in the same request still apply: + - The site's home page, collection template pages, and utility pages (e.g. 404, password, search). + - For secondary locales, updating the slug requires an Advanced or Enterprise localization add-on plan. seo : typing.Optional[PageMetadataWriteSeo] SEO-related fields for the Page @@ -252,7 +253,7 @@ def get_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) @@ -447,7 +448,7 @@ async def list( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) @@ -510,7 +511,7 @@ async def get_metadata( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -567,7 +568,7 @@ async def update_page_settings( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) title : typing.Optional[str] Title for the page @@ -575,8 +576,9 @@ async def update_page_settings( slug : typing.Optional[str] Slug for the page. - - **Note:** Updating slugs in secondary locales is only supported in Advanced and Enterprise localization add-on plans. + **Note:** The slug field is ignored in the following cases — all other fields in the same request still apply: + - The site's home page, collection template pages, and utility pages (e.g. 404, password, search). + - For secondary locales, updating the slug requires an Advanced or Enterprise localization add-on plan. seo : typing.Optional[PageMetadataWriteSeo] SEO-related fields for the Page @@ -663,7 +665,7 @@ async def get_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) diff --git a/src/webflow/resources/pages/raw_client.py b/src/webflow/resources/pages/raw_client.py index 1287d92..55f9cdb 100644 --- a/src/webflow/resources/pages/raw_client.py +++ b/src/webflow/resources/pages/raw_client.py @@ -57,7 +57,7 @@ def list( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) @@ -178,7 +178,7 @@ def get_metadata( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -295,7 +295,7 @@ def update_page_settings( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) title : typing.Optional[str] Title for the page @@ -303,8 +303,9 @@ def update_page_settings( slug : typing.Optional[str] Slug for the page. - - **Note:** Updating slugs in secondary locales is only supported in Advanced and Enterprise localization add-on plans. + **Note:** The slug field is ignored in the following cases — all other fields in the same request still apply: + - The site's home page, collection template pages, and utility pages (e.g. 404, password, search). + - For secondary locales, updating the slug requires an Advanced or Enterprise localization add-on plan. seo : typing.Optional[PageMetadataWriteSeo] SEO-related fields for the Page @@ -441,7 +442,7 @@ def get_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) @@ -724,7 +725,7 @@ async def list( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) @@ -845,7 +846,7 @@ async def get_metadata( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -962,7 +963,7 @@ async def update_page_settings( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) title : typing.Optional[str] Title for the page @@ -970,8 +971,9 @@ async def update_page_settings( slug : typing.Optional[str] Slug for the page. - - **Note:** Updating slugs in secondary locales is only supported in Advanced and Enterprise localization add-on plans. + **Note:** The slug field is ignored in the following cases — all other fields in the same request still apply: + - The site's home page, collection template pages, and utility pages (e.g. 404, password, search). + - For secondary locales, updating the slug requires an Advanced or Enterprise localization add-on plan. seo : typing.Optional[PageMetadataWriteSeo] SEO-related fields for the Page @@ -1108,7 +1110,7 @@ async def get_content( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) limit : typing.Optional[int] Maximum number of records to be returned (max limit: 100) diff --git a/src/webflow/resources/pages/resources/scripts/client.py b/src/webflow/resources/pages/resources/scripts/client.py index 205dca5..0b11ef7 100644 --- a/src/webflow/resources/pages/resources/scripts/client.py +++ b/src/webflow/resources/pages/resources/scripts/client.py @@ -33,6 +33,8 @@ def get_custom_code( """ Get all scripts applied to a page. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -78,6 +80,8 @@ def upsert_custom_code( To apply a script to a page, the script must first be registered to a Site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -189,6 +193,8 @@ async def get_custom_code( """ Get all scripts applied to a page. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -242,6 +248,8 @@ async def upsert_custom_code( To apply a script to a page, the script must first be registered to a Site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters diff --git a/src/webflow/resources/pages/resources/scripts/raw_client.py b/src/webflow/resources/pages/resources/scripts/raw_client.py index 6a71dd8..9912b52 100644 --- a/src/webflow/resources/pages/resources/scripts/raw_client.py +++ b/src/webflow/resources/pages/resources/scripts/raw_client.py @@ -36,6 +36,8 @@ def get_custom_code( """ Get all scripts applied to a page. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -147,6 +149,8 @@ def upsert_custom_code( To apply a script to a page, the script must first be registered to a Site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -182,9 +186,6 @@ def upsert_custom_code( "lastUpdated": last_updated, "createdOn": created_on, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -381,6 +382,8 @@ async def get_custom_code( """ Get all scripts applied to a page. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -492,6 +495,8 @@ async def upsert_custom_code( To apply a script to a page, the script must first be registered to a Site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -527,9 +532,6 @@ async def upsert_custom_code( "lastUpdated": last_updated, "createdOn": created_on, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) diff --git a/src/webflow/resources/scripts/client.py b/src/webflow/resources/scripts/client.py index f8a540e..c072b05 100644 --- a/src/webflow/resources/scripts/client.py +++ b/src/webflow/resources/scripts/client.py @@ -36,6 +36,8 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -83,6 +85,8 @@ def register_hosted( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -157,6 +161,8 @@ def register_inline( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -238,6 +244,8 @@ async def list( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -293,6 +301,8 @@ async def register_hosted( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -375,6 +385,8 @@ async def register_inline( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters diff --git a/src/webflow/resources/scripts/raw_client.py b/src/webflow/resources/scripts/raw_client.py index 0828f55..757b54d 100644 --- a/src/webflow/resources/scripts/raw_client.py +++ b/src/webflow/resources/scripts/raw_client.py @@ -39,6 +39,8 @@ def list( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -152,6 +154,8 @@ def register_hosted( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -291,6 +295,8 @@ def register_inline( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -427,6 +433,8 @@ async def list( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -540,6 +548,8 @@ async def register_hosted( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -679,6 +689,8 @@ async def register_inline( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters diff --git a/src/webflow/resources/sites/__init__.py b/src/webflow/resources/sites/__init__.py index fb81115..580db67 100644 --- a/src/webflow/resources/sites/__init__.py +++ b/src/webflow/resources/sites/__init__.py @@ -6,7 +6,7 @@ from importlib import import_module if typing.TYPE_CHECKING: - from .types import SitesPublishResponse + from .types import SitesPublishResponse, SitesPublishResponsePublishScope from .resources import ( CommentsGetCommentThreadRequestSortBy, CommentsGetCommentThreadRequestSortOrder, @@ -18,6 +18,7 @@ activity_logs, comments, forms, + google_tag, plans, redirects, robots_txt, @@ -32,10 +33,12 @@ "CommentsListCommentThreadsRequestSortBy": ".resources", "CommentsListCommentThreadsRequestSortOrder": ".resources", "SitesPublishResponse": ".types", + "SitesPublishResponsePublishScope": ".types", "WellKnownFileContentType": ".resources", "activity_logs": ".resources", "comments": ".resources", "forms": ".resources", + "google_tag": ".resources", "plans": ".resources", "redirects": ".resources", "robots_txt": ".resources", @@ -73,10 +76,12 @@ def __dir__(): "CommentsListCommentThreadsRequestSortBy", "CommentsListCommentThreadsRequestSortOrder", "SitesPublishResponse", + "SitesPublishResponsePublishScope", "WellKnownFileContentType", "activity_logs", "comments", "forms", + "google_tag", "plans", "redirects", "robots_txt", diff --git a/src/webflow/resources/sites/client.py b/src/webflow/resources/sites/client.py index 30b9ca2..2ad2d85 100644 --- a/src/webflow/resources/sites/client.py +++ b/src/webflow/resources/sites/client.py @@ -16,6 +16,7 @@ from .resources.activity_logs.client import ActivityLogsClient, AsyncActivityLogsClient from .resources.comments.client import AsyncCommentsClient, CommentsClient from .resources.forms.client import AsyncFormsClient, FormsClient + from .resources.google_tag.client import AsyncGoogleTagClient, GoogleTagClient from .resources.plans.client import AsyncPlansClient, PlansClient from .resources.redirects.client import AsyncRedirectsClient, RedirectsClient from .resources.robots_txt.client import AsyncRobotsTxtClient, RobotsTxtClient @@ -33,6 +34,7 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): self._plans: typing.Optional[PlansClient] = None self._robots_txt: typing.Optional[RobotsTxtClient] = None self._well_known: typing.Optional[WellKnownClient] = None + self._google_tag: typing.Optional[GoogleTagClient] = None self._activity_logs: typing.Optional[ActivityLogsClient] = None self._comments: typing.Optional[CommentsClient] = None self._scripts: typing.Optional[ScriptsClient] = None @@ -292,13 +294,19 @@ def publish( *, custom_domains: typing.Optional[typing.Sequence[str]] = OMIT, publish_to_webflow_subdomain: typing.Optional[bool] = OMIT, + page_id: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> SitesPublishResponse: """ - Publishes a site to one or more more domains. + Publishes a site or an individual page to one or more domains. + If multiple individual pages are published to staging, publishing from staging to production publishes all staged changes. To publish to a specific custom domain, use the domain IDs from the [Get Custom Domains](/data/reference/sites/get-custom-domain) endpoint. + You must include at least one of the `customDomains` or `publishToWebflowSubdomain` properties in the request body. + + To publish an individual page instead of the entire site, provide the ID of the page in the `pageId` parameter. + This endpoint has a specific rate limit of one successful publish queue per minute. Required scope | `sites:write` @@ -314,6 +322,9 @@ def publish( publish_to_webflow_subdomain : typing.Optional[bool] Choice of whether to publish to the default Webflow Subdomain + page_id : typing.Optional[str] + The ID of the page to publish + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -339,6 +350,7 @@ def publish( site_id, custom_domains=custom_domains, publish_to_webflow_subdomain=publish_to_webflow_subdomain, + page_id=page_id, request_options=request_options, ) return _response.data @@ -375,6 +387,14 @@ def well_known(self): self._well_known = WellKnownClient(client_wrapper=self._client_wrapper) return self._well_known + @property + def google_tag(self): + if self._google_tag is None: + from .resources.google_tag.client import GoogleTagClient # noqa: E402 + + self._google_tag = GoogleTagClient(client_wrapper=self._client_wrapper) + return self._google_tag + @property def activity_logs(self): if self._activity_logs is None: @@ -416,6 +436,7 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): self._plans: typing.Optional[AsyncPlansClient] = None self._robots_txt: typing.Optional[AsyncRobotsTxtClient] = None self._well_known: typing.Optional[AsyncWellKnownClient] = None + self._google_tag: typing.Optional[AsyncGoogleTagClient] = None self._activity_logs: typing.Optional[AsyncActivityLogsClient] = None self._comments: typing.Optional[AsyncCommentsClient] = None self._scripts: typing.Optional[AsyncScriptsClient] = None @@ -725,13 +746,19 @@ async def publish( *, custom_domains: typing.Optional[typing.Sequence[str]] = OMIT, publish_to_webflow_subdomain: typing.Optional[bool] = OMIT, + page_id: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> SitesPublishResponse: """ - Publishes a site to one or more more domains. + Publishes a site or an individual page to one or more domains. + If multiple individual pages are published to staging, publishing from staging to production publishes all staged changes. To publish to a specific custom domain, use the domain IDs from the [Get Custom Domains](/data/reference/sites/get-custom-domain) endpoint. + You must include at least one of the `customDomains` or `publishToWebflowSubdomain` properties in the request body. + + To publish an individual page instead of the entire site, provide the ID of the page in the `pageId` parameter. + This endpoint has a specific rate limit of one successful publish queue per minute. Required scope | `sites:write` @@ -747,6 +774,9 @@ async def publish( publish_to_webflow_subdomain : typing.Optional[bool] Choice of whether to publish to the default Webflow Subdomain + page_id : typing.Optional[str] + The ID of the page to publish + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -780,6 +810,7 @@ async def main() -> None: site_id, custom_domains=custom_domains, publish_to_webflow_subdomain=publish_to_webflow_subdomain, + page_id=page_id, request_options=request_options, ) return _response.data @@ -816,6 +847,14 @@ def well_known(self): self._well_known = AsyncWellKnownClient(client_wrapper=self._client_wrapper) return self._well_known + @property + def google_tag(self): + if self._google_tag is None: + from .resources.google_tag.client import AsyncGoogleTagClient # noqa: E402 + + self._google_tag = AsyncGoogleTagClient(client_wrapper=self._client_wrapper) + return self._google_tag + @property def activity_logs(self): if self._activity_logs is None: diff --git a/src/webflow/resources/sites/raw_client.py b/src/webflow/resources/sites/raw_client.py index cc08250..722f00e 100644 --- a/src/webflow/resources/sites/raw_client.py +++ b/src/webflow/resources/sites/raw_client.py @@ -686,13 +686,19 @@ def publish( *, custom_domains: typing.Optional[typing.Sequence[str]] = OMIT, publish_to_webflow_subdomain: typing.Optional[bool] = OMIT, + page_id: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[SitesPublishResponse]: """ - Publishes a site to one or more more domains. + Publishes a site or an individual page to one or more domains. + If multiple individual pages are published to staging, publishing from staging to production publishes all staged changes. To publish to a specific custom domain, use the domain IDs from the [Get Custom Domains](/data/reference/sites/get-custom-domain) endpoint. + You must include at least one of the `customDomains` or `publishToWebflowSubdomain` properties in the request body. + + To publish an individual page instead of the entire site, provide the ID of the page in the `pageId` parameter. + This endpoint has a specific rate limit of one successful publish queue per minute. Required scope | `sites:write` @@ -708,6 +714,9 @@ def publish( publish_to_webflow_subdomain : typing.Optional[bool] Choice of whether to publish to the default Webflow Subdomain + page_id : typing.Optional[str] + The ID of the page to publish + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -723,6 +732,7 @@ def publish( json={ "customDomains": custom_domains, "publishToWebflowSubdomain": publish_to_webflow_subdomain, + "pageId": page_id, }, headers={ "content-type": "application/json", @@ -1468,13 +1478,19 @@ async def publish( *, custom_domains: typing.Optional[typing.Sequence[str]] = OMIT, publish_to_webflow_subdomain: typing.Optional[bool] = OMIT, + page_id: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[SitesPublishResponse]: """ - Publishes a site to one or more more domains. + Publishes a site or an individual page to one or more domains. + If multiple individual pages are published to staging, publishing from staging to production publishes all staged changes. To publish to a specific custom domain, use the domain IDs from the [Get Custom Domains](/data/reference/sites/get-custom-domain) endpoint. + You must include at least one of the `customDomains` or `publishToWebflowSubdomain` properties in the request body. + + To publish an individual page instead of the entire site, provide the ID of the page in the `pageId` parameter. + This endpoint has a specific rate limit of one successful publish queue per minute. Required scope | `sites:write` @@ -1490,6 +1506,9 @@ async def publish( publish_to_webflow_subdomain : typing.Optional[bool] Choice of whether to publish to the default Webflow Subdomain + page_id : typing.Optional[str] + The ID of the page to publish + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1505,6 +1524,7 @@ async def publish( json={ "customDomains": custom_domains, "publishToWebflowSubdomain": publish_to_webflow_subdomain, + "pageId": page_id, }, headers={ "content-type": "application/json", diff --git a/src/webflow/resources/sites/resources/__init__.py b/src/webflow/resources/sites/resources/__init__.py index 529b1de..ccb2767 100644 --- a/src/webflow/resources/sites/resources/__init__.py +++ b/src/webflow/resources/sites/resources/__init__.py @@ -6,7 +6,7 @@ from importlib import import_module if typing.TYPE_CHECKING: - from . import activity_logs, comments, forms, plans, redirects, robots_txt, scripts, well_known + from . import activity_logs, comments, forms, google_tag, plans, redirects, robots_txt, scripts, well_known from .comments import ( CommentsGetCommentThreadRequestSortBy, CommentsGetCommentThreadRequestSortOrder, @@ -27,6 +27,7 @@ "activity_logs": ".activity_logs", "comments": ".comments", "forms": ".forms", + "google_tag": ".google_tag", "plans": ".plans", "redirects": ".redirects", "robots_txt": ".robots_txt", @@ -67,6 +68,7 @@ def __dir__(): "activity_logs", "comments", "forms", + "google_tag", "plans", "redirects", "robots_txt", diff --git a/src/webflow/resources/sites/resources/comments/client.py b/src/webflow/resources/sites/resources/comments/client.py index 8fbae1e..038a08e 100644 --- a/src/webflow/resources/sites/resources/comments/client.py +++ b/src/webflow/resources/sites/resources/comments/client.py @@ -59,7 +59,7 @@ def list_comment_threads( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records @@ -140,7 +140,7 @@ def get_comment_thread( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records @@ -223,7 +223,7 @@ def list_comment_replies( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records @@ -318,7 +318,7 @@ async def list_comment_threads( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records @@ -407,7 +407,7 @@ async def get_comment_thread( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records @@ -498,7 +498,7 @@ async def list_comment_replies( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records diff --git a/src/webflow/resources/sites/resources/comments/raw_client.py b/src/webflow/resources/sites/resources/comments/raw_client.py index 9502f35..caef032 100644 --- a/src/webflow/resources/sites/resources/comments/raw_client.py +++ b/src/webflow/resources/sites/resources/comments/raw_client.py @@ -60,7 +60,7 @@ def list_comment_threads( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records @@ -201,7 +201,7 @@ def get_comment_thread( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records @@ -342,7 +342,7 @@ def list_comment_replies( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records @@ -484,7 +484,7 @@ async def list_comment_threads( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records @@ -625,7 +625,7 @@ async def get_comment_thread( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records @@ -766,7 +766,7 @@ async def list_comment_replies( locale_id : typing.Optional[str] Unique identifier for a specific Locale. - [Lear more about localization.](/data/v2.0.0/docs/working-with-localization) + [Learn more about localization.](/data/v2.0.0/docs/working-with-localization) offset : typing.Optional[int] Offset used for pagination if the results have more than limit records diff --git a/src/webflow/resources/sites/resources/google_tag/__init__.py b/src/webflow/resources/sites/resources/google_tag/__init__.py new file mode 100644 index 0000000..5cde020 --- /dev/null +++ b/src/webflow/resources/sites/resources/google_tag/__init__.py @@ -0,0 +1,4 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + diff --git a/src/webflow/resources/sites/resources/google_tag/client.py b/src/webflow/resources/sites/resources/google_tag/client.py new file mode 100644 index 0000000..1c0bf6b --- /dev/null +++ b/src/webflow/resources/sites/resources/google_tag/client.py @@ -0,0 +1,388 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from .....core.request_options import RequestOptions +from .....types.google_tag_id import GoogleTagId +from .....types.google_tag_ids import GoogleTagIds +from .raw_client import AsyncRawGoogleTagClient, RawGoogleTagClient + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class GoogleTagClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawGoogleTagClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawGoogleTagClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawGoogleTagClient + """ + return self._raw_client + + def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GoogleTagIds: + """ + List all Google Tag IDs configured for a site, sorted by order. + + Required scope: `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GoogleTagIds + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.google_tag.list( + site_id="580e63e98c9a982ac9b8b741", + ) + """ + _response = self._raw_client.list(site_id, request_options=request_options) + return _response.data + + def delete_all(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: + """ + Delete all Google Tag IDs from a site. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.google_tag.delete_all( + site_id="580e63e98c9a982ac9b8b741", + ) + """ + _response = self._raw_client.delete_all(site_id, request_options=request_options) + return _response.data + + def upsert( + self, + site_id: str, + *, + google_tag_ids: typing.Sequence[GoogleTagId], + request_options: typing.Optional[RequestOptions] = None, + ) -> GoogleTagIds: + """ + Add or update Google Tag IDs for a site. Existing tags not referenced in the request are preserved. A site may have a maximum of 25 tags total. + + `order` is optional on input — it is auto-assigned for new tags and returned on all tags in the response. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + google_tag_ids : typing.Sequence[GoogleTagId] + List of Google Tags configured for a site, sorted by order. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GoogleTagIds + Request was successful + + Examples + -------- + from webflow import GoogleTagId, Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.google_tag.upsert( + site_id="580e63e98c9a982ac9b8b741", + google_tag_ids=[ + GoogleTagId( + order=0, + display_name="Main Analytics Tag", + tag_id="G-1234567890", + ) + ], + ) + """ + _response = self._raw_client.upsert(site_id, google_tag_ids=google_tag_ids, request_options=request_options) + return _response.data + + def delete( + self, site_id: str, tag_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> GoogleTagIds: + """ + Delete a single Google Tag ID from a site. The `order` values of the remaining tags are renormalized after deletion. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + tag_id : str + The Google Tag ID (e.g. G-XXXXXXXXXX) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GoogleTagIds + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.google_tag.delete( + site_id="580e63e98c9a982ac9b8b741", + tag_id="G-XXXXXXXXXX", + ) + """ + _response = self._raw_client.delete(site_id, tag_id, request_options=request_options) + return _response.data + + +class AsyncGoogleTagClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawGoogleTagClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawGoogleTagClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawGoogleTagClient + """ + return self._raw_client + + async def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GoogleTagIds: + """ + List all Google Tag IDs configured for a site, sorted by order. + + Required scope: `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GoogleTagIds + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.google_tag.list( + site_id="580e63e98c9a982ac9b8b741", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.list(site_id, request_options=request_options) + return _response.data + + async def delete_all(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: + """ + Delete all Google Tag IDs from a site. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.google_tag.delete_all( + site_id="580e63e98c9a982ac9b8b741", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_all(site_id, request_options=request_options) + return _response.data + + async def upsert( + self, + site_id: str, + *, + google_tag_ids: typing.Sequence[GoogleTagId], + request_options: typing.Optional[RequestOptions] = None, + ) -> GoogleTagIds: + """ + Add or update Google Tag IDs for a site. Existing tags not referenced in the request are preserved. A site may have a maximum of 25 tags total. + + `order` is optional on input — it is auto-assigned for new tags and returned on all tags in the response. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + google_tag_ids : typing.Sequence[GoogleTagId] + List of Google Tags configured for a site, sorted by order. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GoogleTagIds + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow, GoogleTagId + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.google_tag.upsert( + site_id="580e63e98c9a982ac9b8b741", + google_tag_ids=[ + GoogleTagId( + order=0, + display_name="Main Analytics Tag", + tag_id="G-1234567890", + ) + ], + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.upsert( + site_id, google_tag_ids=google_tag_ids, request_options=request_options + ) + return _response.data + + async def delete( + self, site_id: str, tag_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> GoogleTagIds: + """ + Delete a single Google Tag ID from a site. The `order` values of the remaining tags are renormalized after deletion. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + tag_id : str + The Google Tag ID (e.g. G-XXXXXXXXXX) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GoogleTagIds + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.google_tag.delete( + site_id="580e63e98c9a982ac9b8b741", + tag_id="G-XXXXXXXXXX", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete(site_id, tag_id, request_options=request_options) + return _response.data diff --git a/src/webflow/resources/sites/resources/google_tag/raw_client.py b/src/webflow/resources/sites/resources/google_tag/raw_client.py new file mode 100644 index 0000000..691f7bb --- /dev/null +++ b/src/webflow/resources/sites/resources/google_tag/raw_client.py @@ -0,0 +1,863 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from .....core.api_error import ApiError +from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from .....core.http_response import AsyncHttpResponse, HttpResponse +from .....core.jsonable_encoder import jsonable_encoder +from .....core.parse_error import ParsingError +from .....core.pydantic_utilities import parse_obj_as +from .....core.request_options import RequestOptions +from .....core.serialization import convert_and_respect_annotation_metadata +from .....errors.bad_request_error import BadRequestError +from .....errors.internal_server_error import InternalServerError +from .....errors.not_found_error import NotFoundError +from .....errors.too_many_requests_error import TooManyRequestsError +from .....errors.unauthorized_error import UnauthorizedError +from .....types.error import Error +from .....types.google_tag_id import GoogleTagId +from .....types.google_tag_ids import GoogleTagIds +from pydantic import ValidationError + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawGoogleTagClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def list( + self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[GoogleTagIds]: + """ + List all Google Tag IDs configured for a site, sorted by order. + + Required scope: `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[GoogleTagIds] + Request was successful + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/integrations/google_tags", + base_url=self._client_wrapper.get_environment().base, + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GoogleTagIds, + parse_obj_as( + type_=GoogleTagIds, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def delete_all( + self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[None]: + """ + Delete all Google Tag IDs from a site. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[None] + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/integrations/google_tags", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return HttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def upsert( + self, + site_id: str, + *, + google_tag_ids: typing.Sequence[GoogleTagId], + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[GoogleTagIds]: + """ + Add or update Google Tag IDs for a site. Existing tags not referenced in the request are preserved. A site may have a maximum of 25 tags total. + + `order` is optional on input — it is auto-assigned for new tags and returned on all tags in the response. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + google_tag_ids : typing.Sequence[GoogleTagId] + List of Google Tags configured for a site, sorted by order. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[GoogleTagIds] + Request was successful + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/integrations/google_tags", + base_url=self._client_wrapper.get_environment().base, + method="PATCH", + json={ + "googleTagIds": convert_and_respect_annotation_metadata( + object_=google_tag_ids, annotation=typing.Sequence[GoogleTagId], direction="write" + ), + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GoogleTagIds, + parse_obj_as( + type_=GoogleTagIds, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def delete( + self, site_id: str, tag_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[GoogleTagIds]: + """ + Delete a single Google Tag ID from a site. The `order` values of the remaining tags are renormalized after deletion. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + tag_id : str + The Google Tag ID (e.g. G-XXXXXXXXXX) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[GoogleTagIds] + Request was successful + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/integrations/google_tags/{jsonable_encoder(tag_id)}", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GoogleTagIds, + parse_obj_as( + type_=GoogleTagIds, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + +class AsyncRawGoogleTagClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list( + self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[GoogleTagIds]: + """ + List all Google Tag IDs configured for a site, sorted by order. + + Required scope: `sites:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[GoogleTagIds] + Request was successful + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/integrations/google_tags", + base_url=self._client_wrapper.get_environment().base, + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GoogleTagIds, + parse_obj_as( + type_=GoogleTagIds, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def delete_all( + self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[None]: + """ + Delete all Google Tag IDs from a site. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[None] + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/integrations/google_tags", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def upsert( + self, + site_id: str, + *, + google_tag_ids: typing.Sequence[GoogleTagId], + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[GoogleTagIds]: + """ + Add or update Google Tag IDs for a site. Existing tags not referenced in the request are preserved. A site may have a maximum of 25 tags total. + + `order` is optional on input — it is auto-assigned for new tags and returned on all tags in the response. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + google_tag_ids : typing.Sequence[GoogleTagId] + List of Google Tags configured for a site, sorted by order. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[GoogleTagIds] + Request was successful + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/integrations/google_tags", + base_url=self._client_wrapper.get_environment().base, + method="PATCH", + json={ + "googleTagIds": convert_and_respect_annotation_metadata( + object_=google_tag_ids, annotation=typing.Sequence[GoogleTagId], direction="write" + ), + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GoogleTagIds, + parse_obj_as( + type_=GoogleTagIds, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def delete( + self, site_id: str, tag_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[GoogleTagIds]: + """ + Delete a single Google Tag ID from a site. The `order` values of the remaining tags are renormalized after deletion. + + Required scope: `sites:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + tag_id : str + The Google Tag ID (e.g. G-XXXXXXXXXX) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[GoogleTagIds] + Request was successful + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/integrations/google_tags/{jsonable_encoder(tag_id)}", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GoogleTagIds, + parse_obj_as( + type_=GoogleTagIds, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) diff --git a/src/webflow/resources/sites/resources/redirects/raw_client.py b/src/webflow/resources/sites/resources/redirects/raw_client.py index d5abafe..77063ec 100644 --- a/src/webflow/resources/sites/resources/redirects/raw_client.py +++ b/src/webflow/resources/sites/resources/redirects/raw_client.py @@ -180,9 +180,6 @@ def create( "fromUrl": from_url, "toUrl": to_url, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -419,9 +416,6 @@ def update( "fromUrl": from_url, "toUrl": to_url, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -658,9 +652,6 @@ async def create( "fromUrl": from_url, "toUrl": to_url, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -897,9 +888,6 @@ async def update( "fromUrl": from_url, "toUrl": to_url, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) diff --git a/src/webflow/resources/sites/resources/robots_txt/raw_client.py b/src/webflow/resources/sites/resources/robots_txt/raw_client.py index ac8d1fe..3f47690 100644 --- a/src/webflow/resources/sites/resources/robots_txt/raw_client.py +++ b/src/webflow/resources/sites/resources/robots_txt/raw_client.py @@ -174,9 +174,6 @@ def put( ), "sitemap": sitemap, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -300,9 +297,6 @@ def delete( ), "sitemap": sitemap, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -424,9 +418,6 @@ def patch( ), "sitemap": sitemap, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -656,9 +647,6 @@ async def put( ), "sitemap": sitemap, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -782,9 +770,6 @@ async def delete( ), "sitemap": sitemap, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -906,9 +891,6 @@ async def patch( ), "sitemap": sitemap, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) diff --git a/src/webflow/resources/sites/resources/scripts/client.py b/src/webflow/resources/sites/resources/scripts/client.py index f7cddec..69d1b5a 100644 --- a/src/webflow/resources/sites/resources/scripts/client.py +++ b/src/webflow/resources/sites/resources/scripts/client.py @@ -38,6 +38,8 @@ def get_custom_code( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -83,6 +85,8 @@ def upsert_custom_code( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -189,6 +193,8 @@ def list_custom_code_blocks( See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -254,6 +260,8 @@ async def get_custom_code( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -307,6 +315,8 @@ async def upsert_custom_code( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -431,6 +441,8 @@ async def list_custom_code_blocks( See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters diff --git a/src/webflow/resources/sites/resources/scripts/raw_client.py b/src/webflow/resources/sites/resources/scripts/raw_client.py index a5e6bb6..e60a37c 100644 --- a/src/webflow/resources/sites/resources/scripts/raw_client.py +++ b/src/webflow/resources/sites/resources/scripts/raw_client.py @@ -40,6 +40,8 @@ def get_custom_code( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -151,6 +153,8 @@ def upsert_custom_code( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -186,9 +190,6 @@ def upsert_custom_code( "lastUpdated": last_updated, "createdOn": created_on, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -380,6 +381,8 @@ def list_custom_code_blocks( See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -500,6 +503,8 @@ async def get_custom_code( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters @@ -611,6 +616,8 @@ async def upsert_custom_code( To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:write` Parameters @@ -646,9 +653,6 @@ async def upsert_custom_code( "lastUpdated": last_updated, "createdOn": created_on, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -840,6 +844,8 @@ async def list_custom_code_blocks( See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app). + Required scope | `custom_code:read` Parameters diff --git a/src/webflow/resources/sites/types/__init__.py b/src/webflow/resources/sites/types/__init__.py index 960aec6..85cd533 100644 --- a/src/webflow/resources/sites/types/__init__.py +++ b/src/webflow/resources/sites/types/__init__.py @@ -7,7 +7,11 @@ if typing.TYPE_CHECKING: from .sites_publish_response import SitesPublishResponse -_dynamic_imports: typing.Dict[str, str] = {"SitesPublishResponse": ".sites_publish_response"} + from .sites_publish_response_publish_scope import SitesPublishResponsePublishScope +_dynamic_imports: typing.Dict[str, str] = { + "SitesPublishResponse": ".sites_publish_response", + "SitesPublishResponsePublishScope": ".sites_publish_response_publish_scope", +} def __getattr__(attr_name: str) -> typing.Any: @@ -31,4 +35,4 @@ def __dir__(): return sorted(lazy_attrs) -__all__ = ["SitesPublishResponse"] +__all__ = ["SitesPublishResponse", "SitesPublishResponsePublishScope"] diff --git a/src/webflow/resources/sites/types/sites_publish_response.py b/src/webflow/resources/sites/types/sites_publish_response.py index d32e70c..18debc2 100644 --- a/src/webflow/resources/sites/types/sites_publish_response.py +++ b/src/webflow/resources/sites/types/sites_publish_response.py @@ -7,6 +7,7 @@ from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel from ....core.serialization import FieldMetadata from ....types.domain import Domain +from .sites_publish_response_publish_scope import SitesPublishResponsePublishScope class SitesPublishResponse(UniversalBaseModel): @@ -20,6 +21,11 @@ class SitesPublishResponse(UniversalBaseModel): FieldMetadata(alias="publishToWebflowSubdomain"), pydantic.Field(alias="publishToWebflowSubdomain", description="Flag for publishing to webflow.io subdomain"), ] = None + publish_scope: typing_extensions.Annotated[ + typing.Optional[SitesPublishResponsePublishScope], + FieldMetadata(alias="publishScope"), + pydantic.Field(alias="publishScope", description="Whether the site or an individual page was published"), + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/webflow/resources/sites/types/sites_publish_response_publish_scope.py b/src/webflow/resources/sites/types/sites_publish_response_publish_scope.py new file mode 100644 index 0000000..11ce327 --- /dev/null +++ b/src/webflow/resources/sites/types/sites_publish_response_publish_scope.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +SitesPublishResponsePublishScope = typing.Union[typing.Literal["site", "page"], typing.Any] diff --git a/src/webflow/resources/token/client.py b/src/webflow/resources/token/client.py index d4712d7..019dd4c 100644 --- a/src/webflow/resources/token/client.py +++ b/src/webflow/resources/token/client.py @@ -56,7 +56,7 @@ def introspect(self, *, request_options: typing.Optional[RequestOptions] = None) """ Information about the authorization token - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/data-clients/getting-started). Parameters ---------- @@ -136,7 +136,7 @@ async def introspect(self, *, request_options: typing.Optional[RequestOptions] = """ Information about the authorization token - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/data-clients/getting-started). Parameters ---------- diff --git a/src/webflow/resources/token/raw_client.py b/src/webflow/resources/token/raw_client.py index ea49a25..bef7137 100644 --- a/src/webflow/resources/token/raw_client.py +++ b/src/webflow/resources/token/raw_client.py @@ -88,7 +88,7 @@ def introspect(self, *, request_options: typing.Optional[RequestOptions] = None) """ Information about the authorization token - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/data-clients/getting-started). Parameters ---------- @@ -212,7 +212,7 @@ async def introspect( """ Information about the authorization token - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/data-clients/getting-started). Parameters ---------- diff --git a/src/webflow/resources/webhooks/client.py b/src/webflow/resources/webhooks/client.py index 4360526..28b5d56 100644 --- a/src/webflow/resources/webhooks/client.py +++ b/src/webflow/resources/webhooks/client.py @@ -82,7 +82,7 @@ def create( Limit of 75 registrations per `triggerType`, per site. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/data-clients/getting-started). Required scope | `sites:write` Parameters @@ -300,7 +300,7 @@ async def create( Limit of 75 registrations per `triggerType`, per site. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/data-clients/getting-started). Required scope | `sites:write` Parameters diff --git a/src/webflow/resources/webhooks/raw_client.py b/src/webflow/resources/webhooks/raw_client.py index ca4462d..902e9c9 100644 --- a/src/webflow/resources/webhooks/raw_client.py +++ b/src/webflow/resources/webhooks/raw_client.py @@ -152,7 +152,7 @@ def create( Limit of 75 registrations per `triggerType`, per site. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/data-clients/getting-started). Required scope | `sites:write` Parameters @@ -207,9 +207,6 @@ def create( "lastTriggered": last_triggered, "createdOn": created_on, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) @@ -602,7 +599,7 @@ async def create( Limit of 75 registrations per `triggerType`, per site. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/data-clients/getting-started). Required scope | `sites:write` Parameters @@ -657,9 +654,6 @@ async def create( "lastTriggered": last_triggered, "createdOn": created_on, }, - headers={ - "content-type": "application/json", - }, request_options=request_options, omit=OMIT, ) diff --git a/src/webflow/types/__init__.py b/src/webflow/types/__init__.py index 88c0cbd..0d72e87 100644 --- a/src/webflow/types/__init__.py +++ b/src/webflow/types/__init__.py @@ -6,6 +6,12 @@ from importlib import import_module if typing.TYPE_CHECKING: + from .analyze_bucket_time_zone import AnalyzeBucketTimeZone + from .analyze_daily_bucketing import AnalyzeDailyBucketing + from .analyze_daily_timeseries_query import AnalyzeDailyTimeseriesQuery + from .analyze_filter_operators import AnalyzeFilterOperators + from .analyze_time_on_page_bucketing import AnalyzeTimeOnPageBucketing + from .analyze_window import AnalyzeWindow from .application import Application from .asset import Asset from .asset_folder import AssetFolder @@ -68,12 +74,24 @@ from .component_node import ComponentNode from .component_properties import ComponentProperties from .component_property import ComponentProperty - from .component_property_type import ComponentPropertyType + from .component_property_text import ComponentPropertyText + from .component_property_text_type import ComponentPropertyTextType from .conflict import Conflict from .custom_code_block import CustomCodeBlock from .custom_code_block_type import CustomCodeBlockType from .custom_code_hosted_response import CustomCodeHostedResponse from .custom_code_inline_response import CustomCodeInlineResponse + from .custom_font import CustomFont + from .custom_font_axis import CustomFontAxis + from .custom_font_batch_delete_response import CustomFontBatchDeleteResponse + from .custom_font_batch_delete_response_deleted_item import CustomFontBatchDeleteResponseDeletedItem + from .custom_font_batch_delete_response_failed_item import CustomFontBatchDeleteResponseFailedItem + from .custom_font_create_response import CustomFontCreateResponse + from .custom_font_font_display import CustomFontFontDisplay + from .custom_font_format import CustomFontFormat + from .custom_font_upload import CustomFontUpload + from .custom_font_upload_fields import CustomFontUploadFields + from .custom_fonts import CustomFonts from .custom_role import CustomRole from .custom_role_audit_log_item import CustomRoleAuditLogItem from .custom_role_audit_log_item_event_sub_type import CustomRoleAuditLogItemEventSubType @@ -88,9 +106,6 @@ from .field_type import FieldType from .field_validations import FieldValidations from .field_validations_additional_properties import FieldValidationsAdditionalProperties - from .field_validations_additional_properties_additional_properties import ( - FieldValidationsAdditionalPropertiesAdditionalProperties, - ) from .forbidden_error_body import ForbiddenErrorBody from .form import Form from .form_field import FormField @@ -104,14 +119,20 @@ from .form_submission_trigger_payload import FormSubmissionTriggerPayload from .form_submission_trigger_payload_schema_item import FormSubmissionTriggerPayloadSchemaItem from .form_submission_trigger_payload_schema_item_field_type import FormSubmissionTriggerPayloadSchemaItemFieldType + from .google_tag_id import GoogleTagId + from .google_tag_ids import GoogleTagIds from .image_node import ImageNode from .image_node_image import ImageNodeImage from .invalid_domain import InvalidDomain from .invalid_scopes import InvalidScopes from .inventory_item import InventoryItem from .inventory_item_inventory_type import InventoryItemInventoryType + from .items_list_items_live_request_created_on import ItemsListItemsLiveRequestCreatedOn from .items_list_items_live_request_last_published import ItemsListItemsLiveRequestLastPublished + from .items_list_items_live_request_last_updated import ItemsListItemsLiveRequestLastUpdated + from .items_list_items_request_created_on import ItemsListItemsRequestCreatedOn from .items_list_items_request_last_published import ItemsListItemsRequestLastPublished + from .items_list_items_request_last_updated import ItemsListItemsRequestLastUpdated from .list_custom_code_blocks import ListCustomCodeBlocks from .locale import Locale from .locales import Locales @@ -201,8 +222,10 @@ from .single_locale_created_payload_field_data import SingleLocaleCreatedPayloadFieldData from .site import Site from .site_activity_log_item import SiteActivityLogItem + from .site_activity_log_item_actor_type import SiteActivityLogItemActorType from .site_activity_log_item_event import SiteActivityLogItemEvent from .site_activity_log_item_resource_operation import SiteActivityLogItemResourceOperation + from .site_activity_log_item_source import SiteActivityLogItemSource from .site_activity_log_item_user import SiteActivityLogItemUser from .site_activity_log_response import SiteActivityLogResponse from .site_data_collection_type import SiteDataCollectionType @@ -214,6 +237,7 @@ from .site_plan_name import SitePlanName from .site_publish import SitePublish from .site_publish_payload import SitePublishPayload + from .site_publish_payload_publish_scope import SitePublishPayloadPublishScope from .sites import Sites from .sku import Sku from .sku_field_data import SkuFieldData @@ -243,6 +267,32 @@ from .text_node import TextNode from .text_node_text import TextNodeText from .text_node_write import TextNodeWrite + from .time_on_page_data_point import TimeOnPageDataPoint + from .time_on_page_filter import TimeOnPageFilter + from .time_on_page_granularity_period import TimeOnPageGranularityPeriod + from .time_on_page_metric_scope import TimeOnPageMetricScope + from .time_on_page_response import TimeOnPageResponse + from .time_on_page_timeseries_query import TimeOnPageTimeseriesQuery + from .top_dimensions_dimension import TopDimensionsDimension + from .top_dimensions_filter import TopDimensionsFilter + from .top_dimensions_metric_scope import TopDimensionsMetricScope + from .top_dimensions_response import TopDimensionsResponse + from .top_dimensions_row import TopDimensionsRow + from .top_events_cms_context_entry import TopEventsCmsContextEntry + from .top_events_component_context_entry import TopEventsComponentContextEntry + from .top_events_filter import TopEventsFilter + from .top_events_response import TopEventsResponse + from .top_events_row import TopEventsRow + from .top_events_timeseries_point import TopEventsTimeseriesPoint + from .top_pages_filter import TopPagesFilter + from .top_pages_response import TopPagesResponse + from .top_pages_row import TopPagesRow + from .top_pages_sort_by import TopPagesSortBy + from .top_pages_timeseries_point import TopPagesTimeseriesPoint + from .traffic_data_point import TrafficDataPoint + from .traffic_filter import TrafficFilter + from .traffic_metric_scope import TrafficMetricScope + from .traffic_response import TrafficResponse from .trigger_type import TriggerType from .updated_order import UpdatedOrder from .user_access import UserAccess @@ -306,6 +356,12 @@ from .workspace_membership_audit_log_item import WorkspaceMembershipAuditLogItem from .workspace_membership_audit_log_item_event_sub_type import WorkspaceMembershipAuditLogItemEventSubType _dynamic_imports: typing.Dict[str, str] = { + "AnalyzeBucketTimeZone": ".analyze_bucket_time_zone", + "AnalyzeDailyBucketing": ".analyze_daily_bucketing", + "AnalyzeDailyTimeseriesQuery": ".analyze_daily_timeseries_query", + "AnalyzeFilterOperators": ".analyze_filter_operators", + "AnalyzeTimeOnPageBucketing": ".analyze_time_on_page_bucketing", + "AnalyzeWindow": ".analyze_window", "Application": ".application", "Asset": ".asset", "AssetFolder": ".asset_folder", @@ -366,12 +422,24 @@ "ComponentNode": ".component_node", "ComponentProperties": ".component_properties", "ComponentProperty": ".component_property", - "ComponentPropertyType": ".component_property_type", + "ComponentPropertyText": ".component_property_text", + "ComponentPropertyTextType": ".component_property_text_type", "Conflict": ".conflict", "CustomCodeBlock": ".custom_code_block", "CustomCodeBlockType": ".custom_code_block_type", "CustomCodeHostedResponse": ".custom_code_hosted_response", "CustomCodeInlineResponse": ".custom_code_inline_response", + "CustomFont": ".custom_font", + "CustomFontAxis": ".custom_font_axis", + "CustomFontBatchDeleteResponse": ".custom_font_batch_delete_response", + "CustomFontBatchDeleteResponseDeletedItem": ".custom_font_batch_delete_response_deleted_item", + "CustomFontBatchDeleteResponseFailedItem": ".custom_font_batch_delete_response_failed_item", + "CustomFontCreateResponse": ".custom_font_create_response", + "CustomFontFontDisplay": ".custom_font_font_display", + "CustomFontFormat": ".custom_font_format", + "CustomFontUpload": ".custom_font_upload", + "CustomFontUploadFields": ".custom_font_upload_fields", + "CustomFonts": ".custom_fonts", "CustomRole": ".custom_role", "CustomRoleAuditLogItem": ".custom_role_audit_log_item", "CustomRoleAuditLogItemEventSubType": ".custom_role_audit_log_item_event_sub_type", @@ -386,7 +454,6 @@ "FieldType": ".field_type", "FieldValidations": ".field_validations", "FieldValidationsAdditionalProperties": ".field_validations_additional_properties", - "FieldValidationsAdditionalPropertiesAdditionalProperties": ".field_validations_additional_properties_additional_properties", "ForbiddenErrorBody": ".forbidden_error_body", "Form": ".form", "FormField": ".form_field", @@ -400,14 +467,20 @@ "FormSubmissionTriggerPayload": ".form_submission_trigger_payload", "FormSubmissionTriggerPayloadSchemaItem": ".form_submission_trigger_payload_schema_item", "FormSubmissionTriggerPayloadSchemaItemFieldType": ".form_submission_trigger_payload_schema_item_field_type", + "GoogleTagId": ".google_tag_id", + "GoogleTagIds": ".google_tag_ids", "ImageNode": ".image_node", "ImageNodeImage": ".image_node_image", "InvalidDomain": ".invalid_domain", "InvalidScopes": ".invalid_scopes", "InventoryItem": ".inventory_item", "InventoryItemInventoryType": ".inventory_item_inventory_type", + "ItemsListItemsLiveRequestCreatedOn": ".items_list_items_live_request_created_on", "ItemsListItemsLiveRequestLastPublished": ".items_list_items_live_request_last_published", + "ItemsListItemsLiveRequestLastUpdated": ".items_list_items_live_request_last_updated", + "ItemsListItemsRequestCreatedOn": ".items_list_items_request_created_on", "ItemsListItemsRequestLastPublished": ".items_list_items_request_last_published", + "ItemsListItemsRequestLastUpdated": ".items_list_items_request_last_updated", "ListCustomCodeBlocks": ".list_custom_code_blocks", "Locale": ".locale", "Locales": ".locales", @@ -495,8 +568,10 @@ "SingleLocaleCreatedPayloadFieldData": ".single_locale_created_payload_field_data", "Site": ".site", "SiteActivityLogItem": ".site_activity_log_item", + "SiteActivityLogItemActorType": ".site_activity_log_item_actor_type", "SiteActivityLogItemEvent": ".site_activity_log_item_event", "SiteActivityLogItemResourceOperation": ".site_activity_log_item_resource_operation", + "SiteActivityLogItemSource": ".site_activity_log_item_source", "SiteActivityLogItemUser": ".site_activity_log_item_user", "SiteActivityLogResponse": ".site_activity_log_response", "SiteDataCollectionType": ".site_data_collection_type", @@ -508,6 +583,7 @@ "SitePlanName": ".site_plan_name", "SitePublish": ".site_publish", "SitePublishPayload": ".site_publish_payload", + "SitePublishPayloadPublishScope": ".site_publish_payload_publish_scope", "Sites": ".sites", "Sku": ".sku", "SkuFieldData": ".sku_field_data", @@ -535,6 +611,32 @@ "TextNode": ".text_node", "TextNodeText": ".text_node_text", "TextNodeWrite": ".text_node_write", + "TimeOnPageDataPoint": ".time_on_page_data_point", + "TimeOnPageFilter": ".time_on_page_filter", + "TimeOnPageGranularityPeriod": ".time_on_page_granularity_period", + "TimeOnPageMetricScope": ".time_on_page_metric_scope", + "TimeOnPageResponse": ".time_on_page_response", + "TimeOnPageTimeseriesQuery": ".time_on_page_timeseries_query", + "TopDimensionsDimension": ".top_dimensions_dimension", + "TopDimensionsFilter": ".top_dimensions_filter", + "TopDimensionsMetricScope": ".top_dimensions_metric_scope", + "TopDimensionsResponse": ".top_dimensions_response", + "TopDimensionsRow": ".top_dimensions_row", + "TopEventsCmsContextEntry": ".top_events_cms_context_entry", + "TopEventsComponentContextEntry": ".top_events_component_context_entry", + "TopEventsFilter": ".top_events_filter", + "TopEventsResponse": ".top_events_response", + "TopEventsRow": ".top_events_row", + "TopEventsTimeseriesPoint": ".top_events_timeseries_point", + "TopPagesFilter": ".top_pages_filter", + "TopPagesResponse": ".top_pages_response", + "TopPagesRow": ".top_pages_row", + "TopPagesSortBy": ".top_pages_sort_by", + "TopPagesTimeseriesPoint": ".top_pages_timeseries_point", + "TrafficDataPoint": ".traffic_data_point", + "TrafficFilter": ".traffic_filter", + "TrafficMetricScope": ".traffic_metric_scope", + "TrafficResponse": ".traffic_response", "TriggerType": ".trigger_type", "UpdatedOrder": ".updated_order", "UserAccess": ".user_access", @@ -598,6 +700,12 @@ def __dir__(): __all__ = [ + "AnalyzeBucketTimeZone", + "AnalyzeDailyBucketing", + "AnalyzeDailyTimeseriesQuery", + "AnalyzeFilterOperators", + "AnalyzeTimeOnPageBucketing", + "AnalyzeWindow", "Application", "Asset", "AssetFolder", @@ -658,12 +766,24 @@ def __dir__(): "ComponentNode", "ComponentProperties", "ComponentProperty", - "ComponentPropertyType", + "ComponentPropertyText", + "ComponentPropertyTextType", "Conflict", "CustomCodeBlock", "CustomCodeBlockType", "CustomCodeHostedResponse", "CustomCodeInlineResponse", + "CustomFont", + "CustomFontAxis", + "CustomFontBatchDeleteResponse", + "CustomFontBatchDeleteResponseDeletedItem", + "CustomFontBatchDeleteResponseFailedItem", + "CustomFontCreateResponse", + "CustomFontFontDisplay", + "CustomFontFormat", + "CustomFontUpload", + "CustomFontUploadFields", + "CustomFonts", "CustomRole", "CustomRoleAuditLogItem", "CustomRoleAuditLogItemEventSubType", @@ -678,7 +798,6 @@ def __dir__(): "FieldType", "FieldValidations", "FieldValidationsAdditionalProperties", - "FieldValidationsAdditionalPropertiesAdditionalProperties", "ForbiddenErrorBody", "Form", "FormField", @@ -692,14 +811,20 @@ def __dir__(): "FormSubmissionTriggerPayload", "FormSubmissionTriggerPayloadSchemaItem", "FormSubmissionTriggerPayloadSchemaItemFieldType", + "GoogleTagId", + "GoogleTagIds", "ImageNode", "ImageNodeImage", "InvalidDomain", "InvalidScopes", "InventoryItem", "InventoryItemInventoryType", + "ItemsListItemsLiveRequestCreatedOn", "ItemsListItemsLiveRequestLastPublished", + "ItemsListItemsLiveRequestLastUpdated", + "ItemsListItemsRequestCreatedOn", "ItemsListItemsRequestLastPublished", + "ItemsListItemsRequestLastUpdated", "ListCustomCodeBlocks", "Locale", "Locales", @@ -787,8 +912,10 @@ def __dir__(): "SingleLocaleCreatedPayloadFieldData", "Site", "SiteActivityLogItem", + "SiteActivityLogItemActorType", "SiteActivityLogItemEvent", "SiteActivityLogItemResourceOperation", + "SiteActivityLogItemSource", "SiteActivityLogItemUser", "SiteActivityLogResponse", "SiteDataCollectionType", @@ -800,6 +927,7 @@ def __dir__(): "SitePlanName", "SitePublish", "SitePublishPayload", + "SitePublishPayloadPublishScope", "Sites", "Sku", "SkuFieldData", @@ -827,6 +955,32 @@ def __dir__(): "TextNode", "TextNodeText", "TextNodeWrite", + "TimeOnPageDataPoint", + "TimeOnPageFilter", + "TimeOnPageGranularityPeriod", + "TimeOnPageMetricScope", + "TimeOnPageResponse", + "TimeOnPageTimeseriesQuery", + "TopDimensionsDimension", + "TopDimensionsFilter", + "TopDimensionsMetricScope", + "TopDimensionsResponse", + "TopDimensionsRow", + "TopEventsCmsContextEntry", + "TopEventsComponentContextEntry", + "TopEventsFilter", + "TopEventsResponse", + "TopEventsRow", + "TopEventsTimeseriesPoint", + "TopPagesFilter", + "TopPagesResponse", + "TopPagesRow", + "TopPagesSortBy", + "TopPagesTimeseriesPoint", + "TrafficDataPoint", + "TrafficFilter", + "TrafficMetricScope", + "TrafficResponse", "TriggerType", "UpdatedOrder", "UserAccess", diff --git a/src/webflow/types/analyze_bucket_time_zone.py b/src/webflow/types/analyze_bucket_time_zone.py new file mode 100644 index 0000000..ccd99dc --- /dev/null +++ b/src/webflow/types/analyze_bucket_time_zone.py @@ -0,0 +1,3 @@ +# This file was auto-generated by Fern from our API Definition. + +AnalyzeBucketTimeZone = str diff --git a/src/webflow/types/analyze_daily_bucketing.py b/src/webflow/types/analyze_daily_bucketing.py new file mode 100644 index 0000000..b0d8835 --- /dev/null +++ b/src/webflow/types/analyze_daily_bucketing.py @@ -0,0 +1,33 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_bucket_time_zone import AnalyzeBucketTimeZone + + +class AnalyzeDailyBucketing(UniversalBaseModel): + """ + Daily bucketing applied to a response. + """ + + granularity_period: typing_extensions.Annotated[ + typing.Literal["day"], + FieldMetadata(alias="granularityPeriod"), + pydantic.Field(alias="granularityPeriod", description="Bucket size used for this response."), + ] = "day" + bucket_time_zone: typing_extensions.Annotated[ + AnalyzeBucketTimeZone, FieldMetadata(alias="bucketTimeZone"), pydantic.Field(alias="bucketTimeZone") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/analyze_daily_timeseries_query.py b/src/webflow/types/analyze_daily_timeseries_query.py new file mode 100644 index 0000000..08f45b1 --- /dev/null +++ b/src/webflow/types/analyze_daily_timeseries_query.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_bucket_time_zone import AnalyzeBucketTimeZone + + +class AnalyzeDailyTimeseriesQuery(UniversalBaseModel): + """ + Options that opt a report into daily timeseries data. + """ + + bucket_time_zone: typing_extensions.Annotated[ + AnalyzeBucketTimeZone, FieldMetadata(alias="bucketTimeZone"), pydantic.Field(alias="bucketTimeZone") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/analyze_filter_operators.py b/src/webflow/types/analyze_filter_operators.py new file mode 100644 index 0000000..8646a0f --- /dev/null +++ b/src/webflow/types/analyze_filter_operators.py @@ -0,0 +1,46 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata + + +class AnalyzeFilterOperators(UniversalBaseModel): + """ + Operators for filtering a single dimension. Specify at least one of `eq`, `in`, `ne`, or `nin`. + """ + + eq: typing.Optional[str] = pydantic.Field(default=None) + """ + Match values exactly equal to the provided value. + """ + + in_: typing_extensions.Annotated[ + typing.Optional[typing.List[str]], + FieldMetadata(alias="in"), + pydantic.Field( + alias="in", + description="Match values in the provided list. Use indexed bracket notation — `filter[][in][0]=value1&filter[][in][1]=value2`. Comma-separated values (for example, `filter[][in]=value1,value2`) are not supported.", + ), + ] = None + ne: typing.Optional[str] = pydantic.Field(default=None) + """ + Exclude values exactly equal to the provided value. + """ + + nin: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Exclude values in the provided list. Use indexed bracket notation — `filter[][nin][0]=value1&filter[][nin][1]=value2`. Comma-separated values (for example, `filter[][nin]=value1,value2`) are not supported. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/analyze_time_on_page_bucketing.py b/src/webflow/types/analyze_time_on_page_bucketing.py new file mode 100644 index 0000000..953ec22 --- /dev/null +++ b/src/webflow/types/analyze_time_on_page_bucketing.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_bucket_time_zone import AnalyzeBucketTimeZone +from .time_on_page_granularity_period import TimeOnPageGranularityPeriod + + +class AnalyzeTimeOnPageBucketing(UniversalBaseModel): + """ + Bucketing applied to a time on page response. + """ + + granularity_period: typing_extensions.Annotated[ + TimeOnPageGranularityPeriod, FieldMetadata(alias="granularityPeriod"), pydantic.Field(alias="granularityPeriod") + ] + bucket_time_zone: typing_extensions.Annotated[ + AnalyzeBucketTimeZone, FieldMetadata(alias="bucketTimeZone"), pydantic.Field(alias="bucketTimeZone") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/analyze_window.py b/src/webflow/types/analyze_window.py new file mode 100644 index 0000000..657c94c --- /dev/null +++ b/src/webflow/types/analyze_window.py @@ -0,0 +1,39 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata + + +class AnalyzeWindow(UniversalBaseModel): + """ + A reporting time window. `endTime` must be greater than `startTime`. + """ + + start_time: typing_extensions.Annotated[ + dt.datetime, + FieldMetadata(alias="startTime"), + pydantic.Field( + alias="startTime", description="Inclusive start of the reporting window, in ISO 8601 / RFC 3339 format." + ), + ] + end_time: typing_extensions.Annotated[ + dt.datetime, + FieldMetadata(alias="endTime"), + pydantic.Field( + alias="endTime", description="Exclusive end of the reporting window, in ISO 8601 / RFC 3339 format." + ), + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/asset.py b/src/webflow/types/asset.py index eb3425d..4921b37 100644 --- a/src/webflow/types/asset.py +++ b/src/webflow/types/asset.py @@ -70,6 +70,14 @@ class Asset(UniversalBaseModel): FieldMetadata(alias="altText"), pydantic.Field(alias="altText", description="The visual description of the asset"), ] = None + folder_id: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="folderId"), + pydantic.Field( + alias="folderId", + description="The ID of the folder the asset belongs to, or `null` if the asset is at the site root.\nThis field is present only in list responses (`GET /sites/{site_id}/assets`).", + ), + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/webflow/types/comment_payload.py b/src/webflow/types/comment_payload.py index 8b51391..b77fb0b 100644 --- a/src/webflow/types/comment_payload.py +++ b/src/webflow/types/comment_payload.py @@ -38,18 +38,15 @@ class CommentPayload(UniversalBaseModel): page_id: typing_extensions.Annotated[ typing.Optional[str], FieldMetadata(alias="pageId"), - pydantic.Field(alias="pageId", description="The page unique identifier"), + pydantic.Field( + alias="pageId", description="The page unique identifier, or for CMS item comments, the template page ID" + ), ] = None locale_id: typing_extensions.Annotated[ typing.Optional[str], FieldMetadata(alias="localeId"), pydantic.Field(alias="localeId", description="The locale unique identifier"), ] = None - item_id: typing_extensions.Annotated[ - typing.Optional[str], - FieldMetadata(alias="itemId"), - pydantic.Field(alias="itemId", description="The item unique identifier"), - ] = None breakpoint: typing.Optional[str] = pydantic.Field(default=None) """ The breakpoint the comment was left on diff --git a/src/webflow/types/component_property.py b/src/webflow/types/component_property.py index 4583f4d..fd30a17 100644 --- a/src/webflow/types/component_property.py +++ b/src/webflow/types/component_property.py @@ -1,45 +1,5 @@ # This file was auto-generated by Fern from our API Definition. -import typing +from .component_property_text import ComponentPropertyText -import pydantic -import typing_extensions -from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from ..core.serialization import FieldMetadata -from .component_property_type import ComponentPropertyType -from .text import Text - - -class ComponentProperty(UniversalBaseModel): - """ - Represents a property of a component instance in the DOM. A property contains a list of both the raw text and the HTML representation, allowing for flexibility in rendering and processing. Additional attributes can be associated with the text for styling or other purposes. - """ - - property_id: typing_extensions.Annotated[ - typing.Optional[str], - FieldMetadata(alias="propertyId"), - pydantic.Field(alias="propertyId", description="The ID of the property."), - ] = None - type: typing.Optional[ComponentPropertyType] = pydantic.Field(default=None) - """ - The type of the property. - """ - - label: typing.Optional[str] = pydantic.Field(default=None) - """ - The label of the property in the UI. - """ - - text: typing.Optional[Text] = pydantic.Field(default=None) - """ - Represents text content within the DOM. It contains both the raw text and its HTML representation. - """ - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow +ComponentProperty = ComponentPropertyText diff --git a/src/webflow/types/component_property_text.py b/src/webflow/types/component_property_text.py new file mode 100644 index 0000000..c708551 --- /dev/null +++ b/src/webflow/types/component_property_text.py @@ -0,0 +1,45 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .component_property_text_type import ComponentPropertyTextType +from .text import Text + + +class ComponentPropertyText(UniversalBaseModel): + """ + A text-based component property containing raw text and HTML representation. + """ + + property_id: typing_extensions.Annotated[ + str, + FieldMetadata(alias="propertyId"), + pydantic.Field(alias="propertyId", description="The ID of the property."), + ] + type: ComponentPropertyTextType = pydantic.Field() + """ + The type of the property. + """ + + label: str = pydantic.Field() + """ + The label of the property in the UI. + """ + + text: Text = pydantic.Field() + """ + Represents text content within the DOM. It contains both the raw text and its HTML representation. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/component_property_text_type.py b/src/webflow/types/component_property_text_type.py new file mode 100644 index 0000000..6038e5c --- /dev/null +++ b/src/webflow/types/component_property_text_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ComponentPropertyTextType = typing.Union[typing.Literal["Plain Text", "Rich Text", "Alt Text"], typing.Any] diff --git a/src/webflow/types/component_property_type.py b/src/webflow/types/component_property_type.py deleted file mode 100644 index 117b2fe..0000000 --- a/src/webflow/types/component_property_type.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -ComponentPropertyType = typing.Union[typing.Literal["Plain Text", "Rich Text", "Alt Text"], typing.Any] diff --git a/src/webflow/types/custom_font.py b/src/webflow/types/custom_font.py new file mode 100644 index 0000000..598edc3 --- /dev/null +++ b/src/webflow/types/custom_font.py @@ -0,0 +1,72 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .custom_font_axis import CustomFontAxis +from .custom_font_font_display import CustomFontFontDisplay +from .custom_font_format import CustomFontFormat + + +class CustomFont(UniversalBaseModel): + """ + A custom font uploaded to a Webflow site + """ + + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Unique identifier for the custom font + """ + + font_family: typing_extensions.Annotated[ + str, + FieldMetadata(alias="fontFamily"), + pydantic.Field(alias="fontFamily", description="The CSS font-family name. Commas are stripped server-side."), + ] + format: typing.Optional[CustomFontFormat] = pydantic.Field(default=None) + """ + The font file format, derived from the file extension. The value `svg` represents read-only legacy data; new SVG font uploads are not accepted. + """ + + file_name: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="fileName"), + pydantic.Field(alias="fileName", description="The file name supplied at upload time"), + ] = None + weight: int = pydantic.Field() + """ + The CSS font-weight value (1–1000) + """ + + italic: bool = pydantic.Field() + """ + Whether the font is italic + """ + + font_display: typing_extensions.Annotated[ + CustomFontFontDisplay, + FieldMetadata(alias="fontDisplay"), + pydantic.Field(alias="fontDisplay", description="The CSS font-display value"), + ] + axes: typing.List[CustomFontAxis] = pydantic.Field() + """ + Variable font axes. An empty array indicates a static font. + """ + + hosted_url: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="hostedUrl"), + pydantic.Field(alias="hostedUrl", description="CDN URL for the font binary"), + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/custom_font_axis.py b/src/webflow/types/custom_font_axis.py new file mode 100644 index 0000000..297084d --- /dev/null +++ b/src/webflow/types/custom_font_axis.py @@ -0,0 +1,52 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata + + +class CustomFontAxis(UniversalBaseModel): + """ + A variable font axis definition + """ + + tag: str = pydantic.Field() + """ + The four-character OpenType axis tag, consisting of exactly 4 printable ASCII characters (for example, `wght`, `opsz`, `slnt`, `wdth`) + """ + + name: typing.Optional[str] = pydantic.Field(default=None) + """ + Optional human-readable label for the axis + """ + + min: float = pydantic.Field() + """ + Minimum value for the axis + """ + + max: float = pydantic.Field() + """ + Maximum value for the axis + """ + + default_value: typing_extensions.Annotated[ + float, + FieldMetadata(alias="defaultValue"), + pydantic.Field( + alias="defaultValue", + description="Default value for the axis. Must be between `min` and `max` (inclusive). Violating this constraint returns `400 BadArgument` with an error prefixed `fontMetadata.axes`.", + ), + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/custom_font_batch_delete_response.py b/src/webflow/types/custom_font_batch_delete_response.py new file mode 100644 index 0000000..42e7872 --- /dev/null +++ b/src/webflow/types/custom_font_batch_delete_response.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .custom_font_batch_delete_response_deleted_item import CustomFontBatchDeleteResponseDeletedItem +from .custom_font_batch_delete_response_failed_item import CustomFontBatchDeleteResponseFailedItem + + +class CustomFontBatchDeleteResponse(UniversalBaseModel): + """ + Per-item result of a bulk-delete operation + """ + + deleted: typing.List[CustomFontBatchDeleteResponseDeletedItem] + failed: typing.List[CustomFontBatchDeleteResponseFailedItem] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/custom_font_batch_delete_response_deleted_item.py b/src/webflow/types/custom_font_batch_delete_response_deleted_item.py new file mode 100644 index 0000000..6113e81 --- /dev/null +++ b/src/webflow/types/custom_font_batch_delete_response_deleted_item.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class CustomFontBatchDeleteResponseDeletedItem(UniversalBaseModel): + id: str = pydantic.Field() + """ + The ID of a successfully deleted custom font + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/custom_font_batch_delete_response_failed_item.py b/src/webflow/types/custom_font_batch_delete_response_failed_item.py new file mode 100644 index 0000000..b61ca09 --- /dev/null +++ b/src/webflow/types/custom_font_batch_delete_response_failed_item.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class CustomFontBatchDeleteResponseFailedItem(UniversalBaseModel): + id: str = pydantic.Field() + """ + The ID of a custom font that could not be deleted + """ + + name: str = pydantic.Field() + """ + Error name + """ + + msg: str = pydantic.Field() + """ + Human-readable error message + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/custom_font_create_response.py b/src/webflow/types/custom_font_create_response.py new file mode 100644 index 0000000..a5aa156 --- /dev/null +++ b/src/webflow/types/custom_font_create_response.py @@ -0,0 +1,30 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .custom_font import CustomFont +from .custom_font_upload import CustomFontUpload + + +class CustomFontCreateResponse(UniversalBaseModel): + """ + The response to a successful custom font creation or file replacement request + """ + + custom_font: typing_extensions.Annotated[ + CustomFont, FieldMetadata(alias="customFont"), pydantic.Field(alias="customFont") + ] + upload: CustomFontUpload + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/custom_font_font_display.py b/src/webflow/types/custom_font_font_display.py new file mode 100644 index 0000000..bf19bca --- /dev/null +++ b/src/webflow/types/custom_font_font_display.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CustomFontFontDisplay = typing.Union[typing.Literal["auto", "block", "swap", "fallback", "optional"], typing.Any] diff --git a/src/webflow/types/custom_font_format.py b/src/webflow/types/custom_font_format.py new file mode 100644 index 0000000..3f0635b --- /dev/null +++ b/src/webflow/types/custom_font_format.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CustomFontFormat = typing.Union[ + typing.Literal["woff2", "woff", "truetype", "opentype", "embedded-opentype", "svg"], typing.Any +] diff --git a/src/webflow/types/custom_font_upload.py b/src/webflow/types/custom_font_upload.py new file mode 100644 index 0000000..b2c4b46 --- /dev/null +++ b/src/webflow/types/custom_font_upload.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .custom_font_upload_fields import CustomFontUploadFields + + +class CustomFontUpload(UniversalBaseModel): + """ + Presigned S3 upload details. Post the font binary to `url` as `multipart/form-data`, including every key from `fields` plus the binary itself in a field named `file`. The `file` field must be the last field in the form. + """ + + url: str = pydantic.Field() + """ + The S3 endpoint to POST the font binary to + """ + + fields: CustomFontUploadFields + expires_at: typing_extensions.Annotated[ + dt.datetime, + FieldMetadata(alias="expiresAt"), + pydantic.Field( + alias="expiresAt", + description="ISO 8601 timestamp after which the presigned URL expires (approximately 15 minutes from issuance)", + ), + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/custom_font_upload_fields.py b/src/webflow/types/custom_font_upload_fields.py new file mode 100644 index 0000000..35552aa --- /dev/null +++ b/src/webflow/types/custom_font_upload_fields.py @@ -0,0 +1,94 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata + + +class CustomFontUploadFields(UniversalBaseModel): + """ + Form fields to include in the S3 multipart POST. Every key must be sent as a form field before the `file` field. + """ + + bucket: str = pydantic.Field() + """ + The S3 bucket name + """ + + key: str = pydantic.Field() + """ + The S3 object key + """ + + policy: typing_extensions.Annotated[ + str, + FieldMetadata(alias="Policy"), + pydantic.Field(alias="Policy", description="Base64-encoded S3 policy document"), + ] + x_amz_algorithm: typing_extensions.Annotated[ + str, + FieldMetadata(alias="X-Amz-Algorithm"), + pydantic.Field(alias="X-Amz-Algorithm", description="AWS Signature Version 4 algorithm identifier"), + ] + x_amz_credential: typing_extensions.Annotated[ + str, + FieldMetadata(alias="X-Amz-Credential"), + pydantic.Field(alias="X-Amz-Credential", description="AWS credential string"), + ] + x_amz_date: typing_extensions.Annotated[ + str, + FieldMetadata(alias="X-Amz-Date"), + pydantic.Field(alias="X-Amz-Date", description="Request date in ISO 8601 basic format"), + ] + x_amz_signature: typing_extensions.Annotated[ + str, + FieldMetadata(alias="X-Amz-Signature"), + pydantic.Field(alias="X-Amz-Signature", description="AWS Signature Version 4 signature"), + ] + x_amz_security_token: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="X-Amz-Security-Token"), + pydantic.Field( + alias="X-Amz-Security-Token", + description="AWS security token (included when temporary credentials are used)", + ), + ] = None + content_md_5: typing_extensions.Annotated[ + str, + FieldMetadata(alias="Content-MD5"), + pydantic.Field( + alias="Content-MD5", + description="Base64-encoded MD5 hash of the file binary, derived from the `fileHash` you supplied", + ), + ] + acl: str = pydantic.Field() + """ + S3 ACL. Always `public-read`, which makes the uploaded font accessible to the Webflow CDN. + """ + + cache_control: typing_extensions.Annotated[ + str, + FieldMetadata(alias="Cache-Control"), + pydantic.Field(alias="Cache-Control", description="Cache-Control header value applied to the S3 object"), + ] + content_type: typing_extensions.Annotated[ + str, + FieldMetadata(alias="Content-Type"), + pydantic.Field(alias="Content-Type", description="MIME type matched to the file extension"), + ] + success_action_status: str = pydantic.Field() + """ + S3 returns this HTTP status code on a successful upload + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/field_validations_additional_properties_additional_properties.py b/src/webflow/types/custom_fonts.py similarity index 61% rename from src/webflow/types/field_validations_additional_properties_additional_properties.py rename to src/webflow/types/custom_fonts.py index 0c676dd..062b671 100644 --- a/src/webflow/types/field_validations_additional_properties_additional_properties.py +++ b/src/webflow/types/custom_fonts.py @@ -6,12 +6,19 @@ import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel from ..core.serialization import FieldMetadata +from .custom_font import CustomFont +from .pagination import Pagination -class FieldValidationsAdditionalPropertiesAdditionalProperties(UniversalBaseModel): - additional_properties: typing_extensions.Annotated[ - typing.Any, FieldMetadata(alias="additionalProperties"), pydantic.Field(alias="additionalProperties") +class CustomFonts(UniversalBaseModel): + """ + A list of custom fonts + """ + + custom_fonts: typing_extensions.Annotated[ + typing.List[CustomFont], FieldMetadata(alias="customFonts"), pydantic.Field(alias="customFonts") ] + pagination: Pagination if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/webflow/types/error_code.py b/src/webflow/types/error_code.py index f9149eb..23dcdae 100644 --- a/src/webflow/types/error_code.py +++ b/src/webflow/types/error_code.py @@ -4,7 +4,11 @@ ErrorCode = typing.Union[ typing.Literal[ + "analyze_filter_conflict", + "analyze_input_validation", + "analyze_unsupported_filter", "bad_request", + "before_historical_floor", "collection_not_found", "conflict", "duplicate_collection", @@ -17,6 +21,7 @@ "invalid_auth_version", "invalid_credentials", "invalid_domain", + "invalid_time_range", "invalid_user_email", "item_not_found", "missing_scopes", @@ -26,6 +31,8 @@ "not_enterprise_plan_workspace", "order_not_found", "resource_not_found", + "service_unavailable", + "time_range_too_wide", "too_many_requests", "unsupported_version", "unsupported_webhook_trigger_type", diff --git a/src/webflow/types/field_validations_additional_properties.py b/src/webflow/types/field_validations_additional_properties.py index 845d42f..4e4a1df 100644 --- a/src/webflow/types/field_validations_additional_properties.py +++ b/src/webflow/types/field_validations_additional_properties.py @@ -2,10 +2,4 @@ import typing -from .field_validations_additional_properties_additional_properties import ( - FieldValidationsAdditionalPropertiesAdditionalProperties, -) - -FieldValidationsAdditionalProperties = typing.Union[ - str, float, bool, int, FieldValidationsAdditionalPropertiesAdditionalProperties -] +FieldValidationsAdditionalProperties = typing.Union[str, float, bool, int, typing.Any] diff --git a/src/webflow/types/form_submission.py b/src/webflow/types/form_submission.py index adf12b7..19301fd 100644 --- a/src/webflow/types/form_submission.py +++ b/src/webflow/types/form_submission.py @@ -40,6 +40,14 @@ class FormSubmission(UniversalBaseModel): FieldMetadata(alias="formResponse"), pydantic.Field(alias="formResponse", description="The data submitted in the Form"), ] = None + locale_id: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="localeId"), + pydantic.Field( + alias="localeId", + description="The ID of the locale the form was submitted from. `null` for primary-locale submissions or sites without localization.", + ), + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/webflow/types/form_submission_trigger_payload.py b/src/webflow/types/form_submission_trigger_payload.py index d715049..43cf81f 100644 --- a/src/webflow/types/form_submission_trigger_payload.py +++ b/src/webflow/types/form_submission_trigger_payload.py @@ -54,6 +54,14 @@ class FormSubmissionTriggerPayload(UniversalBaseModel): FieldMetadata(alias="formElementId"), pydantic.Field(alias="formElementId", description="The uniqueID of the Form element"), ] = None + locale_id: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="localeId"), + pydantic.Field( + alias="localeId", + description="The ID of the locale the form was submitted from. `null` for primary-locale submissions or sites without localization.", + ), + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/webflow/types/google_tag_id.py b/src/webflow/types/google_tag_id.py new file mode 100644 index 0000000..6671d24 --- /dev/null +++ b/src/webflow/types/google_tag_id.py @@ -0,0 +1,42 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata + + +class GoogleTagId(UniversalBaseModel): + """ + A Google Tag associated with a site. + """ + + order: typing.Optional[int] = pydantic.Field(default=None) + """ + Display order of the tag. Optional on input; always present on output. Auto-assigned for new tags and renormalized after deletion. + """ + + display_name: typing_extensions.Annotated[ + str, + FieldMetadata(alias="displayName"), + pydantic.Field(alias="displayName", description="A human-readable label for the tag."), + ] + tag_id: typing_extensions.Annotated[ + str, + FieldMetadata(alias="tagId"), + pydantic.Field( + alias="tagId", + description="The Google Tag ID. Accepts G-, GT-, AW-, and DC- prefixes. Rejects UA- prefixes.", + ), + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/google_tag_ids.py b/src/webflow/types/google_tag_ids.py new file mode 100644 index 0000000..21cdb69 --- /dev/null +++ b/src/webflow/types/google_tag_ids.py @@ -0,0 +1,30 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .google_tag_id import GoogleTagId + + +class GoogleTagIds(UniversalBaseModel): + """ + A list of Google Tags configured for a site. + """ + + google_tag_ids: typing_extensions.Annotated[ + typing.List[GoogleTagId], + FieldMetadata(alias="googleTagIds"), + pydantic.Field(alias="googleTagIds", description="List of Google Tags configured for a site, sorted by order."), + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/items_list_items_live_request_created_on.py b/src/webflow/types/items_list_items_live_request_created_on.py new file mode 100644 index 0000000..93a7ec1 --- /dev/null +++ b/src/webflow/types/items_list_items_live_request_created_on.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ItemsListItemsLiveRequestCreatedOn(UniversalBaseModel): + lte: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + Filter items created before this date + """ + + gte: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + Filter items created after this date + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/items_list_items_live_request_last_updated.py b/src/webflow/types/items_list_items_live_request_last_updated.py new file mode 100644 index 0000000..fc621f8 --- /dev/null +++ b/src/webflow/types/items_list_items_live_request_last_updated.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ItemsListItemsLiveRequestLastUpdated(UniversalBaseModel): + lte: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + Filter items last updated before this date + """ + + gte: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + Filter items last updated after this date + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/items_list_items_request_created_on.py b/src/webflow/types/items_list_items_request_created_on.py new file mode 100644 index 0000000..f67078c --- /dev/null +++ b/src/webflow/types/items_list_items_request_created_on.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ItemsListItemsRequestCreatedOn(UniversalBaseModel): + lte: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + Filter items created before this date + """ + + gte: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + Filter items created after this date + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/items_list_items_request_last_updated.py b/src/webflow/types/items_list_items_request_last_updated.py new file mode 100644 index 0000000..cd3e1ef --- /dev/null +++ b/src/webflow/types/items_list_items_request_last_updated.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ItemsListItemsRequestLastUpdated(UniversalBaseModel): + lte: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + Filter items last updated before this date + """ + + gte: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + Filter items last updated after this date + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/page_created_webhook_payload.py b/src/webflow/types/page_created_webhook_payload.py index 4dd3385..be0d1ca 100644 --- a/src/webflow/types/page_created_webhook_payload.py +++ b/src/webflow/types/page_created_webhook_payload.py @@ -23,6 +23,26 @@ class PageCreatedWebhookPayload(UniversalBaseModel): page_title: typing_extensions.Annotated[ typing.Optional[str], FieldMetadata(alias="pageTitle"), pydantic.Field(alias="pageTitle") ] = None + page_name: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="pageName"), + pydantic.Field(alias="pageName", description="The display name of the page, or null if not set"), + ] = None + archived: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether the page is archived + """ + + draft: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether the page is a draft + """ + + is_branch: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="isBranch"), + pydantic.Field(alias="isBranch", description="Whether the page belongs to a branch"), + ] = None created_on: typing_extensions.Annotated[ typing.Optional[dt.datetime], FieldMetadata(alias="createdOn"), pydantic.Field(alias="createdOn") ] = None diff --git a/src/webflow/types/page_deleted_webhook_payload.py b/src/webflow/types/page_deleted_webhook_payload.py index e78f589..f2df40e 100644 --- a/src/webflow/types/page_deleted_webhook_payload.py +++ b/src/webflow/types/page_deleted_webhook_payload.py @@ -23,6 +23,26 @@ class PageDeletedWebhookPayload(UniversalBaseModel): page_title: typing_extensions.Annotated[ typing.Optional[str], FieldMetadata(alias="pageTitle"), pydantic.Field(alias="pageTitle") ] = None + page_name: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="pageName"), + pydantic.Field(alias="pageName", description="The display name of the page, or null if not set"), + ] = None + archived: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether the page is archived + """ + + draft: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether the page is a draft + """ + + is_branch: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="isBranch"), + pydantic.Field(alias="isBranch", description="Whether the page belongs to a branch"), + ] = None deleted_on: typing_extensions.Annotated[ typing.Optional[dt.datetime], FieldMetadata(alias="deletedOn"), pydantic.Field(alias="deletedOn") ] = None diff --git a/src/webflow/types/page_metadata_updated_webhook_payload.py b/src/webflow/types/page_metadata_updated_webhook_payload.py index d71cf47..31283e0 100644 --- a/src/webflow/types/page_metadata_updated_webhook_payload.py +++ b/src/webflow/types/page_metadata_updated_webhook_payload.py @@ -23,6 +23,26 @@ class PageMetadataUpdatedWebhookPayload(UniversalBaseModel): page_title: typing_extensions.Annotated[ typing.Optional[str], FieldMetadata(alias="pageTitle"), pydantic.Field(alias="pageTitle") ] = None + page_name: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="pageName"), + pydantic.Field(alias="pageName", description="The display name of the page, or null if not set"), + ] = None + archived: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether the page is archived + """ + + draft: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether the page is a draft + """ + + is_branch: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="isBranch"), + pydantic.Field(alias="isBranch", description="Whether the page belongs to a branch"), + ] = None last_updated: typing_extensions.Annotated[ typing.Optional[dt.datetime], FieldMetadata(alias="lastUpdated"), pydantic.Field(alias="lastUpdated") ] = None diff --git a/src/webflow/types/site_activity_log_item.py b/src/webflow/types/site_activity_log_item.py index cc07cef..01e4d7b 100644 --- a/src/webflow/types/site_activity_log_item.py +++ b/src/webflow/types/site_activity_log_item.py @@ -7,8 +7,10 @@ import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel from ..core.serialization import FieldMetadata +from .site_activity_log_item_actor_type import SiteActivityLogItemActorType from .site_activity_log_item_event import SiteActivityLogItemEvent from .site_activity_log_item_resource_operation import SiteActivityLogItemResourceOperation +from .site_activity_log_item_source import SiteActivityLogItemSource from .site_activity_log_item_user import SiteActivityLogItemUser @@ -40,6 +42,35 @@ class SiteActivityLogItem(UniversalBaseModel): typing.Optional[str], FieldMetadata(alias="previousValue"), pydantic.Field(alias="previousValue") ] = None payload: typing.Optional[typing.Dict[str, typing.Any]] = None + source: typing.Optional[SiteActivityLogItemSource] = pydantic.Field(default=None) + """ + The system that originated the event. `WEBFLOW_AI` for Webflow AI features, `WEBFLOW_MCP` for an external MCP server or Bridge App, `DESIGNER` for human writes from the Designer, and `SYSTEM` for automated Webflow processes such as backups or migrations. `null` for legacy events recorded before attribution was available. + """ + + actor_type: typing_extensions.Annotated[ + typing.Optional[SiteActivityLogItemActorType], + FieldMetadata(alias="actorType"), + pydantic.Field( + alias="actorType", + description="The type of actor responsible for the event. `user` for a human who directly triggered or accepted the action, `agent` for a fully autonomous AI agent, `workflow` for a user-created workflow that ran autonomously, and `rule` for an autonomous rule that fired on a trigger. `null` for legacy events.", + ), + ] = None + actor_id: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="actorId"), + pydantic.Field( + alias="actorId", + description="Unique identifier of the actor that originated the event. `null` when not available.", + ), + ] = None + actor_name: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="actorName"), + pydantic.Field( + alias="actorName", + description="Display name of the actor that originated the event. `null` when not available.", + ), + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/webflow/types/site_activity_log_item_actor_type.py b/src/webflow/types/site_activity_log_item_actor_type.py new file mode 100644 index 0000000..1746b29 --- /dev/null +++ b/src/webflow/types/site_activity_log_item_actor_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +SiteActivityLogItemActorType = typing.Union[typing.Literal["user", "agent", "workflow", "rule"], typing.Any] diff --git a/src/webflow/types/site_activity_log_item_source.py b/src/webflow/types/site_activity_log_item_source.py new file mode 100644 index 0000000..6a704c0 --- /dev/null +++ b/src/webflow/types/site_activity_log_item_source.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +SiteActivityLogItemSource = typing.Union[typing.Literal["WEBFLOW_AI", "WEBFLOW_MCP", "DESIGNER", "SYSTEM"], typing.Any] diff --git a/src/webflow/types/site_publish_payload.py b/src/webflow/types/site_publish_payload.py index 3e61145..2bcadfe 100644 --- a/src/webflow/types/site_publish_payload.py +++ b/src/webflow/types/site_publish_payload.py @@ -7,6 +7,7 @@ import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel from ..core.serialization import FieldMetadata +from .site_publish_payload_publish_scope import SitePublishPayloadPublishScope class SitePublishPayload(UniversalBaseModel): @@ -32,7 +33,17 @@ class SitePublishPayload(UniversalBaseModel): published_by: typing_extensions.Annotated[ typing.Optional[typing.Dict[str, typing.Any]], FieldMetadata(alias="publishedBy"), - pydantic.Field(alias="publishedBy", description="The name andID of the user who published the site"), + pydantic.Field(alias="publishedBy", description="The name and ID of the user who published the site"), + ] = None + publish_scope: typing_extensions.Annotated[ + typing.Optional[SitePublishPayloadPublishScope], + FieldMetadata(alias="publishScope"), + pydantic.Field(alias="publishScope", description="Whether the entire site or an individual page was published"), + ] = None + page_id: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="pageId"), + pydantic.Field(alias="pageId", description="The ID of the page that was published"), ] = None if IS_PYDANTIC_V2: diff --git a/src/webflow/types/site_publish_payload_publish_scope.py b/src/webflow/types/site_publish_payload_publish_scope.py new file mode 100644 index 0000000..029f208 --- /dev/null +++ b/src/webflow/types/site_publish_payload_publish_scope.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +SitePublishPayloadPublishScope = typing.Union[typing.Literal["page", "site"], typing.Any] diff --git a/src/webflow/types/time_on_page_data_point.py b/src/webflow/types/time_on_page_data_point.py new file mode 100644 index 0000000..5fee487 --- /dev/null +++ b/src/webflow/types/time_on_page_data_point.py @@ -0,0 +1,38 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata + + +class TimeOnPageDataPoint(UniversalBaseModel): + """ + A single average time on page data point. When `timeseries` is omitted, the response holds one aggregate point covering the whole window; otherwise it returns one point per requested bucket. + """ + + timestamp: dt.datetime = pydantic.Field() + """ + Start of the bucket, in ISO 8601 / RFC 3339 format. For an aggregate result, this is the start of the requested window. + """ + + average_seconds: typing_extensions.Annotated[ + float, + FieldMetadata(alias="averageSeconds"), + pydantic.Field( + alias="averageSeconds", + description="Average time on page for this bucket, in seconds, in units of the request's `metricScope`.", + ), + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/time_on_page_filter.py b/src/webflow/types/time_on_page_filter.py new file mode 100644 index 0000000..d1eee7e --- /dev/null +++ b/src/webflow/types/time_on_page_filter.py @@ -0,0 +1,114 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_filter_operators import AnalyzeFilterOperators + + +class TimeOnPageFilter(UniversalBaseModel): + """ + Filter the time on page report by dimension. Each property is an optional set of `AnalyzeFilterOperators` (`eq`, `in`, `ne`, `nin`) applied to the named dimension. Filter a given dimension in one place — either inside `filter` or as a top-level query parameter. + """ + + audience_ids: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="audienceIds"), pydantic.Field(alias="audienceIds") + ] = None + browser: typing.Optional[AnalyzeFilterOperators] = None + collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="collectionId"), + pydantic.Field(alias="collectionId"), + ] = None + country: typing.Optional[AnalyzeFilterOperators] = None + day_of_week: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="dayOfWeek"), pydantic.Field(alias="dayOfWeek") + ] = None + device_brand: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="deviceBrand"), pydantic.Field(alias="deviceBrand") + ] = None + device_type: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="deviceType"), pydantic.Field(alias="deviceType") + ] = None + domain: typing.Optional[AnalyzeFilterOperators] = None + item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="itemSlug"), pydantic.Field(alias="itemSlug") + ] = None + language: typing.Optional[AnalyzeFilterOperators] = None + locale: typing.Optional[AnalyzeFilterOperators] = None + next_collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="nextCollectionId"), + pydantic.Field(alias="nextCollectionId"), + ] = None + next_item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="nextItemSlug"), + pydantic.Field(alias="nextItemSlug"), + ] = None + next_page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="nextPageId"), pydantic.Field(alias="nextPageId") + ] = None + os: typing.Optional[AnalyzeFilterOperators] = None + page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId") + ] = None + page_path: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="pagePath"), pydantic.Field(alias="pagePath") + ] = None + previous_collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousCollectionId"), + pydantic.Field(alias="previousCollectionId"), + ] = None + previous_item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousItemSlug"), + pydantic.Field(alias="previousItemSlug"), + ] = None + previous_page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousPageId"), + pydantic.Field(alias="previousPageId"), + ] = None + referrer: typing.Optional[AnalyzeFilterOperators] = None + region: typing.Optional[AnalyzeFilterOperators] = None + time_of_day: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="timeOfDay"), pydantic.Field(alias="timeOfDay") + ] = None + timezone: typing.Optional[AnalyzeFilterOperators] = None + traffic_source: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="trafficSource"), + pydantic.Field(alias="trafficSource"), + ] = None + utm_campaign: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmCampaign"), pydantic.Field(alias="utmCampaign") + ] = None + utm_content: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmContent"), pydantic.Field(alias="utmContent") + ] = None + utm_medium: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmMedium"), pydantic.Field(alias="utmMedium") + ] = None + utm_source: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmSource"), pydantic.Field(alias="utmSource") + ] = None + utm_term: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmTerm"), pydantic.Field(alias="utmTerm") + ] = None + visit_status: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="visitStatus"), pydantic.Field(alias="visitStatus") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/time_on_page_granularity_period.py b/src/webflow/types/time_on_page_granularity_period.py new file mode 100644 index 0000000..f0337bf --- /dev/null +++ b/src/webflow/types/time_on_page_granularity_period.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +TimeOnPageGranularityPeriod = typing.Union[typing.Literal["day", "week"], typing.Any] diff --git a/src/webflow/types/time_on_page_metric_scope.py b/src/webflow/types/time_on_page_metric_scope.py new file mode 100644 index 0000000..a65f864 --- /dev/null +++ b/src/webflow/types/time_on_page_metric_scope.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +TimeOnPageMetricScope = typing.Union[typing.Literal["session", "user", "pageview"], typing.Any] diff --git a/src/webflow/types/time_on_page_response.py b/src/webflow/types/time_on_page_response.py new file mode 100644 index 0000000..9384104 --- /dev/null +++ b/src/webflow/types/time_on_page_response.py @@ -0,0 +1,45 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_time_on_page_bucketing import AnalyzeTimeOnPageBucketing +from .analyze_window import AnalyzeWindow +from .time_on_page_data_point import TimeOnPageDataPoint +from .time_on_page_filter import TimeOnPageFilter +from .time_on_page_metric_scope import TimeOnPageMetricScope + + +class TimeOnPageResponse(UniversalBaseModel): + """ + Response payload for the time on page report. + """ + + report: typing.Literal["time_on_page"] = pydantic.Field(default="time_on_page") + """ + Discriminator identifying the report type. + """ + + window: AnalyzeWindow + metric_scope: typing_extensions.Annotated[ + TimeOnPageMetricScope, FieldMetadata(alias="metricScope"), pydantic.Field(alias="metricScope") + ] + bucketing: typing.Optional[AnalyzeTimeOnPageBucketing] = None + data: typing.List[TimeOnPageDataPoint] = pydantic.Field() + """ + Average time on page over the requested window — one aggregate point when `timeseries` is omitted, otherwise one point per bucket. + """ + + filter: typing.Optional[TimeOnPageFilter] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/time_on_page_timeseries_query.py b/src/webflow/types/time_on_page_timeseries_query.py new file mode 100644 index 0000000..4930c08 --- /dev/null +++ b/src/webflow/types/time_on_page_timeseries_query.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_bucket_time_zone import AnalyzeBucketTimeZone +from .time_on_page_granularity_period import TimeOnPageGranularityPeriod + + +class TimeOnPageTimeseriesQuery(UniversalBaseModel): + """ + Options that opt the time on page report into bucketed timeseries data. + """ + + granularity_period: typing_extensions.Annotated[ + TimeOnPageGranularityPeriod, FieldMetadata(alias="granularityPeriod"), pydantic.Field(alias="granularityPeriod") + ] + bucket_time_zone: typing_extensions.Annotated[ + AnalyzeBucketTimeZone, FieldMetadata(alias="bucketTimeZone"), pydantic.Field(alias="bucketTimeZone") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_dimensions_dimension.py b/src/webflow/types/top_dimensions_dimension.py new file mode 100644 index 0000000..513e9d8 --- /dev/null +++ b/src/webflow/types/top_dimensions_dimension.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +TopDimensionsDimension = typing.Union[ + typing.Literal[ + "country", + "region", + "deviceType", + "os", + "browser", + "language", + "locale", + "referrer", + "trafficSource", + "utmCampaign", + "utmContent", + "utmMedium", + "utmSource", + "utmTerm", + "audienceIds", + ], + typing.Any, +] diff --git a/src/webflow/types/top_dimensions_filter.py b/src/webflow/types/top_dimensions_filter.py new file mode 100644 index 0000000..80f7c36 --- /dev/null +++ b/src/webflow/types/top_dimensions_filter.py @@ -0,0 +1,114 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_filter_operators import AnalyzeFilterOperators + + +class TopDimensionsFilter(UniversalBaseModel): + """ + Filter the top dimensions report by dimension. Each property is an optional set of `AnalyzeFilterOperators` (`eq`, `in`, `ne`, `nin`) applied to the named dimension. Filter a given dimension in one place — either inside `filter` or as a top-level query parameter. + """ + + audience_ids: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="audienceIds"), pydantic.Field(alias="audienceIds") + ] = None + browser: typing.Optional[AnalyzeFilterOperators] = None + collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="collectionId"), + pydantic.Field(alias="collectionId"), + ] = None + country: typing.Optional[AnalyzeFilterOperators] = None + day_of_week: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="dayOfWeek"), pydantic.Field(alias="dayOfWeek") + ] = None + device_brand: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="deviceBrand"), pydantic.Field(alias="deviceBrand") + ] = None + device_type: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="deviceType"), pydantic.Field(alias="deviceType") + ] = None + domain: typing.Optional[AnalyzeFilterOperators] = None + item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="itemSlug"), pydantic.Field(alias="itemSlug") + ] = None + language: typing.Optional[AnalyzeFilterOperators] = None + locale: typing.Optional[AnalyzeFilterOperators] = None + next_collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="nextCollectionId"), + pydantic.Field(alias="nextCollectionId"), + ] = None + next_item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="nextItemSlug"), + pydantic.Field(alias="nextItemSlug"), + ] = None + next_page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="nextPageId"), pydantic.Field(alias="nextPageId") + ] = None + os: typing.Optional[AnalyzeFilterOperators] = None + page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId") + ] = None + page_path: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="pagePath"), pydantic.Field(alias="pagePath") + ] = None + previous_collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousCollectionId"), + pydantic.Field(alias="previousCollectionId"), + ] = None + previous_item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousItemSlug"), + pydantic.Field(alias="previousItemSlug"), + ] = None + previous_page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousPageId"), + pydantic.Field(alias="previousPageId"), + ] = None + referrer: typing.Optional[AnalyzeFilterOperators] = None + region: typing.Optional[AnalyzeFilterOperators] = None + time_of_day: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="timeOfDay"), pydantic.Field(alias="timeOfDay") + ] = None + timezone: typing.Optional[AnalyzeFilterOperators] = None + traffic_source: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="trafficSource"), + pydantic.Field(alias="trafficSource"), + ] = None + utm_campaign: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmCampaign"), pydantic.Field(alias="utmCampaign") + ] = None + utm_content: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmContent"), pydantic.Field(alias="utmContent") + ] = None + utm_medium: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmMedium"), pydantic.Field(alias="utmMedium") + ] = None + utm_source: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmSource"), pydantic.Field(alias="utmSource") + ] = None + utm_term: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmTerm"), pydantic.Field(alias="utmTerm") + ] = None + visit_status: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="visitStatus"), pydantic.Field(alias="visitStatus") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_dimensions_metric_scope.py b/src/webflow/types/top_dimensions_metric_scope.py new file mode 100644 index 0000000..b47d786 --- /dev/null +++ b/src/webflow/types/top_dimensions_metric_scope.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +TopDimensionsMetricScope = typing.Union[typing.Literal["session", "user"], typing.Any] diff --git a/src/webflow/types/top_dimensions_response.py b/src/webflow/types/top_dimensions_response.py new file mode 100644 index 0000000..f07829b --- /dev/null +++ b/src/webflow/types/top_dimensions_response.py @@ -0,0 +1,50 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_window import AnalyzeWindow +from .top_dimensions_dimension import TopDimensionsDimension +from .top_dimensions_filter import TopDimensionsFilter +from .top_dimensions_metric_scope import TopDimensionsMetricScope +from .top_dimensions_row import TopDimensionsRow + + +class TopDimensionsResponse(UniversalBaseModel): + """ + Response payload for the top dimensions report. + """ + + report: typing.Literal["top_dimensions"] = pydantic.Field(default="top_dimensions") + """ + Discriminator identifying the report type. + """ + + window: AnalyzeWindow + dimension: TopDimensionsDimension + metric_scope: typing_extensions.Annotated[ + TopDimensionsMetricScope, FieldMetadata(alias="metricScope"), pydantic.Field(alias="metricScope") + ] + limit: int = pydantic.Field() + """ + The row cap that was applied to this response (echoes the resolved request value, including the default). + """ + + data: typing.List[TopDimensionsRow] = pydantic.Field() + """ + Dimension values ranked by `count`, descending. At most `limit` rows. + """ + + filter: typing.Optional[TopDimensionsFilter] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_dimensions_row.py b/src/webflow/types/top_dimensions_row.py new file mode 100644 index 0000000..df56874 --- /dev/null +++ b/src/webflow/types/top_dimensions_row.py @@ -0,0 +1,41 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata + + +class TopDimensionsRow(UniversalBaseModel): + """ + A single value within the chosen dimension, with its count for the requested `metricScope`. + """ + + attribute_key: typing_extensions.Annotated[ + str, + FieldMetadata(alias="attributeKey"), + pydantic.Field( + alias="attributeKey", + description="Identifier for the dimension value. Pass this back into a `filter` on any Analyze report to scope that report to this value.", + ), + ] + name: str = pydantic.Field() + """ + Display label for the dimension value. For many dimensions this matches `attributeKey`; for others (such as `region`, `trafficSource`, and `audienceIds`) it's a human-readable label. + """ + + count: int = pydantic.Field() + """ + Non-negative count for this dimension value, in units of the request's `metricScope`. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_events_cms_context_entry.py b/src/webflow/types/top_events_cms_context_entry.py new file mode 100644 index 0000000..d5edc7a --- /dev/null +++ b/src/webflow/types/top_events_cms_context_entry.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata + + +class TopEventsCmsContextEntry(UniversalBaseModel): + """ + CMS collection-list rendering context for a top event row. + """ + + collection_id: typing_extensions.Annotated[ + str, + FieldMetadata(alias="collectionId"), + pydantic.Field(alias="collectionId", description="Identifier of the CMS collection."), + ] + item_id: typing_extensions.Annotated[ + str, FieldMetadata(alias="itemId"), pydantic.Field(alias="itemId", description="Identifier of the CMS item.") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_events_component_context_entry.py b/src/webflow/types/top_events_component_context_entry.py new file mode 100644 index 0000000..dff2b15 --- /dev/null +++ b/src/webflow/types/top_events_component_context_entry.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata + + +class TopEventsComponentContextEntry(UniversalBaseModel): + """ + Component rendering context for a top event row. + """ + + component_id: typing_extensions.Annotated[ + str, + FieldMetadata(alias="componentId"), + pydantic.Field(alias="componentId", description="Identifier of the component definition."), + ] + instance_id: typing_extensions.Annotated[ + str, + FieldMetadata(alias="instanceId"), + pydantic.Field(alias="instanceId", description="Identifier of the component instance."), + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_events_filter.py b/src/webflow/types/top_events_filter.py new file mode 100644 index 0000000..9ef5777 --- /dev/null +++ b/src/webflow/types/top_events_filter.py @@ -0,0 +1,85 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_filter_operators import AnalyzeFilterOperators + + +class TopEventsFilter(UniversalBaseModel): + """ + Filter the top events report by dimension. Each property is an optional set of `AnalyzeFilterOperators` (`eq`, `in`, `ne`, `nin`) applied to the named dimension. Filter a given dimension in one place — either inside `filter` or as a top-level query parameter. + """ + + audience_ids: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="audienceIds"), pydantic.Field(alias="audienceIds") + ] = None + browser: typing.Optional[AnalyzeFilterOperators] = None + collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="collectionId"), + pydantic.Field(alias="collectionId"), + ] = None + country: typing.Optional[AnalyzeFilterOperators] = None + day_of_week: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="dayOfWeek"), pydantic.Field(alias="dayOfWeek") + ] = None + device_brand: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="deviceBrand"), pydantic.Field(alias="deviceBrand") + ] = None + device_type: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="deviceType"), pydantic.Field(alias="deviceType") + ] = None + domain: typing.Optional[AnalyzeFilterOperators] = None + item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="itemSlug"), pydantic.Field(alias="itemSlug") + ] = None + language: typing.Optional[AnalyzeFilterOperators] = None + locale: typing.Optional[AnalyzeFilterOperators] = None + os: typing.Optional[AnalyzeFilterOperators] = None + page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId") + ] = None + page_path: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="pagePath"), pydantic.Field(alias="pagePath") + ] = None + region: typing.Optional[AnalyzeFilterOperators] = None + time_of_day: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="timeOfDay"), pydantic.Field(alias="timeOfDay") + ] = None + timezone: typing.Optional[AnalyzeFilterOperators] = None + traffic_source: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="trafficSource"), + pydantic.Field(alias="trafficSource"), + ] = None + utm_campaign: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmCampaign"), pydantic.Field(alias="utmCampaign") + ] = None + utm_content: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmContent"), pydantic.Field(alias="utmContent") + ] = None + utm_medium: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmMedium"), pydantic.Field(alias="utmMedium") + ] = None + utm_source: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmSource"), pydantic.Field(alias="utmSource") + ] = None + utm_term: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmTerm"), pydantic.Field(alias="utmTerm") + ] = None + visit_status: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="visitStatus"), pydantic.Field(alias="visitStatus") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_events_response.py b/src/webflow/types/top_events_response.py new file mode 100644 index 0000000..591e8f2 --- /dev/null +++ b/src/webflow/types/top_events_response.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .analyze_daily_bucketing import AnalyzeDailyBucketing +from .analyze_window import AnalyzeWindow +from .top_events_filter import TopEventsFilter +from .top_events_row import TopEventsRow + + +class TopEventsResponse(UniversalBaseModel): + """ + Response payload for the top events report. + """ + + report: typing.Literal["top_events"] = pydantic.Field(default="top_events") + """ + Discriminator identifying the report type. + """ + + window: AnalyzeWindow + limit: int = pydantic.Field() + """ + The row cap that was applied to this response (echoes the resolved request value, including the default). + """ + + bucketing: typing.Optional[AnalyzeDailyBucketing] = None + data: typing.List[TopEventsRow] = pydantic.Field() + """ + Events ranked by `count`, descending. At most `limit` rows. + """ + + filter: typing.Optional[TopEventsFilter] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_events_row.py b/src/webflow/types/top_events_row.py new file mode 100644 index 0000000..2dc37eb --- /dev/null +++ b/src/webflow/types/top_events_row.py @@ -0,0 +1,93 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .top_events_cms_context_entry import TopEventsCmsContextEntry +from .top_events_component_context_entry import TopEventsComponentContextEntry +from .top_events_timeseries_point import TopEventsTimeseriesPoint + + +class TopEventsRow(UniversalBaseModel): + """ + A single event in the ranked response, with its event count over the requested window. Events are counted individually, not rolled up into sessions, users, or pageviews, so this report has no `metricScope` — `count` is always the number of times the event fired. + """ + + event_id: typing_extensions.Annotated[ + str, + FieldMetadata(alias="eventId"), + pydantic.Field(alias="eventId", description="Opaque identifier of the event."), + ] + name: typing.Optional[str] = pydantic.Field(default=None) + """ + Display name of the event. Omitted when the event has no name (customer-defined events may leave it blank). + """ + + page_id: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="pageId"), + pydantic.Field( + alias="pageId", + description="Identifier of the Webflow page the event is associated with. Omitted when the upstream has no page context for the event.", + ), + ] = None + page_name: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="pageName"), + pydantic.Field( + alias="pageName", description="Display name of the associated page. Omitted when the page label is unknown." + ), + ] = None + count: int = pydantic.Field() + """ + Number of times the event fired during the requested window. + """ + + component_context: typing_extensions.Annotated[ + typing.Optional[typing.List[TopEventsComponentContextEntry]], + FieldMetadata(alias="componentContext"), + pydantic.Field( + alias="componentContext", + description="Component rendering context for the event. Omitted when the event is not rendered inside a component.", + ), + ] = None + cms_context: typing_extensions.Annotated[ + typing.Optional[typing.List[TopEventsCmsContextEntry]], + FieldMetadata(alias="cmsContext"), + pydantic.Field( + alias="cmsContext", + description="CMS collection-list rendering context for the event. Omitted when the event is not rendered inside a CMS collection list.", + ), + ] = None + collection_id: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="collectionId"), + pydantic.Field( + alias="collectionId", + description="Identifier of the CMS collection the associated page belongs to. Present only for events on CMS-templated pages.", + ), + ] = None + item_slug: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="itemSlug"), + pydantic.Field( + alias="itemSlug", + description="Slug of the CMS item the associated page represents. Present only for events on CMS-templated pages.", + ), + ] = None + timeseries: typing.Optional[typing.List[TopEventsTimeseriesPoint]] = pydantic.Field(default=None) + """ + Daily count timeseries for this event over the requested window. Returned when `timeseries` is requested. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_events_timeseries_point.py b/src/webflow/types/top_events_timeseries_point.py new file mode 100644 index 0000000..251dc3e --- /dev/null +++ b/src/webflow/types/top_events_timeseries_point.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class TopEventsTimeseriesPoint(UniversalBaseModel): + """ + A single **daily** bucket in a per-event timeseries. Returned only when `timeseries` is requested. + + Buckets are aligned to local day boundaries in the response's `bucketing.bucketTimeZone`; the `timestamp` is the UTC instant for that local bucket start. A row's `timeseries` contains daily buckets for the requested window. When `timeseries` is requested but the event did not occur in the window, `timeseries` is an empty array — distinguishing "asked, none" from "didn't ask". + """ + + timestamp: dt.datetime = pydantic.Field() + """ + Start of the daily bucket, in ISO 8601 / RFC 3339 format. + """ + + count: int = pydantic.Field() + """ + Number of times the event occurred on this day. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_pages_filter.py b/src/webflow/types/top_pages_filter.py new file mode 100644 index 0000000..13df95e --- /dev/null +++ b/src/webflow/types/top_pages_filter.py @@ -0,0 +1,114 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_filter_operators import AnalyzeFilterOperators + + +class TopPagesFilter(UniversalBaseModel): + """ + Filter the top pages report by dimension. Each property is an optional set of `AnalyzeFilterOperators` (`eq`, `in`, `ne`, `nin`) applied to the named dimension. Filter a given dimension in one place — either inside `filter` or as a top-level query parameter. + """ + + audience_ids: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="audienceIds"), pydantic.Field(alias="audienceIds") + ] = None + browser: typing.Optional[AnalyzeFilterOperators] = None + collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="collectionId"), + pydantic.Field(alias="collectionId"), + ] = None + country: typing.Optional[AnalyzeFilterOperators] = None + day_of_week: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="dayOfWeek"), pydantic.Field(alias="dayOfWeek") + ] = None + device_brand: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="deviceBrand"), pydantic.Field(alias="deviceBrand") + ] = None + device_type: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="deviceType"), pydantic.Field(alias="deviceType") + ] = None + domain: typing.Optional[AnalyzeFilterOperators] = None + item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="itemSlug"), pydantic.Field(alias="itemSlug") + ] = None + language: typing.Optional[AnalyzeFilterOperators] = None + locale: typing.Optional[AnalyzeFilterOperators] = None + next_collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="nextCollectionId"), + pydantic.Field(alias="nextCollectionId"), + ] = None + next_item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="nextItemSlug"), + pydantic.Field(alias="nextItemSlug"), + ] = None + next_page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="nextPageId"), pydantic.Field(alias="nextPageId") + ] = None + os: typing.Optional[AnalyzeFilterOperators] = None + page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId") + ] = None + page_path: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="pagePath"), pydantic.Field(alias="pagePath") + ] = None + previous_collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousCollectionId"), + pydantic.Field(alias="previousCollectionId"), + ] = None + previous_item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousItemSlug"), + pydantic.Field(alias="previousItemSlug"), + ] = None + previous_page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousPageId"), + pydantic.Field(alias="previousPageId"), + ] = None + referrer: typing.Optional[AnalyzeFilterOperators] = None + region: typing.Optional[AnalyzeFilterOperators] = None + time_of_day: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="timeOfDay"), pydantic.Field(alias="timeOfDay") + ] = None + timezone: typing.Optional[AnalyzeFilterOperators] = None + traffic_source: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="trafficSource"), + pydantic.Field(alias="trafficSource"), + ] = None + utm_campaign: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmCampaign"), pydantic.Field(alias="utmCampaign") + ] = None + utm_content: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmContent"), pydantic.Field(alias="utmContent") + ] = None + utm_medium: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmMedium"), pydantic.Field(alias="utmMedium") + ] = None + utm_source: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmSource"), pydantic.Field(alias="utmSource") + ] = None + utm_term: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmTerm"), pydantic.Field(alias="utmTerm") + ] = None + visit_status: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="visitStatus"), pydantic.Field(alias="visitStatus") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_pages_response.py b/src/webflow/types/top_pages_response.py new file mode 100644 index 0000000..550c7b5 --- /dev/null +++ b/src/webflow/types/top_pages_response.py @@ -0,0 +1,48 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_daily_bucketing import AnalyzeDailyBucketing +from .analyze_window import AnalyzeWindow +from .top_pages_filter import TopPagesFilter +from .top_pages_row import TopPagesRow +from .top_pages_sort_by import TopPagesSortBy + + +class TopPagesResponse(UniversalBaseModel): + """ + Response payload for the top pages report. + """ + + report: typing.Literal["top_pages"] = pydantic.Field(default="top_pages") + """ + Discriminator identifying the report type. + """ + + window: AnalyzeWindow + sort_by: typing_extensions.Annotated[TopPagesSortBy, FieldMetadata(alias="sortBy"), pydantic.Field(alias="sortBy")] + limit: int = pydantic.Field() + """ + The row cap that was applied to this response (echoes the resolved request value, including the default). + """ + + bucketing: typing.Optional[AnalyzeDailyBucketing] = None + data: typing.List[TopPagesRow] = pydantic.Field() + """ + Pages ranked by `sortBy`, descending. At most `limit` rows. + """ + + filter: typing.Optional[TopPagesFilter] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_pages_row.py b/src/webflow/types/top_pages_row.py new file mode 100644 index 0000000..c65107e --- /dev/null +++ b/src/webflow/types/top_pages_row.py @@ -0,0 +1,76 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .top_pages_timeseries_point import TopPagesTimeseriesPoint + + +class TopPagesRow(UniversalBaseModel): + """ + A single page in the ranked response. Every row carries all three scope counts (`sessionCount`, `userCount`, `pageviewCount`); `sortBy` governs only the row ordering. + """ + + page_id: typing_extensions.Annotated[ + str, + FieldMetadata(alias="pageId"), + pydantic.Field(alias="pageId", description="Identifier of the Webflow page."), + ] + title: str = pydantic.Field() + """ + Display title for the page. Resolves to the page's CMS item name when applicable, otherwise the page label. Falls back to `pageId` when no title is available. + """ + + session_count: typing_extensions.Annotated[ + int, + FieldMetadata(alias="sessionCount"), + pydantic.Field( + alias="sessionCount", description="Sessions attributed to this page during the requested window." + ), + ] + user_count: typing_extensions.Annotated[ + int, + FieldMetadata(alias="userCount"), + pydantic.Field( + alias="userCount", description="Unique users that visited this page during the requested window." + ), + ] + pageview_count: typing_extensions.Annotated[ + int, + FieldMetadata(alias="pageviewCount"), + pydantic.Field( + alias="pageviewCount", description="Pageviews recorded for this page during the requested window." + ), + ] + collection_id: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="collectionId"), + pydantic.Field( + alias="collectionId", + description="Identifier of the CMS collection this page belongs to. Present only for CMS-templated pages.", + ), + ] = None + item_slug: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="itemSlug"), + pydantic.Field( + alias="itemSlug", + description="Slug of the CMS item this row represents. Present only for CMS-templated pages.", + ), + ] = None + timeseries: typing.Optional[typing.List[TopPagesTimeseriesPoint]] = pydantic.Field(default=None) + """ + Daily pageview timeseries for this page over the requested window. Returned when `timeseries` is requested. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/top_pages_sort_by.py b/src/webflow/types/top_pages_sort_by.py new file mode 100644 index 0000000..468ee6c --- /dev/null +++ b/src/webflow/types/top_pages_sort_by.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +TopPagesSortBy = typing.Union[typing.Literal["session", "user", "pageview"], typing.Any] diff --git a/src/webflow/types/top_pages_timeseries_point.py b/src/webflow/types/top_pages_timeseries_point.py new file mode 100644 index 0000000..5b96d1b --- /dev/null +++ b/src/webflow/types/top_pages_timeseries_point.py @@ -0,0 +1,39 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata + + +class TopPagesTimeseriesPoint(UniversalBaseModel): + """ + A single **daily** bucket in a per-page timeseries. Returned only when `timeseries` is requested. + + Buckets are aligned to local day boundaries in the response's `bucketing.bucketTimeZone`; the `timestamp` is the UTC instant for that local bucket start. A row's `timeseries` contains daily buckets for the requested window. + + Bucket counts are always pageviews, regardless of the request's `sortBy`. Row-level `sessionCount` / `userCount` / `pageviewCount` reflect `sortBy`. + """ + + timestamp: dt.datetime = pydantic.Field() + """ + Start of the daily bucket, in ISO 8601 / RFC 3339 format. + """ + + pageview_count: typing_extensions.Annotated[ + int, + FieldMetadata(alias="pageviewCount"), + pydantic.Field(alias="pageviewCount", description="Pageviews recorded for this day."), + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/traffic_data_point.py b/src/webflow/types/traffic_data_point.py new file mode 100644 index 0000000..b7d6c9c --- /dev/null +++ b/src/webflow/types/traffic_data_point.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class TrafficDataPoint(UniversalBaseModel): + """ + A single daily bucket in a traffic time series. Buckets are aligned to local day boundaries in the response's `bucketing.bucketTimeZone`; the `timestamp` is the UTC instant for that local bucket start. + """ + + timestamp: dt.datetime = pydantic.Field() + """ + Start of the daily bucket, in ISO 8601 / RFC 3339 format. + """ + + count: int = pydantic.Field() + """ + Non-negative count for this day, in units of the request's `metricScope`. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/traffic_filter.py b/src/webflow/types/traffic_filter.py new file mode 100644 index 0000000..5a48264 --- /dev/null +++ b/src/webflow/types/traffic_filter.py @@ -0,0 +1,114 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_filter_operators import AnalyzeFilterOperators + + +class TrafficFilter(UniversalBaseModel): + """ + Filter the traffic report by dimension. Each property is an optional set of `AnalyzeFilterOperators` (`eq`, `in`, `ne`, `nin`) applied to the named dimension. Filter a given dimension in one place — either inside `filter` or as a top-level query parameter. + """ + + audience_ids: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="audienceIds"), pydantic.Field(alias="audienceIds") + ] = None + browser: typing.Optional[AnalyzeFilterOperators] = None + collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="collectionId"), + pydantic.Field(alias="collectionId"), + ] = None + country: typing.Optional[AnalyzeFilterOperators] = None + day_of_week: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="dayOfWeek"), pydantic.Field(alias="dayOfWeek") + ] = None + device_brand: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="deviceBrand"), pydantic.Field(alias="deviceBrand") + ] = None + device_type: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="deviceType"), pydantic.Field(alias="deviceType") + ] = None + domain: typing.Optional[AnalyzeFilterOperators] = None + item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="itemSlug"), pydantic.Field(alias="itemSlug") + ] = None + language: typing.Optional[AnalyzeFilterOperators] = None + locale: typing.Optional[AnalyzeFilterOperators] = None + next_collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="nextCollectionId"), + pydantic.Field(alias="nextCollectionId"), + ] = None + next_item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="nextItemSlug"), + pydantic.Field(alias="nextItemSlug"), + ] = None + next_page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="nextPageId"), pydantic.Field(alias="nextPageId") + ] = None + os: typing.Optional[AnalyzeFilterOperators] = None + page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId") + ] = None + page_path: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="pagePath"), pydantic.Field(alias="pagePath") + ] = None + previous_collection_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousCollectionId"), + pydantic.Field(alias="previousCollectionId"), + ] = None + previous_item_slug: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousItemSlug"), + pydantic.Field(alias="previousItemSlug"), + ] = None + previous_page_id: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="previousPageId"), + pydantic.Field(alias="previousPageId"), + ] = None + referrer: typing.Optional[AnalyzeFilterOperators] = None + region: typing.Optional[AnalyzeFilterOperators] = None + time_of_day: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="timeOfDay"), pydantic.Field(alias="timeOfDay") + ] = None + timezone: typing.Optional[AnalyzeFilterOperators] = None + traffic_source: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], + FieldMetadata(alias="trafficSource"), + pydantic.Field(alias="trafficSource"), + ] = None + utm_campaign: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmCampaign"), pydantic.Field(alias="utmCampaign") + ] = None + utm_content: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmContent"), pydantic.Field(alias="utmContent") + ] = None + utm_medium: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmMedium"), pydantic.Field(alias="utmMedium") + ] = None + utm_source: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmSource"), pydantic.Field(alias="utmSource") + ] = None + utm_term: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="utmTerm"), pydantic.Field(alias="utmTerm") + ] = None + visit_status: typing_extensions.Annotated[ + typing.Optional[AnalyzeFilterOperators], FieldMetadata(alias="visitStatus"), pydantic.Field(alias="visitStatus") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/traffic_metric_scope.py b/src/webflow/types/traffic_metric_scope.py new file mode 100644 index 0000000..7a54a55 --- /dev/null +++ b/src/webflow/types/traffic_metric_scope.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +TrafficMetricScope = typing.Union[typing.Literal["session", "user", "pageview"], typing.Any] diff --git a/src/webflow/types/traffic_response.py b/src/webflow/types/traffic_response.py new file mode 100644 index 0000000..e89d1ad --- /dev/null +++ b/src/webflow/types/traffic_response.py @@ -0,0 +1,45 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ..core.serialization import FieldMetadata +from .analyze_daily_bucketing import AnalyzeDailyBucketing +from .analyze_window import AnalyzeWindow +from .traffic_data_point import TrafficDataPoint +from .traffic_filter import TrafficFilter +from .traffic_metric_scope import TrafficMetricScope + + +class TrafficResponse(UniversalBaseModel): + """ + Response payload for the traffic report. + """ + + report: typing.Literal["traffic"] = pydantic.Field(default="traffic") + """ + Discriminator identifying the report type. + """ + + window: AnalyzeWindow + metric_scope: typing_extensions.Annotated[ + TrafficMetricScope, FieldMetadata(alias="metricScope"), pydantic.Field(alias="metricScope") + ] + bucketing: AnalyzeDailyBucketing + data: typing.List[TrafficDataPoint] = pydantic.Field() + """ + Time-ordered series of data points covering the requested window. + """ + + filter: typing.Optional[TrafficFilter] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow