From a636bec1f1d65dd52347bc249ed193ee93d34894 Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 22:44:20 +0000 Subject: [PATCH] SDK regeneration --- .github/workflows/ci.yml | 8 +- .mock/definition/__package__.yml | 1297 ++++++++- .mock/definition/accessGroups.yml | 1 + .mock/definition/api.yml | 11 +- .mock/definition/assets.yml | 135 +- .mock/definition/collections.yml | 187 +- .mock/definition/collections/fields.yml | 119 +- .mock/definition/collections/items.yml | 545 ++-- .mock/definition/components.yml | 143 +- .mock/definition/ecommerce.yml | 1 + .mock/definition/forms.yml | 116 +- .mock/definition/inventory.yml | 2 + .mock/definition/orders.yml | 102 +- .mock/definition/pages.yml | 121 +- .mock/definition/pages/scripts.yml | 54 +- .mock/definition/products.yml | 241 +- .mock/definition/scripts.yml | 71 +- .mock/definition/sites.yml | 86 +- .mock/definition/sites/activityLogs.yml | 17 +- .mock/definition/sites/comments.yml | 323 +++ .mock/definition/sites/plans.yml | 8 +- .mock/definition/sites/redirects.yml | 41 +- .mock/definition/sites/robotsTxt.yml | 221 ++ .mock/definition/sites/scripts.yml | 52 +- .mock/definition/sites/wellKnown.yml | 114 + .mock/definition/token.yml | 2 + .mock/definition/users.yml | 50 +- .mock/definition/webhooks.yml | 15 +- .mock/definition/workspaces/auditLogs.yml | 119 + .mock/fern.config.json | 2 +- poetry.lock | 67 +- pyproject.toml | 2 +- reference.md | 2512 ++++++++++++++--- src/webflow/__init__.py | 174 +- src/webflow/client.py | 35 +- src/webflow/core/client_wrapper.py | 29 +- src/webflow/environment.py | 22 +- src/webflow/resources/__init__.py | 9 +- src/webflow/resources/access_groups/client.py | 2 + src/webflow/resources/assets/client.py | 50 +- src/webflow/resources/collections/__init__.py | 20 +- src/webflow/resources/collections/client.py | 108 +- .../collections/resources/__init__.py | 20 +- .../collections/resources/fields/__init__.py | 3 - .../collections/resources/fields/client.py | 152 +- .../resources/fields/types/__init__.py | 5 - .../collections/resources/items/__init__.py | 18 +- .../collections/resources/items/client.py | 414 ++- .../resources/items/types/__init__.py | 18 +- .../resources/items/types/item_i_ds.py | 25 + .../items/types/item_i_ds_with_locales.py | 24 + ...=> items_create_item_live_request_body.py} | 2 +- ...t.py => items_create_item_request_body.py} | 2 +- ...ms_delete_items_live_request_items_item.py | 6 +- .../items/types/items_publish_item_request.py | 7 + ...s_publish_item_request_items_items_item.py | 31 + .../types/items_update_items_response.py | 7 + src/webflow/resources/components/client.py | 108 +- .../types/component_dom_write_nodes_item.py | 10 +- src/webflow/resources/ecommerce/client.py | 2 + src/webflow/resources/forms/client.py | 540 ++++ src/webflow/resources/inventory/client.py | 4 + src/webflow/resources/orders/client.py | 12 + src/webflow/resources/pages/client.py | 130 +- .../pages/resources/scripts/client.py | 58 +- .../pages/types/page_dom_write_nodes_item.py | 10 +- src/webflow/resources/products/__init__.py | 4 +- src/webflow/resources/products/client.py | 342 ++- .../resources/products/types/__init__.py | 4 +- .../types/product_sku_create_product.py | 22 + .../products/types/product_sku_create_sku.py | 22 + .../types/products_create_sku_response.py | 2 +- src/webflow/resources/scripts/client.py | 70 +- src/webflow/resources/sites/__init__.py | 35 +- src/webflow/resources/sites/client.py | 62 +- .../resources/sites/resources/__init__.py | 28 +- .../sites/resources/activity_logs/client.py | 14 +- .../sites/resources/comments/__init__.py | 19 + .../sites/resources/comments/client.py | 901 ++++++ .../resources/comments/types/__init__.py | 17 + ...ents_get_comment_thread_request_sort_by.py | 5 + ...s_get_comment_thread_request_sort_order.py | 5 + ...ts_list_comment_replies_request_sort_by.py | 5 + ...list_comment_replies_request_sort_order.py | 5 + ...ts_list_comment_threads_request_sort_by.py | 5 + ...list_comment_threads_request_sort_order.py | 5 + .../resources/sites/resources/plans/client.py | 6 + .../sites/resources/redirects/client.py | 44 +- .../sites/resources/robots_txt/__init__.py | 2 + .../sites/resources/robots_txt/client.py | 1050 +++++++ .../sites/resources/scripts/client.py | 64 +- .../sites/resources/well_known/__init__.py | 5 + .../sites/resources/well_known/client.py | 532 ++++ .../resources/well_known/types/__init__.py | 5 + .../types/well_known_file_content_type.py | 5 + src/webflow/resources/token/client.py | 4 + src/webflow/resources/users/__init__.py | 4 +- src/webflow/resources/users/client.py | 186 +- src/webflow/resources/users/types/__init__.py | 3 +- .../users/types/users_update_request_data.py | 38 - src/webflow/resources/webhooks/client.py | 8 + src/webflow/resources/workspaces/__init__.py | 13 + src/webflow/resources/workspaces/client.py | 18 + .../workspaces/resources/__init__.py | 10 + .../resources/audit_logs/__init__.py | 5 + .../workspaces/resources/audit_logs/client.py | 332 +++ .../resources/audit_logs/types/__init__.py | 6 + ...workspace_audit_logs_request_event_type.py | 8 + ...workspace_audit_logs_request_sort_order.py | 5 + src/webflow/types/__init__.py | 193 +- src/webflow/types/application.py | 38 +- src/webflow/types/asset.py | 14 +- src/webflow/types/asset_variant.py | 24 +- src/webflow/types/assets.py | 2 + src/webflow/types/bulk_collection_item.py | 4 +- src/webflow/types/collection.py | 12 +- .../types/collection_list_array_item.py | 4 +- src/webflow/types/comment_reply.py | 95 + src/webflow/types/comment_reply_author.py | 32 + src/webflow/types/comment_reply_list.py | 26 + .../types/comment_reply_list_pagination.py | 32 + .../comment_reply_mentioned_users_item.py | 32 + src/webflow/types/comment_thread.py | 100 + src/webflow/types/comment_thread_author.py | 34 + src/webflow/types/comment_thread_list.py | 26 + .../types/comment_thread_list_pagination.py | 32 + .../comment_thread_mentioned_users_item.py | 34 + src/webflow/types/component.py | 4 +- src/webflow/types/component_dom.py | 2 +- ...errides_write.py => component_instance.py} | 2 +- src/webflow/types/component_node.py | 12 +- src/webflow/types/conflict.py | 5 + src/webflow/types/custom_role.py | 33 + .../types/custom_role_audit_log_item.py | 26 + ...stom_role_audit_log_item_event_sub_type.py | 7 + src/webflow/types/dom.py | 7 + src/webflow/types/domain.py | 4 +- src/webflow/types/field.py | 10 +- src/webflow/types/field_create.py | 8 + src/webflow/types/field_type.py | 6 +- src/webflow/types/field_validations.py | 28 + ...field_validations_additional_properties.py | 10 + ...tional_properties_additional_properties.py | 23 + src/webflow/types/image_node.py | 6 +- src/webflow/types/image_node_image.py | 4 + src/webflow/types/metadata.py | 27 + src/webflow/types/metadata_options_item.py | 31 + src/webflow/types/node.py | 96 +- src/webflow/types/option_field.py | 58 + src/webflow/types/order.py | 6 +- src/webflow/types/order_billing_address.py | 78 + .../types/order_billing_address_japan_type.py | 5 + .../types/order_billing_address_type.py | 5 + src/webflow/types/order_shipping_address.py | 78 + .../order_shipping_address_japan_type.py | 5 + .../types/order_shipping_address_type.py | 5 + src/webflow/types/page.py | 11 +- src/webflow/types/pagination.py | 8 +- src/webflow/types/product_field_data.py | 4 +- src/webflow/types/reference_field.py | 62 + src/webflow/types/reference_field_metadata.py | 28 + src/webflow/types/reference_field_type.py | 5 + src/webflow/types/registered_script_list.py | 2 + src/webflow/types/robots.py | 32 + src/webflow/types/robots_rules_item.py | 34 + .../{text_node_write.py => search_button.py} | 8 +- src/webflow/types/search_button_node.py | 36 + src/webflow/types/select.py | 34 + src/webflow/types/select_node.py | 37 + src/webflow/types/select_node_choices_item.py | 27 + .../types/select_node_write_choices_item.py | 27 + src/webflow/types/site_membership.py | 49 + .../types/site_membership_audit_log_item.py | 26 + ...embership_audit_log_item_event_sub_type.py | 7 + src/webflow/types/sku_field_data.py | 32 +- ...sku_field_data_ec_sku_subscription_plan.py | 4 + src/webflow/types/sku_field_data_price.py | 5 + src/webflow/types/static_field.py | 56 + .../static_field_type.py} | 5 +- src/webflow/types/submit_button.py | 40 + src/webflow/types/submit_button_node.py | 43 + src/webflow/types/text.py | 4 + src/webflow/types/text_input.py | 33 + src/webflow/types/text_input_node.py | 36 + src/webflow/types/text_node.py | 14 +- src/webflow/types/text_node_text.py | 4 + src/webflow/types/trigger_type.py | 1 + src/webflow/types/user_access.py | 33 + .../types/user_access_audit_log_item.py | 26 + ...er_access_audit_log_item_event_sub_type.py | 5 + src/webflow/types/webhook_list.py | 4 +- src/webflow/types/workspace_audit_log_item.py | 141 + .../types/workspace_audit_log_item_actor.py | 20 + ...log_item_payload_site_membership_method.py | 7 + ...t_log_item_payload_site_membership_site.py | 20 + ...tem_payload_site_membership_target_user.py | 20 + ..._item_payload_site_membership_user_type.py | 7 + ...dit_log_item_payload_user_access_method.py | 7 + ...tem_payload_workspace_invitation_method.py | 7 + ...ayload_workspace_invitation_target_user.py | 20 + ..._payload_workspace_invitation_user_type.py | 7 + ...tem_payload_workspace_membership_method.py | 7 + ...ayload_workspace_membership_target_user.py | 20 + ..._payload_workspace_membership_user_type.py | 7 + .../workspace_audit_log_item_workspace.py | 20 + .../types/workspace_audit_log_response.py | 22 + src/webflow/types/workspace_invitation.py | 49 + .../workspace_invitation_audit_log_item.py | 26 + ...nvitation_audit_log_item_event_sub_type.py | 7 + src/webflow/types/workspace_membership.py | 49 + .../workspace_membership_audit_log_item.py | 26 + ...embership_audit_log_item_event_sub_type.py | 7 + tests/collections/test_fields.py | 35 +- tests/collections/test_items.py | 174 +- tests/conftest.py | 19 +- tests/sites/test_activity_logs.py | 6 - tests/sites/test_comments.py | 212 ++ tests/sites/test_robots_txt.py | 145 + tests/sites/test_scripts.py | 2 - tests/sites/test_well_known.py | 32 + tests/test_assets.py | 129 +- tests/test_collections.py | 399 ++- tests/test_components.py | 115 +- tests/test_forms.py | 87 +- tests/test_orders.py | 178 +- tests/test_pages.py | 119 +- tests/test_products.py | 349 ++- tests/test_scripts.py | 12 +- tests/test_sites.py | 81 +- tests/test_token.py | 2 +- tests/test_users.py | 27 +- tests/test_webhooks.py | 8 +- tests/workspaces/__init__.py | 2 + tests/workspaces/test_audit_logs.py | 53 + 234 files changed, 14891 insertions(+), 2665 deletions(-) create mode 100644 .mock/definition/sites/comments.yml create mode 100644 .mock/definition/sites/robotsTxt.yml create mode 100644 .mock/definition/sites/wellKnown.yml create mode 100644 .mock/definition/workspaces/auditLogs.yml delete mode 100644 src/webflow/resources/collections/resources/fields/types/__init__.py create mode 100644 src/webflow/resources/collections/resources/items/types/item_i_ds.py create mode 100644 src/webflow/resources/collections/resources/items/types/item_i_ds_with_locales.py rename src/webflow/resources/collections/resources/items/types/{items_create_item_live_request.py => items_create_item_live_request_body.py} (69%) rename src/webflow/resources/collections/resources/items/types/{items_create_item_request.py => items_create_item_request_body.py} (70%) create mode 100644 src/webflow/resources/collections/resources/items/types/items_publish_item_request.py create mode 100644 src/webflow/resources/collections/resources/items/types/items_publish_item_request_items_items_item.py create mode 100644 src/webflow/resources/collections/resources/items/types/items_update_items_response.py create mode 100644 src/webflow/resources/products/types/product_sku_create_product.py create mode 100644 src/webflow/resources/products/types/product_sku_create_sku.py create mode 100644 src/webflow/resources/sites/resources/comments/__init__.py create mode 100644 src/webflow/resources/sites/resources/comments/client.py create mode 100644 src/webflow/resources/sites/resources/comments/types/__init__.py create mode 100644 src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_by.py create mode 100644 src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_order.py create mode 100644 src/webflow/resources/sites/resources/comments/types/comments_list_comment_replies_request_sort_by.py create mode 100644 src/webflow/resources/sites/resources/comments/types/comments_list_comment_replies_request_sort_order.py create mode 100644 src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_by.py create mode 100644 src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_order.py create mode 100644 src/webflow/resources/sites/resources/robots_txt/__init__.py create mode 100644 src/webflow/resources/sites/resources/robots_txt/client.py create mode 100644 src/webflow/resources/sites/resources/well_known/__init__.py create mode 100644 src/webflow/resources/sites/resources/well_known/client.py create mode 100644 src/webflow/resources/sites/resources/well_known/types/__init__.py create mode 100644 src/webflow/resources/sites/resources/well_known/types/well_known_file_content_type.py delete mode 100644 src/webflow/resources/users/types/users_update_request_data.py create mode 100644 src/webflow/resources/workspaces/__init__.py create mode 100644 src/webflow/resources/workspaces/client.py create mode 100644 src/webflow/resources/workspaces/resources/__init__.py create mode 100644 src/webflow/resources/workspaces/resources/audit_logs/__init__.py create mode 100644 src/webflow/resources/workspaces/resources/audit_logs/client.py create mode 100644 src/webflow/resources/workspaces/resources/audit_logs/types/__init__.py create mode 100644 src/webflow/resources/workspaces/resources/audit_logs/types/audit_logs_get_workspace_audit_logs_request_event_type.py create mode 100644 src/webflow/resources/workspaces/resources/audit_logs/types/audit_logs_get_workspace_audit_logs_request_sort_order.py create mode 100644 src/webflow/types/comment_reply.py create mode 100644 src/webflow/types/comment_reply_author.py create mode 100644 src/webflow/types/comment_reply_list.py create mode 100644 src/webflow/types/comment_reply_list_pagination.py create mode 100644 src/webflow/types/comment_reply_mentioned_users_item.py create mode 100644 src/webflow/types/comment_thread.py create mode 100644 src/webflow/types/comment_thread_author.py create mode 100644 src/webflow/types/comment_thread_list.py create mode 100644 src/webflow/types/comment_thread_list_pagination.py create mode 100644 src/webflow/types/comment_thread_mentioned_users_item.py rename src/webflow/types/{component_instance_node_property_overrides_write.py => component_instance.py} (94%) create mode 100644 src/webflow/types/conflict.py create mode 100644 src/webflow/types/custom_role.py create mode 100644 src/webflow/types/custom_role_audit_log_item.py create mode 100644 src/webflow/types/custom_role_audit_log_item_event_sub_type.py create mode 100644 src/webflow/types/field_create.py create mode 100644 src/webflow/types/field_validations.py create mode 100644 src/webflow/types/field_validations_additional_properties.py create mode 100644 src/webflow/types/field_validations_additional_properties_additional_properties.py create mode 100644 src/webflow/types/metadata.py create mode 100644 src/webflow/types/metadata_options_item.py create mode 100644 src/webflow/types/option_field.py create mode 100644 src/webflow/types/order_billing_address.py create mode 100644 src/webflow/types/order_billing_address_japan_type.py create mode 100644 src/webflow/types/order_billing_address_type.py create mode 100644 src/webflow/types/order_shipping_address.py create mode 100644 src/webflow/types/order_shipping_address_japan_type.py create mode 100644 src/webflow/types/order_shipping_address_type.py create mode 100644 src/webflow/types/reference_field.py create mode 100644 src/webflow/types/reference_field_metadata.py create mode 100644 src/webflow/types/reference_field_type.py create mode 100644 src/webflow/types/robots.py create mode 100644 src/webflow/types/robots_rules_item.py rename src/webflow/types/{text_node_write.py => search_button.py} (75%) create mode 100644 src/webflow/types/search_button_node.py create mode 100644 src/webflow/types/select.py create mode 100644 src/webflow/types/select_node.py create mode 100644 src/webflow/types/select_node_choices_item.py create mode 100644 src/webflow/types/select_node_write_choices_item.py create mode 100644 src/webflow/types/site_membership.py create mode 100644 src/webflow/types/site_membership_audit_log_item.py create mode 100644 src/webflow/types/site_membership_audit_log_item_event_sub_type.py create mode 100644 src/webflow/types/static_field.py rename src/webflow/{resources/collections/resources/fields/types/field_create_type.py => types/static_field_type.py} (82%) create mode 100644 src/webflow/types/submit_button.py create mode 100644 src/webflow/types/submit_button_node.py create mode 100644 src/webflow/types/text_input.py create mode 100644 src/webflow/types/text_input_node.py create mode 100644 src/webflow/types/user_access.py create mode 100644 src/webflow/types/user_access_audit_log_item.py create mode 100644 src/webflow/types/user_access_audit_log_item_event_sub_type.py create mode 100644 src/webflow/types/workspace_audit_log_item.py create mode 100644 src/webflow/types/workspace_audit_log_item_actor.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_site_membership_method.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_site_membership_site.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_site_membership_target_user.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_site_membership_user_type.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_user_access_method.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_method.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_target_user.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_user_type.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_workspace_membership_method.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_workspace_membership_target_user.py create mode 100644 src/webflow/types/workspace_audit_log_item_payload_workspace_membership_user_type.py create mode 100644 src/webflow/types/workspace_audit_log_item_workspace.py create mode 100644 src/webflow/types/workspace_audit_log_response.py create mode 100644 src/webflow/types/workspace_invitation.py create mode 100644 src/webflow/types/workspace_invitation_audit_log_item.py create mode 100644 src/webflow/types/workspace_invitation_audit_log_item_event_sub_type.py create mode 100644 src/webflow/types/workspace_membership.py create mode 100644 src/webflow/types/workspace_membership_audit_log_item.py create mode 100644 src/webflow/types/workspace_membership_audit_log_item_event_sub_type.py create mode 100644 tests/sites/test_comments.py create mode 100644 tests/sites/test_robots_txt.py create mode 100644 tests/sites/test_well_known.py create mode 100644 tests/workspaces/__init__.py create mode 100644 tests/workspaces/test_audit_logs.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d396980..14569f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ name: ci on: [push] jobs: compile: - runs-on: ubuntu-24.04 + runs-on: ubuntu-20.04 steps: - name: Checkout repo uses: actions/checkout@v3 @@ -19,7 +19,7 @@ jobs: - name: Compile run: poetry run mypy . test: - runs-on: ubuntu-24.04 + runs-on: ubuntu-20.04 steps: - name: Checkout repo uses: actions/checkout@v3 @@ -36,12 +36,12 @@ jobs: - name: Install Fern run: npm install -g fern-api - name: Test - run: fern test --command "poetry run pytest -rP ./tests/custom/" + run: fern test --command "poetry run pytest -rP ." publish: needs: [compile, test] if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') - runs-on: ubuntu-24.04 + runs-on: ubuntu-20.04 steps: - name: Checkout repo uses: actions/checkout@v3 diff --git a/.mock/definition/__package__.yml b/.mock/definition/__package__.yml index db84636..a9bcf85 100644 --- a/.mock/definition/__package__.yml +++ b/.mock/definition/__package__.yml @@ -67,10 +67,18 @@ errors: ConflictError: status-code: 409 type: unknown - docs: Site is published to multiple domains at different times + docs: Collection already exists examples: + - value: + code: duplicate_collection + message: Collection already exists - value: message: '''Site is published to multiple domains at different times' + - value: + code: conflict + message: >- + Conflict: Conflict with server data: Live PATCH updates can't be + applied to items that have never been published - value: code: custom_code_max_registered_scripts message: The maximum number of registered scripts has been reached. @@ -173,7 +181,24 @@ types: docs: Array of errors source: openapi: ../../../openapi/referenced-specs/v2.yml - Application: unknown + Application: + properties: + id: + type: optional + docs: Unique identifier for the Application + description: + type: optional + docs: Application description provided by the developer + homepage: + type: optional + docs: Application homepage URL provided by the developer + validation: + format: uri + displayName: + type: optional + docs: Application name provided by the developer + source: + openapi: ../../../openapi/referenced-specs/v2.yml AuthorizationAuthorizationAuthorizedTo: properties: siteIds: @@ -224,14 +249,16 @@ types: Domain: properties: id: - type: string + type: optional docs: Unique identifier for the Domain + access: read-only url: type: optional docs: The registered Domain name lastPublished: type: optional docs: The date the custom domain was last published to + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml Locale: @@ -329,6 +356,302 @@ types: openapi: ../../../openapi/referenced-specs/v2.yml InvalidScopes: unknown NotEnterprisePlanWorkspace: unknown + WorkspaceAuditLogItemPayloadUserAccessMethod: + enum: + - dashboard + - sso + - api + - google + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + User access: + properties: + method: + type: optional + location: + type: optional + docs: The geolocation based on the logged IP address + ipAddress: + type: optional + docs: The captured IP address of the user + source: + openapi: ../../../openapi/referenced-specs/v2.yml + UserAccessAuditLogItemEventSubType: + enum: + - login + - logout + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + UserAccessAuditLogItem: + properties: + eventSubType: + type: optional + payload: + type: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Custom role: + properties: + roleName: + type: optional + docs: The name of the custom role + previousRoleName: + type: optional + docs: The previous name of the custom role + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CustomRoleAuditLogItemEventSubType: + enum: + - role_created + - role_updated + - role_deleted + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CustomRoleAuditLogItem: + properties: + eventSubType: + type: optional + payload: + type: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser: + properties: + id: optional + email: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod: + enum: + - sso + - dashboard + - admin + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType: + enum: + - member + - guest + - reviewer + - client + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Workspace membership: + properties: + targetUser: + type: optional + method: + type: optional + userType: + type: optional + roleName: + type: optional + docs: The name of the role that was assigned to the user + previousRoleName: + type: optional + docs: The previous role that the user had + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceMembershipAuditLogItemEventSubType: + enum: + - user_added + - user_removed + - user_role_updated + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceMembershipAuditLogItem: + properties: + eventSubType: + type: optional + payload: + type: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceAuditLogItemPayloadSiteMembershipSite: + properties: + id: optional + slug: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + WorkspaceAuditLogItemPayloadSiteMembershipTargetUser: + properties: + id: optional + email: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + WorkspaceAuditLogItemPayloadSiteMembershipMethod: + enum: + - sso + - invite + - scim + - dashboard + - admin + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceAuditLogItemPayloadSiteMembershipUserType: + enum: + - member + - guest + - reviewer + - client + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Site membership: + properties: + site: + type: optional + targetUser: + type: optional + method: + type: optional + userType: + type: optional + roleName: + type: optional + docs: The name of the role that was assigned to the user + previousRoleName: + type: optional + docs: The previous role that the user had + source: + openapi: ../../../openapi/referenced-specs/v2.yml + SiteMembershipAuditLogItemEventSubType: + enum: + - user_added + - user_removed + - user_role_updated + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + SiteMembershipAuditLogItem: + properties: + eventSubType: + type: optional + payload: + type: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser: + properties: + id: optional + email: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod: + enum: + - sso + - dashboard + - admin + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType: + enum: + - member + - guest + - reviewer + - client + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Workspace invitation: + properties: + targetUser: + type: optional + method: + type: optional + userType: + type: optional + roleName: + type: optional + docs: The name of the role that was assigned to the user + previousRoleName: + type: optional + docs: The previous role that the user had + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceInvitationAuditLogItemEventSubType: + enum: + - invite_sent + - invite_accepted + - invite_updated + - invite_canceled + - invite_declined + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceInvitationAuditLogItem: + properties: + eventSubType: + type: optional + payload: + type: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceAuditLogItemActor: + properties: + id: optional + email: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + WorkspaceAuditLogItemWorkspace: + properties: + id: optional + slug: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + WorkspaceAuditLogItem: + discriminant: eventType + base-properties: + timestamp: optional + actor: optional + workspace: optional + union: + user_access: + type: UserAccessAuditLogItem + custom_role: + type: CustomRoleAuditLogItem + workspace_membership: + type: WorkspaceMembershipAuditLogItem + site_membership: + type: SiteMembershipAuditLogItem + workspace_invitation: + type: WorkspaceInvitationAuditLogItem + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Pagination: + docs: Pagination object + properties: + limit: + type: double + docs: The limit used for pagination + offset: + type: double + docs: The offset used for pagination + total: + type: double + docs: The total number of records + source: + openapi: ../../../openapi/referenced-specs/v2.yml + WorkspaceAuditLogResponse: + properties: + items: optional> + pagination: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml Sites: properties: sites: optional> @@ -348,6 +671,7 @@ types: id: type: optional docs: The ID of the specific redirect rule + access: read-only fromUrl: type: optional docs: The source URL path that will be redirected. @@ -356,20 +680,6 @@ types: docs: The target URL path where the user or client will be redirected. source: openapi: ../../../openapi/referenced-specs/v2.yml - Pagination: - docs: Pagination object - properties: - limit: - type: optional - docs: The limit used for pagination - offset: - type: optional - docs: The offset used for pagination - total: - type: optional - docs: The total number of records - source: - openapi: ../../../openapi/referenced-specs/v2.yml Redirects: docs: Site redirects response properties: @@ -440,6 +750,31 @@ types: docs: URL for more information about Webflow hosting plan pricing. source: openapi: ../../../openapi/referenced-specs/v2.yml + RobotsRulesItem: + properties: + userAgent: + type: string + docs: The user agent the rules apply to. + allows: + type: optional> + docs: List of paths allowed for this user agent. + disallows: + type: optional> + docs: List of paths disallowed for this user agent. + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + Robots: + docs: The robots.txt file for a given site + properties: + rules: + type: optional> + docs: List of rules for user agents. + sitemap: + type: optional + docs: URL to the sitemap. + source: + openapi: ../../../openapi/referenced-specs/v2.yml SiteActivityLogItemEvent: enum: - styles_modified @@ -533,8 +868,9 @@ types: docs: A collection object properties: id: - type: string + type: optional docs: Unique identifier for a Collection + access: read-only displayName: type: optional docs: Name given to the Collection @@ -549,9 +885,11 @@ types: createdOn: type: optional docs: The date the collection was created + access: read-only lastUpdated: type: optional docs: The date the collection was last updated + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml CollectionList: @@ -561,37 +899,215 @@ types: docs: An array of Collections source: openapi: ../../../openapi/referenced-specs/v2.yml + StaticFieldType: + enum: + - Color + - DateTime + - Email + - File + - Image + - Link + - MultiImage + - Number + - Phone + - PlainText + - RichText + - Switch + - VideoLink + docs: Choose these appropriate field type for your collection data + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Static Field: + properties: + id: + type: optional + docs: Unique identifier for a Field + access: read-only + isEditable: + type: optional + docs: Define whether the field is editable + access: read-only + isRequired: + type: optional + docs: define whether a field is required in a collection + type: + type: StaticFieldType + docs: Choose these appropriate field type for your collection data + displayName: + type: string + docs: The name of a field + helpText: + type: optional + docs: Additional text to help anyone filling out this field + source: + openapi: ../../../openapi/referenced-specs/v2.yml + MetadataOptionsItem: + docs: A single option value for the Option field. + properties: + name: + type: string + docs: The name of the option + id: + type: optional + docs: The unique identifier of the option + access: read-only + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + Metadata: + docs: The metadata for the Option field. + properties: + options: + docs: The option values for the Option field. + type: list + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Option Field: + properties: + id: + type: optional + docs: Unique identifier for a Field + access: read-only + isEditable: + type: optional + docs: Define whether the field is editable + access: read-only + isRequired: + type: optional + docs: define whether a field is required in a collection + type: + type: literal<"Option"> + docs: >- + The [Option field + type](/data/reference/field-types-item-values#option) + displayName: + type: string + docs: The name of a field + helpText: + type: optional + docs: Additional text to help anyone filling out this field + metadata: Metadata + source: + openapi: ../../../openapi/referenced-specs/v2.yml + ReferenceFieldType: + enum: + - MultiReference + - Reference + docs: Choose these appropriate field type for your collection data + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + ReferenceFieldMetadata: + docs: >- + The collectionId for the referenced collection. Only applicable for + Reference and MultiReference fields. + properties: + collectionId: + type: string + docs: The unique identifier of the collection + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + Reference Field: + properties: + id: + type: optional + docs: Unique identifier for a Field + access: read-only + isEditable: + type: optional + docs: Define whether the field is editable + access: read-only + isRequired: + type: optional + docs: define whether a field is required in a collection + type: + type: ReferenceFieldType + docs: Choose these appropriate field type for your collection data + displayName: + type: string + docs: The name of a field + helpText: + type: optional + docs: Additional text to help anyone filling out this field + metadata: + type: ReferenceFieldMetadata + docs: >- + The collectionId for the referenced collection. Only applicable for + Reference and MultiReference fields. + source: + openapi: ../../../openapi/referenced-specs/v2.yml + FieldCreate: + discriminated: false + docs: Details about the field of a collection + union: + - type: Static Field + - type: Option Field + - type: Reference Field + source: + openapi: ../../../openapi/referenced-specs/v2.yml FieldType: enum: - Color - DateTime - Email - ExtFileRef + - File - Image - Link - MultiImage + - MultiReference - Number + - Option - Phone - PlainText + - Reference - RichText - Switch - - Video + - VideoLink docs: Choose these appropriate field type for your collection data inline: true source: openapi: ../../../openapi/referenced-specs/v2.yml + FieldValidationsAdditionalPropertiesAdditionalProperties: + properties: + additionalProperties: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + FieldValidationsAdditionalProperties: + discriminated: false + union: + - string + - double + - boolean + - integer + - FieldValidationsAdditionalPropertiesAdditionalProperties + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + FieldValidations: + docs: The validations for the field + properties: + additionalProperties: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true Field: docs: The details of a field in a collection properties: id: - type: string + type: optional docs: Unique identifier for a Field + access: read-only isRequired: type: boolean docs: define whether a field is required in a collection isEditable: type: optional docs: Define whether the field is editable + access: read-only type: type: FieldType docs: Choose these appropriate field type for your collection data @@ -606,19 +1122,24 @@ types: helpText: type: optional docs: Additional text to help anyone filling out this field + validations: + type: optional + docs: The validations for the field + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml Collection: docs: A collection object properties: id: - type: string + type: optional docs: Unique identifier for a Collection + access: read-only displayName: - type: optional + type: string docs: Name given to the Collection singularName: - type: optional + type: string docs: >- The name of one Item in Collection (e.g. ”Blog Post” if the Collection is called “Blog Posts”) @@ -628,9 +1149,11 @@ types: createdOn: type: optional docs: The date the collection was created + access: read-only lastUpdated: type: optional docs: The date the collection was last updated + access: read-only fields: docs: The list of fields in the Collection type: list @@ -669,18 +1192,22 @@ types: id: type: optional docs: Unique identifier for the Item + access: read-only cmsLocaleId: type: optional docs: Identifier for the locale of the CMS item lastPublished: type: optional docs: The date the item was last published + access: read-only lastUpdated: type: optional docs: The date the item was last updated + access: read-only createdOn: type: optional docs: The date the item was created + access: read-only isArchived: type: optional docs: Boolean determining if the Item is set to archived @@ -714,7 +1241,8 @@ types: items: type: optional> docs: List of Items within the collection - pagination: optional + pagination: + type: optional source: openapi: ../../../openapi/referenced-specs/v2.yml CollectionItemPostSingleFieldData: @@ -750,18 +1278,22 @@ types: id: type: optional docs: Unique identifier for the Item + access: read-only cmsLocaleId: type: optional docs: Identifier for the locale of the CMS item lastPublished: type: optional docs: The date the item was last published + access: read-only lastUpdated: type: optional docs: The date the item was last updated + access: read-only createdOn: type: optional docs: The date the item was created + access: read-only isArchived: type: optional docs: Boolean determining if the Item is in an archived state. @@ -769,7 +1301,7 @@ types: isDraft: type: optional docs: Boolean determining if the Item is in a draft state. - default: false + default: true fieldData: CollectionItemPostSingleFieldData source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -803,12 +1335,15 @@ types: lastPublished: type: optional docs: The date the item was last published + access: read-only lastUpdated: type: optional docs: The date the item was last updated + access: read-only createdOn: type: optional docs: The date the item was created + access: read-only isArchived: type: optional docs: Boolean determining if the Item is set to archived @@ -826,6 +1361,7 @@ types: docs: List of Items within the collection source: openapi: ../../../openapi/referenced-specs/v2.yml + Conflict: unknown BulkCollectionItemFieldData: properties: name: @@ -848,20 +1384,24 @@ types: items properties: id: - type: string + type: optional docs: Unique identifier for the Item + access: read-only cmsLocaleIds: type: optional> docs: Array of identifiers for the locales where the item will be created lastPublished: type: optional docs: The date the item was last published + access: read-only lastUpdated: type: optional docs: The date the item was last updated + access: read-only createdOn: type: optional docs: The date the item was created + access: read-only isArchived: type: optional docs: Boolean determining if the Item is set to archived @@ -897,18 +1437,22 @@ types: id: type: optional docs: Unique identifier for the Item + access: read-only cmsLocaleId: type: optional docs: Identifier for the locale of the CMS item lastPublished: type: optional docs: The date the item was last published + access: read-only lastUpdated: type: optional docs: The date the item was last updated + access: read-only createdOn: type: optional docs: The date the item was created + access: read-only isArchived: type: optional docs: Boolean determining if the Item is set to archived @@ -918,6 +1462,222 @@ types: fieldData: optional source: openapi: ../../../openapi/referenced-specs/v2.yml + CommentThreadAuthor: + properties: + userId: + type: string + docs: The unique identifier of the author + email: + type: string + docs: Email of the author + name: + type: string + docs: Name of the author + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentThreadMentionedUsersItem: + properties: + userId: + type: string + docs: The unique identifier of the mentioned user + email: + type: string + docs: Email of the user + name: + type: string + docs: Name of the User + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentThread: + docs: > + A comment thread represents a conversation between users on a specific + page. Each comment thread has a unique identifier and can contain multiple + comments. Retrieve comment replies using the replies API endpoint. + properties: + id: + type: optional + docs: Unique identifier for the comment thread + access: read-only + siteId: + type: optional + docs: The site unique identifier + access: read-only + pageId: + type: optional + docs: The page unique identifier + access: read-only + localeId: + type: optional + docs: The locale unique identifier + access: read-only + itemId: + type: optional + docs: The item unique identifier + access: read-only + breakpoint: + type: optional + docs: The breakpoint the comment was left on + access: read-only + url: + type: optional + docs: The URL of the page the comment was left on + access: read-only + content: + type: string + docs: The content of the comment reply + isResolved: + type: boolean + docs: Boolean determining if the comment thread is resolved + default: false + author: CommentThreadAuthor + mentionedUsers: + docs: >- + List of mentioned users. This is an empty array until email + notifications are sent, which can take up to 5 minutes after the + comment is created. + type: list + createdOn: + type: optional + docs: The date the item was created + access: read-only + lastUpdated: + type: optional + docs: The date the item was last updated + access: read-only + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentThreadListPagination: + properties: + limit: + type: double + docs: The limit specified in the request (default 100) + default: 100 + offset: + type: double + docs: The offset specified for pagination + default: 0 + total: + type: double + docs: Total number of comment threads + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentThreadList: + docs: > + A list of comment threads on the site. Contains the content of the first + reply. + properties: + comments: list + pagination: CommentThreadListPagination + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentReplyAuthor: + properties: + id: + type: string + docs: The unique identifier of the author + email: + type: string + docs: Email of the author + name: + type: string + docs: Name of the author + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentReplyMentionedUsersItem: + properties: + id: + type: string + docs: The unique identifier of the mentioned user + email: + type: string + docs: Email of the user + name: + type: string + docs: Name of the User + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentReply: + docs: > + A comment thread represents a conversation between users on a specific + page. Each comment thread has a unique identifier and can contain multiple + comments. + properties: + id: + type: optional + docs: Unique identifier for the comment thread + access: read-only + commentId: + type: optional + docs: The comment reply unique identifier + access: read-only + siteId: + type: optional + docs: The site unique identifier + access: read-only + pageId: + type: optional + docs: The page unique identifier + access: read-only + localeId: + type: optional + docs: The locale unique identifier + access: read-only + breakpoint: + type: optional + docs: The breakpoint the comment was left on + access: read-only + content: + type: string + docs: The content of the comment reply + isResolved: + type: boolean + docs: Boolean determining if the comment thread is resolved + default: false + author: CommentReplyAuthor + mentionedUsers: + type: optional> + docs: >- + List of mentioned users is an empty array until email notifications + are sent. + lastUpdated: + type: optional + docs: The date the item was last updated + access: read-only + createdOn: + type: optional + docs: The date the item was created + access: read-only + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentReplyListPagination: + properties: + limit: + type: double + docs: The limit specified in the request (default 100) + default: 100 + offset: + type: double + docs: The offset specified for pagination + default: 0 + total: + type: double + docs: Total number of comment replies + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentReplyList: + docs: | + A list of comment replies. + properties: + comments: list + pagination: CommentReplyListPagination + source: + openapi: ../../../openapi/referenced-specs/v2.yml PageSeo: docs: SEO-related fields for the Page properties: @@ -940,6 +1700,7 @@ types: type: optional docs: Indicates the Open Graph title was copied from the SEO title default: true + access: read-only description: type: optional docs: The description supplied to Open Graph annotations @@ -949,6 +1710,7 @@ types: Indicates the Open Graph description was copied from the SEO description default: true + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true @@ -956,11 +1718,13 @@ types: docs: The Page object properties: id: - type: string + type: optional docs: Unique identifier for the Page + access: read-only siteId: type: optional docs: Unique identifier for the Site + access: read-only title: type: optional docs: Title of the Page @@ -970,43 +1734,45 @@ types: parentId: type: optional docs: Identifier of the parent folder + access: read-only collectionId: type: optional docs: >- Unique identifier for a linked Collection, value will be null if the Page is not part of a Collection. + access: read-only createdOn: type: optional docs: The date the Page was created + access: read-only lastUpdated: type: optional docs: The date the Page was most recently updated + access: read-only archived: type: optional docs: Whether the Page has been archived default: false + access: read-only draft: type: optional docs: Whether the Page is a draft default: false + access: read-only canBranch: type: optional docs: >- Indicates whether the Page supports [Page Branching](https://university.webflow.com/lesson/page-branching) default: false + access: read-only isBranch: type: optional docs: >- Indicates whether the Page is a Branch of another Page [Page Branching](https://university.webflow.com/lesson/page-branching) default: false - isMembersOnly: - type: optional - docs: >- - Indicates whether the Page is restricted by [Memberships - Controls](https://university.webflow.com/lesson/webflow-memberships-overview#how-to-manage-page-restrictions) - default: false + access: read-only seo: type: optional docs: SEO-related fields for the Page @@ -1016,9 +1782,11 @@ types: localeId: type: optional docs: Unique ID of the page locale + access: read-only publishedPath: type: optional docs: Relative path of the published page URL + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml PageList: @@ -1029,6 +1797,7 @@ types: source: openapi: ../../../openapi/referenced-specs/v2.yml TextNodeText: + docs: The text content of the node properties: html: type: optional @@ -1048,13 +1817,17 @@ types: id: type: optional docs: Node UUID - text: optional + access: read-only + text: + type: TextNodeText + docs: The text content of the node attributes: type: optional> docs: The custom attributes of the node source: openapi: ../../../openapi/referenced-specs/v2.yml ImageNodeImage: + docs: The image details of the node properties: alt: optional assetId: optional @@ -1071,13 +1844,17 @@ types: id: type: optional docs: Node UUID - image: optional + access: read-only + image: + type: ImageNodeImage + docs: The image details of the node attributes: type: optional> docs: The custom attributes of the node source: openapi: ../../../openapi/referenced-specs/v2.yml Text: + docs: The text content of the node properties: html: type: optional @@ -1129,13 +1906,100 @@ types: properties: id: type: optional - docs: Node UUID + docs: The unique identifier of the component instance node + access: read-only componentId: - type: optional - docs: Component ID + type: string + docs: The unique identifier of the component propertyOverrides: - type: optional> docs: List of component properties with overrides for a component instance. + type: list + source: + openapi: ../../../openapi/referenced-specs/v2.yml + TextInputNode: + docs: > + Represents text input and textarea elements within the DOM. It contains + the placeholder text in the input. Additional attributes can be associated + with the text for styling or other purposes. + properties: + id: + type: optional + docs: Node UUID + access: read-only + placeholder: + type: string + docs: The placeholder text of the input node + attributes: + type: optional> + docs: The custom attributes of the node + source: + openapi: ../../../openapi/referenced-specs/v2.yml + SelectNodeChoicesItem: + properties: + value: + type: string + docs: The value of the choice when selected. + text: + type: string + docs: The text to display for the choice. + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + SelectNode: + docs: > + Represents select elements within the DOM. It contains the list of choices + in the select. Additional attributes can be associated with the text for + styling or other purposes. + properties: + id: + type: optional + docs: Node UUID + access: read-only + choices: + docs: The list of choices in this select node. + type: list + attributes: + type: optional> + docs: The custom attributes of the node + source: + openapi: ../../../openapi/referenced-specs/v2.yml + SubmitButtonNode: + docs: > + Represents submit button elements within the DOM. It contains the text and + waiting text of the button. Additional attributes can be associated with + the text for styling or other purposes. + properties: + id: + type: optional + docs: Node UUID + access: read-only + value: + type: string + docs: The text content of the submit button. + waitingText: + type: string + docs: The text to show while the form is submitting. + attributes: + type: optional> + docs: The custom attributes of the node + source: + openapi: ../../../openapi/referenced-specs/v2.yml + SearchButtonNode: + docs: > + Represents search button elements within the DOM. It contains the text of + the button. Additional attributes can be associated with the text for + styling or other purposes. + properties: + id: + type: optional + docs: Node UUID + access: read-only + value: + type: string + docs: The text content of the search button. + attributes: + type: optional> + docs: The custom attributes of the node source: openapi: ../../../openapi/referenced-specs/v2.yml Node: @@ -1149,6 +2013,10 @@ types: text: TextNode image: ImageNode component-instance: ComponentNode + text-input: TextInputNode + select: SelectNode + submit-button: SubmitButtonNode + search-button: SearchButtonNode source: openapi: ../../../openapi/referenced-specs/v2.yml Dom: @@ -1165,9 +2033,13 @@ types: docs: Page ID nodes: optional> pagination: optional + lastUpdated: + type: optional + docs: The date the page dom was most recently updated + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml - TextNodeWrite: + Text Node: docs: Update a text node properties: nodeId: @@ -1201,7 +2073,7 @@ types: source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true - ComponentInstanceNodePropertyOverridesWrite: + Component Instance: docs: Update text property overrides of a component instance properties: nodeId: @@ -1214,27 +2086,90 @@ types: type: list source: openapi: ../../../openapi/referenced-specs/v2.yml + SelectNodeWriteChoicesItem: + properties: + value: + type: string + docs: The value of the choice when selected. + text: + type: string + docs: The text to display for the choice. + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + Select: + docs: Update choices on a select node + properties: + nodeId: + type: string + docs: Node UUID + choices: + docs: The list of choices to set on the select node. + type: list + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Text Input: + docs: Update placeholder text on a text input node + properties: + nodeId: + type: string + docs: Node UUID + placeholder: + type: string + docs: The placeholder text of the input node + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Submit Button: + docs: Update a submit button node + properties: + nodeId: + type: string + docs: Node UUID + value: + type: optional + docs: The text content of the submit button. + waitingText: + type: optional + docs: The text to show while the form is submitting. + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Search Button: + docs: Update a search button node + properties: + nodeId: + type: string + docs: Node UUID + value: + type: string + docs: The text content of the search button. + source: + openapi: ../../../openapi/referenced-specs/v2.yml Component: docs: The Component object properties: id: - type: string + type: optional docs: Unique identifier for the Component + access: read-only name: type: optional docs: Component Name + access: read-only group: type: optional docs: The group that the component belongs to + access: read-only description: type: optional docs: Component Description + access: read-only readonly: type: optional docs: >- Indicates whether the component is read-only. Components that cannot be updated within this Site are set to readonly. Workspace Libraries are a good example. + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml ComponentList: @@ -1249,8 +2184,8 @@ types: The Component DOM schema represents the content structure of a component. Similar to Page DOM, it captures various content nodes and their associated attributes, but specifically for a component's structure. Each - node has a unique identifier and can contain text, images, or nested - component instances. + node has a unique identifier and can contain text, images, select or text + inputs, submit buttons, or nested component instances. properties: componentId: type: optional @@ -1270,6 +2205,7 @@ types: componentId: type: optional docs: Component ID + access: read-only properties: optional> pagination: optional source: @@ -1314,9 +2250,11 @@ types: lastUpdated: type: optional docs: Date when the Site's scripts were last updated + access: read-only createdOn: type: optional docs: Date when the Site's scripts were created + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml CustomCodeHostedResponse: @@ -1325,6 +2263,7 @@ types: id: type: optional docs: Human readable id, derived from the user-specified display name + access: read-only canCopy: type: optional docs: >- @@ -1347,9 +2286,11 @@ types: createdOn: type: optional docs: Timestamp when the script version was created + access: read-only lastUpdated: type: optional docs: Timestamp when the script version was last updated + access: read-only version: type: optional docs: A Semantic Version (SemVer) string, denoting the version of the script @@ -1359,6 +2300,7 @@ types: docs: A list of scripts registered to the site properties: registeredScripts: optional> + pagination: optional source: openapi: ../../../openapi/referenced-specs/v2.yml CustomCodeInlineResponse: @@ -1367,6 +2309,7 @@ types: id: type: optional docs: Human readable id, derived from the user-specified display name + access: read-only canCopy: type: optional docs: >- @@ -1389,9 +2332,11 @@ types: createdOn: type: optional docs: Timestamp when the script version was created + access: read-only lastUpdated: type: optional docs: Timestamp when the script version was last updated + access: read-only version: type: optional docs: A Semantic Version (SemVer) string, denoting the version of the script @@ -1426,9 +2371,11 @@ types: createdOn: type: optional docs: The date the Block was created + access: read-only lastUpdated: type: optional docs: The date the Block was most recently updated + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml ListCustomCodeBlocks: @@ -1439,29 +2386,30 @@ types: source: openapi: ../../../openapi/referenced-specs/v2.yml AssetVariant: + docs: Asset variant details properties: hostedUrl: - type: optional + type: string docs: URL of where the asset variant is hosted validation: format: uri originalFileName: - type: optional + type: string docs: Original file name of the variant displayName: - type: optional + type: string docs: Display name of the variant format: - type: optional + type: string docs: format of the variant width: - type: optional + type: integer docs: Width in pixels height: type: optional docs: Height in pixels quality: - type: optional + type: integer docs: Value between 0 and 100 representing the image quality error: type: optional @@ -1469,37 +2417,51 @@ types: source: openapi: ../../../openapi/referenced-specs/v2.yml Asset: + docs: Asset details properties: id: type: optional docs: Unique identifier for this asset + access: read-only contentType: type: optional docs: File format type + access: read-only size: type: optional docs: size in bytes + access: read-only siteId: type: optional docs: Unique identifier for the site that hosts this asset + access: read-only hostedUrl: type: optional docs: Link to the asset validation: format: uri + access: read-only originalFileName: type: optional docs: Original file name at the time of upload + access: read-only displayName: - type: optional + type: string docs: Display name of the asset lastUpdated: type: optional docs: Date the asset metadata was last updated + access: read-only createdOn: type: optional docs: Date the asset metadata was created - variants: optional> + access: read-only + variants: + docs: >- + A list of [asset + variants](https://help.webflow.com/hc/en-us/articles/33961378697107-Responsive-images) + created by Webflow to serve your site responsively. + type: list altText: type: optional docs: The visual description of the asset @@ -1509,6 +2471,7 @@ types: docs: A list of assets properties: assets: optional> + pagination: optional source: openapi: ../../../openapi/referenced-specs/v2.yml AssetUploadUploadDetails: @@ -1617,47 +2580,10 @@ types: - collection_item_changed - collection_item_deleted - collection_item_unpublished + - comment_created docs: > - * `form_submission` - Sends the [form_submission](#form_submission) event - - * `site_publish` - Sends a [site_publish](#site_publish) event - - * `page_created` - Send the [page_created](#page_created) event - - * `page_metadata_updated` - Sends the - [page_metadata_updated](#page_metadata_updated) event - - * `page_deleted` - Sends the [page_deleted](#page_deleted) event - - * `ecomm_new_order` - Sends the new [ecomm_new_order](#ecomm_new_order) - event - - * `ecomm_order_changed` - Sends the - [ecomm_order_changed](#ecomm_order_changed) event - - * `ecomm_inventory_changed` - Sends the - [ecomm_inventory_changed](#ecomm_inventory_changed) event - - * `user_account_added` - Sends the - [user_account_added](#user_account_added) event - - * `user_account_updated` - Sends the - [user_account_updated](#user_account_updated) event - - * `user_account_deleted` - Sends the - [user_account_deleted](#user_account_deleted) event - - * `collection_item_created` - Sends the - [collection_item_created](#collection_item_created) event - - * `collection_item_changed` - Sends the - [collection_item_changed](#collection_item_changed) event - - * `collection_item_deleted` - Sends the - [collection_item_deleted](#collection_item_deleted) event - - * `collection_item_unpublished` - Sends the - [collection_item_unpublished](#collection_item_unpublished) event + The type of event that triggered the request. See the the documentation + for details on [supported events](/data/reference/all-events). source: openapi: ../../../openapi/referenced-specs/v2.yml WebhookFilter: @@ -1676,6 +2602,7 @@ types: id: type: optional docs: Unique identifier for the Webhook registration + access: read-only triggerType: optional url: type: optional @@ -1683,9 +2610,11 @@ types: workspaceId: type: optional docs: Unique identifier for the Workspace the Webhook is registered in + access: read-only siteId: type: optional docs: Unique identifier for the Site the Webhook is registered in + access: read-only filter: type: optional docs: >- @@ -1694,15 +2623,17 @@ types: lastTriggered: type: optional docs: Date the Webhook instance was last triggered + access: read-only createdOn: type: optional docs: Date the Webhook registration was created + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml WebhookList: properties: - pagination: optional webhooks: optional> + pagination: optional source: openapi: ../../../openapi/referenced-specs/v2.yml FormFieldValueType: @@ -1905,24 +2836,31 @@ types: id: type: optional docs: Unique identifier for the User + access: read-only isEmailVerified: type: optional docs: Shows whether the user has verified their email address + access: read-only lastUpdated: type: optional docs: The timestamp the user was updated + access: read-only invitedOn: type: optional docs: The timestamp the user was invited + access: read-only createdOn: type: optional docs: The timestamp the user was created + access: read-only lastLogin: type: optional docs: The timestamp the user was logged in + access: read-only status: type: optional docs: The status of the user + access: read-only accessGroups: type: optional> docs: Access groups the user belongs to @@ -2128,9 +3066,9 @@ types: sku-properties: type: optional> docs: Variant types to include in SKUs - categories: + category: type: optional> - docs: The categories your product belongs to. + docs: The category your product belongs to. tax-category: type: optional docs: Product tax class @@ -2152,18 +3090,23 @@ types: id: type: optional docs: Unique identifier for the Product + access: read-only cmsLocaleId: type: optional docs: Identifier for the locale of the CMS item + access: read-only lastPublished: type: optional docs: The date the Product was last published + access: read-only lastUpdated: type: optional docs: The date the Product was last updated + access: read-only createdOn: type: optional docs: The date the Product was created + access: read-only isArchived: type: optional docs: Boolean determining if the Product is set to archived @@ -2178,8 +3121,10 @@ types: SkuValueList: type: map docs: > - A dictionary that maps a SKU property to a SKU value. The key of the - dictionary is the SKU property ID, and the value is the SKU value ID. + A mapping between SKU properties and their values, represented as + key-value pairs. Each key represents a SKU Property ID (e.g. "color") and + maps to its corresponding SKU Value ID (e.g. "blue"). This structure + defines the specific variant combination for a SKU. SkuFieldDataPrice: docs: price of SKU properties: @@ -2189,6 +3134,9 @@ types: unit: type: optional docs: Currency of Item + currency: + type: optional + docs: Currency of Item (alternative representation) source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true @@ -2209,6 +3157,10 @@ types: - value: one-time name: OneTime - subscription + docs: >- + [Billing + method](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#billing-methods)for + the SKU inline: true source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -2246,6 +3198,10 @@ types: openapi: ../../../openapi/referenced-specs/v2.yml inline: true SkuFieldDataEcSkuSubscriptionPlan: + docs: >- + [Subscription + plan](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#subscription) + for the SKU properties: interval: type: optional @@ -2256,7 +3212,9 @@ types: trial: type: optional docs: Number of days of a trial - plans: optional> + plans: + type: optional> + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true @@ -2276,8 +3234,18 @@ types: compare-at-price: type: optional docs: comparison price of SKU - ec-sku-billing-method: optional - ec-sku-subscription-plan: optional + ec-sku-billing-method: + type: optional + docs: >- + [Billing + method](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#billing-methods)for + the SKU + ec-sku-subscription-plan: + type: optional + docs: >- + [Subscription + plan](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#subscription) + for the SKU track-inventory: type: optional docs: >- @@ -2287,6 +3255,15 @@ types: quantity: type: optional docs: Quantity of SKU that will be tracked as items are ordered. + main-image: + type: optional + docs: The URL for the main image of the SKU + sku: + type: optional + docs: A unique identifier for the SKU + sku-properties: + type: optional> + docs: The properties of the SKU source: openapi: ../../../openapi/referenced-specs/v2.yml Sku: @@ -2295,18 +3272,23 @@ types: id: type: optional docs: Unique identifier for the Product + access: read-only cmsLocaleId: type: optional docs: Identifier for the locale of the CMS item + access: read-only lastPublished: type: optional docs: The date the Product was last published + access: read-only lastUpdated: type: optional docs: The date the Product was last updated + access: read-only createdOn: type: optional docs: The date the Product was created + access: read-only fieldData: optional source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -2472,6 +3454,7 @@ types: productId: type: optional docs: The unique identifier for the Product + access: read-only productName: type: optional docs: User-facing name of the Product @@ -2637,6 +3620,112 @@ types: inline: true source: openapi: ../../../openapi/referenced-specs/v2.yml + OrderShippingAddressType: + enum: + - shipping + - billing + docs: The type of the order address (billing or shipping) + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + OrderShippingAddressJapanType: + enum: + - kana + - kanji + docs: >- + Represents a Japan-only address format. This field will only appear on + orders placed from Japan. + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + OrderShippingAddress: + docs: The shipping address + properties: + type: + type: optional + docs: The type of the order address (billing or shipping) + japanType: + type: optional + docs: >- + Represents a Japan-only address format. This field will only appear on + orders placed from Japan. + addressee: + type: optional + docs: Display name on the address + line1: + type: optional + docs: The first line of the address + line2: + type: optional + docs: The second line of the address + city: + type: optional + docs: The city of the address. + state: + type: optional + docs: The state or province of the address + country: + type: optional + docs: The country of the address + postalCode: + type: optional + docs: The postal code of the address + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + OrderBillingAddressType: + enum: + - shipping + - billing + docs: The type of the order address (billing or shipping) + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + OrderBillingAddressJapanType: + enum: + - kana + - kanji + docs: >- + Represents a Japan-only address format. This field will only appear on + orders placed from Japan. + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + OrderBillingAddress: + docs: The billing address + properties: + type: + type: optional + docs: The type of the order address (billing or shipping) + japanType: + type: optional + docs: >- + Represents a Japan-only address format. This field will only appear on + orders placed from Japan. + addressee: + type: optional + docs: Display name on the address + line1: + type: optional + docs: The first line of the address + line2: + type: optional + docs: The second line of the address + city: + type: optional + docs: The city of the address. + state: + type: optional + docs: The state or province of the address + country: + type: optional + docs: The country of the address + postalCode: + type: optional + docs: The postal code of the address + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true OrderCustomerInfo: docs: An object with the keys `fullName` and `email`. properties: @@ -2725,6 +3814,7 @@ types: The order ID. Will usually be 6 hex characters, but can also be 9 hex characters if the site has a very large number of Orders. Randomly assigned. + access: read-only status: type: optional docs: | @@ -2780,10 +3870,10 @@ types: type: optional> docs: All addresses provided by the customer during the ordering flow. shippingAddress: - type: optional + type: optional docs: The shipping address billingAddress: - type: optional + type: optional docs: The billing address shippingProvider: type: optional @@ -2868,6 +3958,7 @@ types: id: type: optional docs: Unique identifier for a SKU item + access: read-only quantity: type: optional docs: >- @@ -2884,9 +3975,11 @@ types: siteId: type: optional docs: The identifier of the Site + access: read-only createdOn: type: optional docs: Date that the Site was created on + access: read-only defaultCurrency: type: optional docs: The three-letter ISO currency code for the Site diff --git a/.mock/definition/accessGroups.yml b/.mock/definition/accessGroups.yml index d8828f8..7689533 100644 --- a/.mock/definition/accessGroups.yml +++ b/.mock/definition/accessGroups.yml @@ -49,6 +49,7 @@ service: response: docs: Request was successful type: root.AccessGroupList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/api.yml b/.mock/definition/api.yml index aee9acd..b881d16 100644 --- a/.mock/definition/api.yml +++ b/.mock/definition/api.yml @@ -3,8 +3,15 @@ error-discrimination: strategy: status-code display-name: Data API environments: - Default: https://api.webflow.com/v2 -default-environment: Default + Data API: + urls: + Base: https://api.webflow.com/v2 + Data API: https://api.webflow.com/v2 + Content Delivery API: https://api-cdn.webflow.com/v2 + Production: https://api.webflow.com/v2 + CDN: https://api-cdn.webflow.com/v2 +default-environment: Data API +default-url: Base auth-schemes: BearerToken: scheme: bearer diff --git a/.mock/definition/assets.yml b/.mock/definition/assets.yml index 35392ec..3d36d0b 100644 --- a/.mock/definition/assets.yml +++ b/.mock/definition/assets.yml @@ -9,7 +9,7 @@ service: method: GET auth: true docs: | - List assets for a given site + List of assets uploaded to a site Required scope | `assets:read` source: @@ -22,6 +22,7 @@ service: response: docs: Request was successful type: root.Assets + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -55,35 +56,64 @@ service: width: 500 height: 900 quality: 100 - altText: A red chair + altText: A single candy wrapper + - id: 63e5889e7fe4eafa7384cea5 + contentType: image/png + size: 2212772 + siteId: 63938b302ea6b0aa6f3d8745 + hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg + originalFileName: Gum-Wrapper.svg + displayName: 63e5889e7fe4eafa7384cea5_Gum-Wrapper.png + lastUpdated: '2023-03-01T23:42:57Z' + createdOn: '2023-02-09T23:58:22Z' + variants: + - hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + originalFileName: >- + Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + displayName: >- + 660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + format: png + width: 500 + height: 900 + quality: 100 + altText: A single gum wrapper + pagination: + limit: 2 + offset: 0 + total: 2 create: path: /sites/{site_id}/assets method: POST auth: true docs: > - Create a new asset entry. + The first step in uploading an asset to a site. This endpoint generates a response with the following information: - `uploadUrl` and `uploadDetails`. + `uploadUrl` and `uploadDetails`. - You can use these two properties to [upload the file to Amazon s3 by - making a - POST](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) - request to the `uploadUrl` with the `uploadDetails` object as your - header information in the request. - - Required scope | `assets:write` + Use these properties in the header of a [POST request to Amazson + s3](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) + to complete the upload. + + + + To learn more about how to upload assets to Webflow, see our [assets + guide](/data/docs/working-with-assets). + + Required scope | `assets:write` source: openapi: ../../../openapi/referenced-specs/v2.yml path-parameters: site_id: type: string docs: Unique identifier for a Site - display-name: Create Asset Metadata + display-name: Upload Asset request: name: AssetsCreateRequest body: @@ -103,6 +133,7 @@ service: response: docs: Request was successful type: root.AssetUpload + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -137,7 +168,7 @@ service: assetUrl: >- https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d907ab9e91e3e9f56385e_paranoidAndroid-2024.png hostedUrl: >- - https://d1otoma47x30pg.cloudfront.net/643021114e290e0d3a0602b2/64358b9544249dc43d37d2b7_Screenshot%202023-04-11%20at%209.50.42%20AM.png + https://dev-assets.website-files.com/643021114e290e0d3a0602b2/64358b9544249dc43d37d2b7_Screenshot%202023-04-11%20at%209.50.42%20AM.png originalFileName: file.png createdOn: '2023-04-11T16:32:21Z' lastUpdated: '2023-04-12T20:31:03Z' @@ -146,7 +177,7 @@ service: method: GET auth: true docs: | - Get an Asset + Get details about an asset Required scope | `assets:read` source: @@ -159,6 +190,7 @@ service: response: docs: Request was successful type: root.Asset + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -170,25 +202,27 @@ service: asset_id: 580e63fc8c9a982ac9b8b745 response: body: - id: 55131cd036c09f7d07883dfc + id: 63e5889e7fe4eafa7384cea4 contentType: image/png - size: 1500 - siteId: 62749158efef318abc8d5a0f - hostedUrl: example.com/hostedimage.png - originalFileName: image.png - displayName: example-image-123.png - lastUpdated: '2016-09-06T21:12:22Z' - createdOn: '2016-09-02T23:26:22Z' + size: 2212772 + siteId: 63938b302ea6b0aa6f3d8745 + hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg + originalFileName: Candy-Wrapper.svg + displayName: 63e5889e7fe4eafa7384cea4_Candy-Wrapper.png + lastUpdated: '2023-03-01T23:42:57Z' + createdOn: '2023-02-09T23:58:22Z' variants: - - hostedUrl: example.com/hostedimage.png - originalFileName: image.png - displayName: A brown dog - format: format - width: 1500 + - hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + originalFileName: Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + displayName: >- + 660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + format: png + width: 500 height: 900 - quality: 1 - error: error - altText: A red chair + quality: 100 + altText: A single candy wrapper delete: path: /assets/{asset_id} method: DELETE @@ -218,7 +252,7 @@ service: method: PATCH auth: true docs: | - Update an Asset + Update details of an Asset. Required scope | `assets:write` source: @@ -244,6 +278,7 @@ service: response: docs: Request was successful type: root.Asset + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -256,25 +291,27 @@ service: request: {} response: body: - id: 55131cd036c09f7d07883dfc + id: 63e5889e7fe4eafa7384cea4 contentType: image/png - size: 1500 - siteId: 62749158efef318abc8d5a0f - hostedUrl: example.com/hostedimage.png - originalFileName: image.png - displayName: example-image-123.png - lastUpdated: '2016-09-06T21:12:22Z' - createdOn: '2016-09-02T23:26:22Z' + size: 2212772 + siteId: 63938b302ea6b0aa6f3d8745 + hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg + originalFileName: Candy-Wrapper.svg + displayName: 63e5889e7fe4eafa7384cea4_Candy-Wrapper.png + lastUpdated: '2023-03-01T23:42:57Z' + createdOn: '2023-02-09T23:58:22Z' variants: - - hostedUrl: example.com/hostedimage.png - originalFileName: image.png - displayName: A brown dog - format: format - width: 1500 + - hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + originalFileName: Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + displayName: >- + 660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + format: png + width: 500 height: 900 - quality: 1 - error: error - altText: A red chair + quality: 100 + altText: A single candy wrapper list-folders: path: /sites/{site_id}/asset_folders method: GET @@ -293,6 +330,7 @@ service: response: docs: Request was successful type: root.AssetFolderList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -307,7 +345,6 @@ service: assetFolders: - id: 6390c49774a71f0e3c1a08ee displayName: emoji icons - parentFolder: 6390c49774a71f99f21a08eb assets: - 63e5889e7fe4eafa7384cea4 - 659595234426a9fcbad57043 @@ -349,6 +386,7 @@ service: response: docs: Request was successful type: root.AssetFolder + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -389,6 +427,7 @@ service: response: docs: Request was successful type: root.AssetFolder + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/collections.yml b/.mock/definition/collections.yml index 661b54b..effcb1d 100644 --- a/.mock/definition/collections.yml +++ b/.mock/definition/collections.yml @@ -22,6 +22,7 @@ service: response: docs: Request was successful type: root.CollectionList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -56,8 +57,16 @@ service: path: /sites/{site_id}/collections method: POST auth: true - docs: | - Create a Collection for a site. + docs: > + Create a Collection for a site with collection fields. + + + Each collection includes the required _name_ and _slug_ fields, which + are generated automatically. You can update the `displayName` of these + fields, but the slug for them cannot be changed. Fields slugs are + automatically converted to lowercase. Spaces in slugs are replaced with + hyphens. + Required scope | `cms:write` source: @@ -80,14 +89,19 @@ service: slug: type: optional docs: Part of a URL that identifier + fields: + type: optional> + docs: An array of custom fields to add to the collection content-type: application/json response: docs: Request was successful type: root.Collection + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError - root.NotFoundError + - root.ConflictError - root.TooManyRequestsError - root.InternalServerError examples: @@ -97,22 +111,51 @@ service: displayName: Blog Posts singularName: Blog Post slug: posts + fields: + - isRequired: true + type: PlainText + displayName: Title + helpText: The title of the blog post + - isRequired: true + type: RichText + displayName: Content + helpText: The content of the blog post + - isRequired: true + type: Reference + displayName: Author + helpText: The author of the blog post + metadata: + collectionId: 23cc2d952d4e4631ffd4345d2743db4e response: body: - id: 580e63fc8c9a982ac9b8b745 + id: 562ac0395358780a1f5e6fbd displayName: Blog Posts singularName: Blog Post - slug: post + slug: posts createdOn: '2016-10-24T19:41:48Z' lastUpdated: '2016-10-24T19:42:38Z' fields: - - id: 23cc2d952d4e4631ffd4345d2743db4e + - id: id isRequired: true isEditable: true type: PlainText - slug: name - displayName: Name - helpText: helpText + slug: title + displayName: Title + helpText: The title of the blog post + - id: id + isRequired: true + isEditable: true + type: RichText + slug: content + displayName: Content + helpText: The content of the blog post + - id: id + isRequired: true + isEditable: true + type: Reference + slug: author + displayName: Author + helpText: The author of the blog post get: path: /collections/{collection_id} method: GET @@ -131,6 +174,7 @@ service: response: docs: Request was successful type: root.Collection + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -142,20 +186,129 @@ service: collection_id: 580e63fc8c9a982ac9b8b745 response: body: - id: 580e63fc8c9a982ac9b8b745 - displayName: Blog Posts - singularName: Blog Post - slug: post - createdOn: '2016-10-24T19:41:48Z' - lastUpdated: '2016-10-24T19:42:38Z' + id: 7f15043107e2fc95644e93807ee25dd6 + displayName: Guide Entries + singularName: Guide Entry + slug: guide-entry + createdOn: '2024-04-12T12:42:00Z' + lastUpdated: '2024-04-12T12:42:00Z' fields: - - id: 23cc2d952d4e4631ffd4345d2743db4e + - id: 5e2a1b3c4d5e6f7890a1b2c3 isRequired: true isEditable: true type: PlainText slug: name - displayName: Name - helpText: helpText + displayName: Entry Title + helpText: Name of the entry. + - id: 5e2a1b3c4d5e6f7890a1b2c4 + isRequired: true + isEditable: true + type: PlainText + slug: slug + displayName: Slug + helpText: Slug of the entry. + - id: 6f7e8d9c0b1a2e3d4c5b6a7f + isRequired: false + isEditable: true + type: PlainText + slug: summary + displayName: Summary + helpText: A short summary of the entry. + - id: 1a2b3c4d5e6f7a8b9c0d1e2f + isRequired: false + isEditable: true + type: RichText + slug: entry-html + displayName: Entry HTML + helpText: The HTML content of the entry. + - id: 7e8d9c0b1a2e3d4c5b6a7f8e + isRequired: false + isEditable: true + type: Image + slug: illustration-image + displayName: Illustration Image + helpText: An image of the entry. + - id: 2f3e4d5c6b7a8e9d0c1b2a3f + isRequired: false + isEditable: true + type: VideoLink + slug: demonstration-video + displayName: Demonstration Video + helpText: A video of the entry. + - id: 8e9d0c1b2a3f4e5d6c7b8a9e + isRequired: false + isEditable: true + type: Link + slug: more-info-link + displayName: More Info Link + helpText: A link to more information about the entry. + - id: 3f4e5d6c7b8a9e0d1c2b3a4f + isRequired: false + isEditable: true + type: Number + slug: importance-level + displayName: Importance Level + helpText: The importance level of the entry. + - id: 9e0d1c2b3a4f5e6d7c8b9a0e + isRequired: false + isEditable: true + type: Switch + slug: is-essential + displayName: Is Essential + helpText: Is this entry essential? + - id: 4f5e6d7c8b9a0e1d2c3b4a5f + isRequired: false + isEditable: true + type: Color + slug: first-mentioned + displayName: First Mentioned + helpText: Date of the first mention of the subject. + - id: 0e1d2c3b4a5f6e7d8c9b0a1e + isRequired: false + isEditable: true + type: Color + slug: towel-color + displayName: Towel Color + helpText: The color of the towel. + - id: 5f6e7d8c9b0a1e2d3c4b5a6f + isRequired: false + isEditable: true + type: Reference + slug: related-entry + displayName: Related Entry + helpText: A related entry. + - id: 1e2d3c4b5a6f7e8d9c0b1a2f + isRequired: false + isEditable: true + type: MultiReference + slug: mentioned-in-entries + displayName: Mentioned In Entries + helpText: Entries that mention this subject. + - id: 6f7e8d9c0b1a2e3d4c5b6a8f + isRequired: false + isEditable: true + type: Option + slug: item-type + displayName: Item Type + helpText: The type of item. + - id: 2e3d4c5b6a7f8e9d0c1b2a4f + isRequired: false + isEditable: true + type: File + slug: guide-file + displayName: Guide File + - id: 7f8e9d0c1b2a3f4e5d6c8b9e + isRequired: false + isEditable: true + type: Email + slug: contributor-email + displayName: Contributor Email + - id: 3a4f5e6d7c8b9a0e1d2c4b5f + isRequired: false + isEditable: true + type: Phone + slug: emergency-contact + displayName: Emergency Contact delete: path: /collections/{collection_id} method: DELETE diff --git a/.mock/definition/collections/fields.yml b/.mock/definition/collections/fields.yml index 08dc554..a7af253 100644 --- a/.mock/definition/collections/fields.yml +++ b/.mock/definition/collections/fields.yml @@ -1,24 +1,3 @@ -types: - FieldCreateType: - enum: - - Color - - DateTime - - Email - - ExtFileRef - - File - - Image - - Link - - MultiImage - - Number - - Phone - - PlainText - - RichText - - Switch - - Video - docs: Choose these appropriate field type for your collection data - inline: true - source: - openapi: ../../../openapi/referenced-specs/v2.yml imports: root: ../__package__.yml service: @@ -30,20 +9,15 @@ service: method: POST auth: true docs: > - Create a custom field in a collection. + Create a custom field in a collection. - Slugs must be all lowercase letters without spaces. + Field validation is currently not available through the API. - If you pass a string with uppercase letters and/or spaces to the "Slug" - property, Webflow will - convert the slug to lowercase and replace spaces with "-." - - - Only some field types can be created through the API. - - This endpoint does not currently support bulk creation. + 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` @@ -55,48 +29,88 @@ service: docs: Unique identifier for a Collection display-name: Create Collection Field request: - name: FieldCreate - body: - properties: - isRequired: - type: optional - docs: define whether a field is required in a collection - type: - type: FieldCreateType - docs: Choose these appropriate field type for your collection data - displayName: - type: string - docs: The name of a field - helpText: - type: optional - docs: Additional text to help anyone filling out this field + body: root.FieldCreate content-type: application/json response: docs: Request was successful - type: root.Field + type: root.FieldCreate + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError - root.NotFoundError + - root.ConflictError - root.TooManyRequestsError - root.InternalServerError examples: - - path-parameters: + - name: StaticField + path-parameters: collection_id: 580e63fc8c9a982ac9b8b745 request: + id: 562ac0395358780a1f5e6fbc + isEditable: true isRequired: false type: RichText displayName: Post Body helpText: Add the body of your post here response: body: - id: 75821f618da60c18383330bcc0ca488b - isRequired: false + id: 562ac0395358780a1f5e6fbc isEditable: true + isRequired: false type: RichText - slug: post-body displayName: Post Body helpText: Add the body of your post here + - name: OptionField + path-parameters: + collection_id: 580e63fc8c9a982ac9b8b745 + request: + id: 562ac0395358780a1f5e6fbc + isEditable: true + isRequired: false + type: Option + displayName: Post Type + helpText: Add the body of your post here + metadata: + options: + - name: Feature + - name: News + - name: Product Highlight + response: + body: + id: 562ac0395358780a1f5e6fbc + isEditable: true + isRequired: false + type: Option + displayName: Post Type + helpText: Add the body of your post here + metadata: + options: + - name: Feature + - name: News + - name: Product Highlight + - name: ReferenceField + path-parameters: + collection_id: 580e63fc8c9a982ac9b8b745 + request: + id: 562ac0395358780a1f5e6fbd + isEditable: true + isRequired: false + type: Reference + displayName: Author + helpText: Add the post author here + metadata: + collectionId: 63692ab61fb2852f582ba8f5 + response: + body: + id: 562ac0395358780a1f5e6fbd + isEditable: true + isRequired: false + type: Reference + displayName: Author + helpText: Add the post author here + metadata: + collectionId: 63692ab61fb2852f582ba8f5 delete: path: /collections/{collection_id}/fields/{field_id} method: DELETE @@ -162,6 +176,7 @@ service: response: docs: Request was successful type: root.Field + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -185,5 +200,7 @@ service: slug: post-body displayName: Post Body helpText: Add the body of your post here + validations: + additionalProperties: additionalProperties source: openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/definition/collections/items.yml b/.mock/definition/collections/items.yml index f765817..997b173 100644 --- a/.mock/definition/collections/items.yml +++ b/.mock/definition/collections/items.yml @@ -20,7 +20,7 @@ types: source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true - ItemsCreateItemRequest: + ItemsCreateItemRequestBody: discriminated: false union: - root.CollectionItemPostSingle @@ -38,6 +38,13 @@ types: source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true + ItemsUpdateItemsResponse: + discriminated: false + union: + - type: root.CollectionItem + - type: root.CollectionItemList + source: + openapi: ../../../openapi/referenced-specs/v2.yml ItemsListItemsLiveRequestSortBy: enum: - lastPublished @@ -59,16 +66,16 @@ types: source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true - ItemsCreateItemLiveRequest: + ItemsCreateItemLiveRequestBody: discriminated: false union: - - root.CollectionItem - - Multiple Live Items + - type: root.CollectionItem + - type: Multiple Live Items source: openapi: ../../../openapi/referenced-specs/v2.yml ItemsDeleteItemsLiveRequestItemsItem: properties: - itemId: + id: type: string docs: Unique identifier for the Item cmsLocaleIds: @@ -113,12 +120,48 @@ types: CreateBulkCollectionItemRequestBodyFieldData: discriminated: false union: - - Single CMS Item + - type: Single CMS Item - docs: A list of CMS items to create type: list source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true + Item IDs: + docs: An array of Item IDs in a single locale + properties: + itemIds: + type: optional> + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + ItemsPublishItemRequestItemsItemsItem: + properties: + id: + type: string + docs: The ID of the CMS item + cmsLocaleIds: + type: optional> + docs: Array of identifiers for the locales where the item will be published + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + Item IDs with Locales: + docs: An array of Item IDs with included `cmsLocaleIds` + properties: + items: + type: optional> + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + ItemsPublishItemRequest: + discriminated: false + union: + - type: Item IDs + docs: An array of Item IDs in a single locale + - type: Item IDs with Locales + docs: An array of Item IDs with included `cmsLocaleIds` + source: + openapi: ../../../openapi/referenced-specs/v2.yml ItemsPublishItemResponse: properties: publishedItemIds: optional> @@ -166,10 +209,10 @@ service: docs: 'Maximum number of records to be returned (max limit: 100)' name: type: optional - docs: The name of the item(s) + docs: Filter by the exact name of the item(s) slug: type: optional - docs: The slug of the item + docs: Filter by the exact slug of the item sortBy: type: optional docs: Sort results by the provided value @@ -179,6 +222,7 @@ service: response: docs: Request was successful type: root.CollectionItemList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -229,7 +273,7 @@ service: To create items across multiple locales, please use [this - endpoint.](/v2.0.0/data/reference/cms/collection-items/staged-items/create-items) + endpoint.](/data/reference/cms/collection-items/staged-items/create-items) Required scope | `CMS:write` @@ -241,11 +285,20 @@ service: docs: Unique identifier for a Collection display-name: Create Collection Item(s) request: - body: ItemsCreateItemRequest + body: ItemsCreateItemRequestBody + query-parameters: + skipInvalidFiles: + type: optional + default: true + docs: >- + When true, invalid files are skipped and processing continues. + When false, the entire request fails if any file is invalid. + name: ItemsCreateItemRequest content-type: application/json response: docs: Request was successful type: root.CollectionItem + status-code: 202 errors: - root.BadRequestError - root.UnauthorizedError @@ -322,8 +375,8 @@ service: Delete Items from a Collection. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the - items are localized, items will be deleted only in the primary locale. + Items will only be deleted in the primary + locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -338,7 +391,7 @@ service: name: ItemsDeleteItemsRequest body: properties: - items: optional> + items: list content-type: application/json errors: - root.BadRequestError @@ -350,17 +403,22 @@ service: examples: - path-parameters: collection_id: 580e63fc8c9a982ac9b8b745 - request: {} + request: + items: + - id: 580e64008c9a982ac9b8b754 update-items: path: /collections/{collection_id}/items method: PATCH auth: true docs: > - Update a single item or multiple items (up to 100) in a Collection. + Update a single item or multiple items in a Collection. + + + The limit for this endpoint is 100 items. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the - items are localized, items will be updated only in the primary locale. + Items will only be updated in the primary + locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -373,13 +431,21 @@ service: display-name: Update Collection Items request: name: ItemsUpdateItemsRequest + query-parameters: + skipInvalidFiles: + type: optional + default: true + docs: >- + When true, invalid files are skipped and processing continues. + When false, the entire request fails if any file is invalid. body: properties: items: optional> content-type: application/json response: docs: Request was successful - type: root.CollectionItem + type: ItemsUpdateItemsResponse + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -418,19 +484,55 @@ service: featured: false response: body: - id: id - cmsLocaleId: 653ad57de882f528b32e810e - lastPublished: '2023-03-17T18:47:35.560Z' - lastUpdated: '2023-03-17T18:47:35.560Z' - createdOn: '2023-03-17T18:47:35.560Z' - isArchived: true - isDraft: true - fieldData: - name: My new item - slug: my-new-item - date: '2022-11-18T00:00:00.000Z' - featured: false - color: '#db4b68' + items: + - id: 66f6ed9576ddacf3149d5ea6 + cmsLocaleId: 66f6e966c9e1dc700a857ca5 + lastPublished: '2024-09-27T17:38:29.066Z' + lastUpdated: '2024-09-27T17:38:29.066Z' + createdOn: '2024-09-27T17:38:29.066Z' + isArchived: false + isDraft: false + fieldData: + name: Ne Paniquez Pas + slug: ne-paniquez-pas + featured: false + - id: 66f6ed9576ddacf3149d5ea6 + cmsLocaleId: 66f6e966c9e1dc700a857ca4 + lastPublished: '2024-09-27T17:38:29.066Z' + lastUpdated: '2024-09-27T17:38:29.066Z' + createdOn: '2024-09-27T17:38:29.066Z' + isArchived: false + isDraft: false + fieldData: + name: No Entrar en Pánico + slug: no-entrar-en-panico + featured: false + - id: 66f6ed9576ddacf3149d5eaa + cmsLocaleId: 66f6e966c9e1dc700a857ca5 + lastPublished: '2024-09-27T17:38:29.066Z' + lastUpdated: '2024-09-27T17:38:29.066Z' + createdOn: '2024-09-27T17:38:29.066Z' + isArchived: false + isDraft: false + fieldData: + name: Au Revoir et Merci pour Tous les Poissons + slug: au-revoir-et-merci + featured: false + - id: 66f6ed9576ddacf3149d5eaa + cmsLocaleId: 66f6e966c9e1dc700a857ca4 + lastPublished: '2024-09-27T17:38:29.066Z' + lastUpdated: '2024-09-27T17:38:29.066Z' + createdOn: '2024-09-27T17:38:29.066Z' + isArchived: false + isDraft: false + fieldData: + name: Hasta Luego y Gracias por Todo el Pescado + slug: hasta-luego-y-gracias + featured: false + pagination: + limit: 25 + offset: 0 + total: 4 - name: MultipleItems path-parameters: collection_id: 580e63fc8c9a982ac9b8b745 @@ -454,113 +556,46 @@ service: department: Product response: body: - id: id - cmsLocaleId: 653ad57de882f528b32e810e - lastPublished: '2023-03-17T18:47:35.560Z' - lastUpdated: '2023-03-17T18:47:35.560Z' - createdOn: '2023-03-17T18:47:35.560Z' - isArchived: true - isDraft: true - fieldData: - name: My new item - slug: my-new-item - date: '2022-11-18T00:00:00.000Z' - featured: false - color: '#db4b68' - - name: Multiple items updated across multiple locales - path-parameters: - collection_id: 580e63fc8c9a982ac9b8b745 - request: - items: - - id: 66f6ed9576ddacf3149d5ea6 - cmsLocaleId: 66f6e966c9e1dc700a857ca5 - fieldData: - name: Ne Paniquez Pas - slug: ne-paniquez-pas - featured: false - - id: 66f6ed9576ddacf3149d5ea6 - cmsLocaleId: 66f6e966c9e1dc700a857ca4 - fieldData: - name: No Entrar en Pánico - slug: no-entrar-en-panico - featured: false - - id: 66f6ed9576ddacf3149d5eaa - cmsLocaleId: 66f6e966c9e1dc700a857ca5 - fieldData: - name: Au Revoir et Merci pour Tous les Poissons - slug: au-revoir-et-merci - featured: false - - id: 66f6ed9576ddacf3149d5eaa - cmsLocaleId: 66f6e966c9e1dc700a857ca4 - fieldData: - name: Hasta Luego y Gracias por Todo el Pescado - slug: hasta-luego-y-gracias - featured: false - response: - body: - id: id - cmsLocaleId: 653ad57de882f528b32e810e - lastPublished: '2023-03-17T18:47:35.560Z' - lastUpdated: '2023-03-17T18:47:35.560Z' - createdOn: '2023-03-17T18:47:35.560Z' - isArchived: true - isDraft: true - fieldData: - name: My new item - slug: my-new-item - date: '2022-11-18T00:00:00.000Z' - featured: false - color: '#db4b68' - - name: Mulitple items updated in a single locale - path-parameters: - collection_id: 580e63fc8c9a982ac9b8b745 - request: - items: - - id: 66f6ed9576ddacf3149d5ea6 - cmsLocaleId: 66f6e966c9e1dc700a857ca5 - fieldData: - name: Ne Paniquez Pas - slug: ne-paniquez-pas - featured: false - - id: 66f6ed9576ddacf3149d5ea6 - cmsLocaleId: 66f6e966c9e1dc700a857ca4 - fieldData: - name: No Entrar en Pánico - slug: no-entrar-en-panico - featured: false - - id: 66f6ed9576ddacf3149d5eaa - cmsLocaleId: 66f6e966c9e1dc700a857ca5 - fieldData: - name: Au Revoir et Merci pour Tous les Poissons - slug: au-revoir-et-merci - featured: false - - id: 66f6ed9576ddacf3149d5eaa - cmsLocaleId: 66f6e966c9e1dc700a857ca4 - fieldData: - name: Hasta Luego y Gracias por Todo el Pescado - slug: hasta-luego-y-gracias - featured: false - response: - body: - id: id - cmsLocaleId: 653ad57de882f528b32e810e - lastPublished: '2023-03-17T18:47:35.560Z' - lastUpdated: '2023-03-17T18:47:35.560Z' - createdOn: '2023-03-17T18:47:35.560Z' - isArchived: true - isDraft: true - fieldData: - name: My new item - slug: my-new-item - date: '2022-11-18T00:00:00.000Z' - featured: false - color: '#db4b68' + items: + - id: 62b720ef280c7a7a3be8cabe + cmsLocaleId: 66f6e966c9e1dc700a857ca3 + lastPublished: '2022-06-30T13:35:20.878Z' + lastUpdated: '2022-06-25T14:51:27.809Z' + createdOn: '2022-06-25T14:51:27.809Z' + isArchived: false + isDraft: false + fieldData: + name: Senior Data Analyst + slug: senior-data-analyst + url: https://boards.greenhouse.io/webflow/jobs/26567701 + department: Data + - id: 62c880ef281c7b7b4cf9dabc + cmsLocaleId: 66f6e966c9e1dc700a857ca3 + lastPublished: '2023-04-15T10:25:18.123Z' + lastUpdated: '2023-04-10T11:45:30.567Z' + createdOn: '2023-04-10T11:45:30.567Z' + isArchived: false + isDraft: false + fieldData: + name: Product Manager + slug: product-manager + url: https://boards.greenhouse.io/webflow/jobs/31234567 + department: Product + pagination: + limit: 25 + offset: 0 + total: 2 list-items-live: path: /collections/{collection_id}/items/live method: GET auth: true docs: | - List of all live Items within a Collection. + List all published items in a collection. + + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + Required scope | `CMS:read` source: @@ -590,10 +625,10 @@ service: docs: 'Maximum number of records to be returned (max limit: 100)' name: type: optional - docs: The name of the item(s) + docs: Filter by the exact name of the item(s) slug: type: optional - docs: The slug of the item + docs: Filter by the exact slug of the item sortBy: type: optional docs: Sort results by the provided value @@ -603,6 +638,8 @@ service: response: docs: Request was successful type: root.CollectionItemList + status-code: 200 + url: Data API errors: - root.BadRequestError - root.UnauthorizedError @@ -648,13 +685,13 @@ service: method: POST auth: true docs: > - Create live Item(s) in a Collection. The Item(s) will be published to - the live site. + 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.](/v2.0.0/data/reference/cms/collection-items/staged-items/create-items) + endpoint.](/data/reference/cms/collection-items/staged-items/create-items) @@ -667,11 +704,20 @@ service: docs: Unique identifier for a Collection display-name: Create Live Collection Item(s) request: - body: ItemsCreateItemLiveRequest + body: ItemsCreateItemLiveRequestBody + query-parameters: + skipInvalidFiles: + type: optional + default: true + docs: >- + When true, invalid files are skipped and processing continues. + When false, the entire request fails if any file is invalid. + name: ItemsCreateItemLiveRequest content-type: application/json response: docs: Request was successful type: root.CollectionItem + status-code: 202 errors: - root.BadRequestError - root.UnauthorizedError @@ -745,14 +791,12 @@ service: method: DELETE auth: true docs: > - Remove an item or multiple items (up to 100 items) from the live site. - Deleting published items will unpublish the items from the live site and - set them to draft. + Unpublish up to 100 items from the live site and set the `isDraft` + property to `true`. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the - items are localized, items will be unpublished only in the primary - locale. + Items will only be unpublished in the + primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -762,12 +806,12 @@ service: collection_id: type: string docs: Unique identifier for a Collection - display-name: Delete Live Collection Items + display-name: Unpublish Live Collection Items request: name: ItemsDeleteItemsLiveRequest body: properties: - items: optional> + items: list content-type: application/json errors: - root.BadRequestError @@ -778,18 +822,20 @@ service: examples: - path-parameters: collection_id: 580e63fc8c9a982ac9b8b745 - request: {} + request: + items: + - id: 580e64008c9a982ac9b8b754 update-items-live: path: /collections/{collection_id}/items/live method: PATCH auth: true docs: > - Update a single live item or multiple live items (up to 100) in a - Collection + Update a single published item or multiple published items (up to 100) + in a Collection - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the - items are localized, items will be updated only in the primary locale. + Items will only be updated in the primary + locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -802,6 +848,13 @@ service: display-name: Update Live Collection Items request: name: ItemsUpdateItemsLiveRequest + query-parameters: + skipInvalidFiles: + type: optional + default: true + docs: >- + When true, invalid files are skipped and processing continues. + When false, the entire request fails if any file is invalid. body: properties: items: optional> @@ -809,10 +862,12 @@ service: response: docs: Request was successful type: root.CollectionItemListNoPagination + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError - root.NotFoundError + - root.ConflictError - root.TooManyRequestsError - root.InternalServerError examples: @@ -850,44 +905,44 @@ service: items: - id: 66f6ed9576ddacf3149d5ea6 cmsLocaleId: 66f6e966c9e1dc700a857ca5 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: Ne Paniquez Pas slug: ne-paniquez-pas featured: false - id: 66f6ed9576ddacf3149d5ea6 cmsLocaleId: 66f6e966c9e1dc700a857ca4 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: No Entrar en Pánico slug: no-entrar-en-panico featured: false - id: 66f6ed9576ddacf3149d5eaa cmsLocaleId: 66f6e966c9e1dc700a857ca5 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: Au Revoir et Merci pour Tous les Poissons slug: au-revoir-et-merci featured: false - id: 66f6ed9576ddacf3149d5eaa cmsLocaleId: 66f6e966c9e1dc700a857ca4 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: Hasta Luego y Gracias por Todo el Pescado slug: hasta-luego-y-gracias @@ -918,44 +973,44 @@ service: items: - id: 66f6ed9576ddacf3149d5ea6 cmsLocaleId: 66f6e966c9e1dc700a857ca5 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: Ne Paniquez Pas slug: ne-paniquez-pas featured: false - id: 66f6ed9576ddacf3149d5ea6 cmsLocaleId: 66f6e966c9e1dc700a857ca4 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: No Entrar en Pánico slug: no-entrar-en-panico featured: false - id: 66f6ed9576ddacf3149d5eaa cmsLocaleId: 66f6e966c9e1dc700a857ca5 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: Au Revoir et Merci pour Tous les Poissons slug: au-revoir-et-merci featured: false - id: 66f6ed9576ddacf3149d5eaa cmsLocaleId: 66f6e966c9e1dc700a857ca4 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: Hasta Luego y Gracias por Todo el Pescado slug: hasta-luego-y-gracias @@ -994,49 +1049,49 @@ service: items: - id: 66f6ed9576ddacf3149d5ea6 cmsLocaleId: 66f6e966c9e1dc700a857ca5 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: Ne Paniquez Pas slug: ne-paniquez-pas featured: false - id: 66f6ed9576ddacf3149d5ea6 cmsLocaleId: 66f6e966c9e1dc700a857ca4 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: No Entrar en Pánico slug: no-entrar-en-panico featured: false - id: 66f6ed9576ddacf3149d5eaa cmsLocaleId: 66f6e966c9e1dc700a857ca5 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: Au Revoir et Merci pour Tous les Poissons slug: au-revoir-et-merci featured: false - id: 66f6ed9576ddacf3149d5eaa cmsLocaleId: 66f6e966c9e1dc700a857ca4 - lastPublished: '2023-03-17T18:47:35.560Z' + lastPublished: '2024-09-27T17:38:29.066Z' lastUpdated: '2024-09-27T17:38:29.066Z' createdOn: '2024-09-27T17:38:29.066Z' - isArchived: true - isDraft: true + isArchived: false + isDraft: false fieldData: name: Hasta Luego y Gracias por Todo el Pescado slug: hasta-luego-y-gracias featured: false - - name: Mulitple items updated in a single locale + - name: Multiple items updated in a single locale path-parameters: collection_id: 580e63fc8c9a982ac9b8b745 request: @@ -1101,9 +1156,11 @@ service: corresponding locales. - **Notes:** + - This endpoint can create up to 100 items in a request. - - If the `cmsLocaleIds` parameter is undefined or empty and localization is enabled, items will only be created in the primary locale. + - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale. + + Required scope | `CMS:write` source: @@ -1115,6 +1172,13 @@ service: display-name: Create Collection Items request: name: CreateBulkCollectionItemRequestBody + query-parameters: + skipInvalidFiles: + type: optional + default: true + docs: >- + When true, invalid files are skipped and processing continues. + When false, the entire request fails if any file is invalid. body: properties: cmsLocaleIds: @@ -1129,12 +1193,13 @@ service: isDraft: type: optional docs: Indicates whether the item is in draft state. - default: false + default: true fieldData: CreateBulkCollectionItemRequestBodyFieldData content-type: application/json response: docs: Request was successful type: root.BulkCollectionItem + status-code: 202 errors: - root.BadRequestError - root.UnauthorizedError @@ -1173,7 +1238,7 @@ service: date: '2022-11-18T00:00:00.000Z' featured: false color: '#db4b68' - - name: Create multiple items across multipel locales + - name: Create multiple items across multiple locales path-parameters: collection_id: 580e63fc8c9a982ac9b8b745 request: @@ -1298,6 +1363,8 @@ service: response: docs: Request was successful type: root.CollectionItem + status-code: 200 + url: Production errors: - root.BadRequestError - root.UnauthorizedError @@ -1327,10 +1394,8 @@ service: path: /collections/{collection_id}/items/{item_id} method: DELETE auth: true - docs: > - Delete an Item from a Collection. This endpoint does not currently - support bulk deletion. - + docs: | + Delete an item from a collection. Required scope | `CMS:write` source: @@ -1383,10 +1448,19 @@ service: display-name: Update Collection Item request: body: root.CollectionItemPatchSingle + query-parameters: + skipInvalidFiles: + type: optional + default: true + docs: >- + When true, invalid files are skipped and processing continues. + When false, the entire request fails if any file is invalid. + name: ItemsUpdateItemRequest content-type: application/json response: docs: Request was successful type: root.CollectionItem + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -1428,6 +1502,11 @@ service: docs: | Get details of a selected Collection live Item. + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + + Required scope | `CMS:read` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -1452,6 +1531,8 @@ service: response: docs: Request was successful type: root.CollectionItem + status-code: 200 + url: Data API errors: - root.BadRequestError - root.UnauthorizedError @@ -1482,11 +1563,12 @@ service: method: DELETE auth: true docs: > - Remove a live item from the site. Removing a published item will - unpublish the item from the live site and set it to draft. + Unpublish a live item from the site and set the `isDraft` property to + `true`. - This endpoint does not currently support bulk deletion. + For bulk unpublishing, please use [this + endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live) Required scope | `CMS:write` @@ -1499,7 +1581,7 @@ service: item_id: type: string docs: Unique identifier for an Item - display-name: Delete Live Collection Item + display-name: Unpublish Live Collection Item request: name: ItemsDeleteItemLiveRequest query-parameters: @@ -1542,14 +1624,24 @@ service: display-name: Update Live Collection Item request: body: root.CollectionItemPatchSingle + query-parameters: + skipInvalidFiles: + type: optional + default: true + docs: >- + When true, invalid files are skipped and processing continues. + When false, the entire request fails if any file is invalid. + name: ItemsUpdateItemLiveRequest content-type: application/json response: docs: Request was successful type: root.CollectionItem + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError - root.NotFoundError + - root.ConflictError - root.TooManyRequestsError - root.InternalServerError examples: @@ -1596,14 +1688,12 @@ service: docs: Unique identifier for a Collection display-name: Publish Collection Item request: - name: ItemsPublishItemRequest - body: - properties: - itemIds: list + body: ItemsPublishItemRequest content-type: application/json response: docs: Request was successful type: ItemsPublishItemResponse + status-code: 202 errors: - root.BadRequestError - root.UnauthorizedError @@ -1612,11 +1702,52 @@ service: - root.TooManyRequestsError - root.InternalServerError examples: - - path-parameters: + - name: PrimaryLocale + path-parameters: collection_id: 580e63fc8c9a982ac9b8b745 request: itemIds: - - itemIds + - 643fd856d66b6528195ee2ca + - 643fd856d66b6528195ee2cb + - 643fd856d66b6528195ee2cc + response: + body: + publishedItemIds: + - 643fd856d66b6528195ee2ca + - 643fd856d66b6528195ee2cb + errors: + - Staging item ID 643fd856d66b6528195ee2cf not found. + - name: SecondaryLocale + path-parameters: + collection_id: 580e63fc8c9a982ac9b8b745 + request: + items: + - id: 643fd856d66b6528195ee2ca + cmsLocaleIds: + - 653ad57de882f528b32e810e + - id: 643fd856d66b6528195ee2cb + cmsLocaleIds: + - 653ad57de882f528b32e810e + - id: 643fd856d66b6528195ee2cc + cmsLocaleIds: + - 653ad57de882f528b32e810e + response: + body: + publishedItemIds: + - 643fd856d66b6528195ee2ca + - 643fd856d66b6528195ee2cb + errors: + - Staging item ID 643fd856d66b6528195ee2cf not found. + - name: MultipleLocales + path-parameters: + collection_id: 580e63fc8c9a982ac9b8b745 + request: + items: + - id: 643fd856d66b6528195ee2ca + cmsLocaleIds: + - 653ad57de882f528b32e810e + - 6514390aea353fc691d69827 + - 65143930ea353fc691d69cd8 response: body: publishedItemIds: diff --git a/.mock/definition/components.yml b/.mock/definition/components.yml index b9eb7d6..7ce89f4 100644 --- a/.mock/definition/components.yml +++ b/.mock/definition/components.yml @@ -33,6 +33,7 @@ service: response: docs: Request was successful type: root.ComponentList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -59,13 +60,9 @@ service: readonly: true - id: 6258612d1ee792848f805dcf name: Card - group: Buttons - description: A button component that can be used across the site readonly: true - id: 68a2b1d1ee792848f805dcf name: Nav - group: Buttons - description: A button component that can be used across the site readonly: true pagination: limit: 20 @@ -77,7 +74,8 @@ service: auth: true docs: > Get static content from a component definition. This includes text - nodes, image nodes and nested component instances. + nodes, image nodes, select nodes, text input nodes, submit button nodes, + and nested component instances. To retrieve dynamic content set by component properties, use the [get component @@ -120,6 +118,7 @@ service: response: docs: Request was successful type: root.ComponentDom + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -127,49 +126,7 @@ service: - root.TooManyRequestsError - root.InternalServerError examples: - - name: ComponentDOM - path-parameters: - site_id: 580e63e98c9a982ac9b8b741 - component_id: 8505ba55-ef72-629e-f85c-33e4b703d48b - query-parameters: - localeId: 65427cf400e02b306eaa04a0 - response: - body: - componentId: 69118560-d0bc-15fc-bbf8-b8fe5f6535b5 - nodes: - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad623 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad627 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad629 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad631 - componentId: 6258612d1ee792848f805dcf - propertyOverrides: - - propertyId: a245c12d-995b-55ee-5ec7-aa36a6cad633 - type: Plain Text - text: - text: Don't Panic! - - propertyId: a245c12d-995b-55ee-5ec7-aa36a6cad635 - type: Rich Text - text: - html:

Always know where your towel is.

- pagination: - limit: 4 - offset: 0 - total: 4 - - name: LocalizedComponentDOM - path-parameters: + - path-parameters: site_id: 580e63e98c9a982ac9b8b741 component_id: 8505ba55-ef72-629e-f85c-33e4b703d48b query-parameters: @@ -178,25 +135,48 @@ service: body: componentId: 69118560-d0bc-15fc-bbf8-b8fe5f6535b5 nodes: - - type: component-instance - id: 69118560-d0bc-15fc-bbf8-b8fe5f6535b8 - componentId: nodes + - id: id + text: {} + attributes: + key: value + type: text + - id: id + text: {} + attributes: + key: value + type: text + - id: id + image: {} + attributes: + key: value + type: image + - id: id + placeholder: placeholder + attributes: + key: value + type: text-input + - id: id + choices: + - value: value + text: text + attributes: + key: value + type: select + - id: id + value: value + waitingText: waitingText + attributes: + key: value + type: submit-button + - id: id + componentId: componentId propertyOverrides: - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: 8ebfb409-7493-3bca-5d48-0e547befb960 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: 69118560-d0bc-15fc-bbf8-b8fe5f6535c2 - componentId: 69118560-d0bc-15fc-bbf8-b8fe5f6535b5 - propertyOverrides: - - propertyId: a245c12d-995b-55ee-5ec7-aa36a6cad623 + type: component-instance pagination: - limit: 100 + limit: 7 offset: 0 - total: 3 + total: 7 update-content: path: /sites/{site_id}/components/{component_id}/dom method: POST @@ -255,6 +235,7 @@ service: response: docs: Request was successful type: ComponentsUpdateContentResponse + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -276,6 +257,17 @@ service: text: >-

Don't Panic!

Always know where your towel is.

+ - nodeId: a245c12d-995b-55ee-5ec7-aa36a6cad635 + choices: + - value: choice-1 + text: First choice + - value: choice-2 + text: Second choice + - nodeId: a245c12d-995b-55ee-5ec7-aa36a6cad642 + placeholder: Enter something here... + - nodeId: a245c12d-995b-55ee-5ec7-aa36a6cad671 + value: Submit + waitingText: Submitting... - nodeId: a245c12d-995b-55ee-5ec7-aa36a6cad629 propertyOverrides: - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 @@ -291,10 +283,10 @@ service: method: GET auth: true docs: > - Get the property default values of a component definition. + Get the default property values of a component definition. - If you do not provide a Locale ID in your request, the response + If you do not include a `localeId` in your request, the response will return any properties that can be localized from the Primary locale. @@ -329,6 +321,7 @@ service: response: docs: Request was successful type: root.ComponentProperties + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -366,18 +359,17 @@ service: method: POST auth: true docs: > - Update the property default values of a component definition in a + Update the default property values of a component definition in a specificed locale. - Before making updates: - - 1. Use the [get component + Before making updates, use the [get component properties](/data/reference/pages-and-components/components/get-properties) - endpoint to identify available properties + endpoint to identify properties that can be updated in a secondary + locale. - The request requires a secondary locale ID. If a locale is + The request requires a secondary locale ID. If a `localeId` is missing, the request will not be processed and will result in an error. @@ -412,6 +404,7 @@ service: response: docs: Request was successful type: ComponentsUpdatePropertiesResponse + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -442,8 +435,12 @@ types: ComponentDomWriteNodesItem: discriminated: false union: - - root.TextNodeWrite - - root.ComponentInstanceNodePropertyOverridesWrite + - type: root.Text Node + - type: root.Component Instance + - type: root.Select + - type: root.Text Input + - type: root.Submit Button + - type: root.Search Button source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true diff --git a/.mock/definition/ecommerce.yml b/.mock/definition/ecommerce.yml index 1a2ca95..b3e9857 100644 --- a/.mock/definition/ecommerce.yml +++ b/.mock/definition/ecommerce.yml @@ -22,6 +22,7 @@ service: response: docs: Request was successful type: root.EcommerceSettings + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/forms.yml b/.mock/definition/forms.yml index 9eac177..2288b2b 100644 --- a/.mock/definition/forms.yml +++ b/.mock/definition/forms.yml @@ -33,6 +33,7 @@ service: response: docs: Request was successful type: root.FormList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -108,6 +109,7 @@ service: response: docs: Request was successful type: root.Form + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -127,7 +129,6 @@ service: 660d5bcc9c0772150459dfb1: displayName: Name type: Plain - placeholder: Enter your email userVisible: true 589a331aa51e760df7ccb89d: displayName: Email @@ -137,7 +138,6 @@ service: responseSettings: redirectUrl: https://example.com redirectMethod: GET - redirectAction: POST https://example.com sendEmailConfirmation: true id: 589a331aa51e760df7ccb89e siteId: 580e63e98c9a982ac9b8b741 @@ -153,6 +153,12 @@ service: docs: | 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` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -175,6 +181,7 @@ service: response: docs: Request was successful type: root.FormSubmissionList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -226,6 +233,7 @@ service: response: docs: Request was successful type: root.FormSubmission + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -246,6 +254,33 @@ service: formResponse: First Name: Arthur Last Name: Dent + delete-submission: + path: /form_submissions/{form_submission_id} + method: DELETE + auth: true + docs: | + Delete a form submission + + + Required scope | `forms:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + form_submission_id: + type: string + docs: Unique identifier for a Form Submission + display-name: Delete Form Submission + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.ForbiddenError + - root.NotFoundError + - root.ConflictError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + form_submission_id: 580e63e98c9a982ac9b8b741 update-submission: path: /form_submissions/{form_submission_id} method: PATCH @@ -274,6 +309,7 @@ service: response: docs: Request was successful type: root.FormSubmission + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -296,6 +332,82 @@ service: formResponse: First Name: Arthur Last Name: Dent + list-submissions-by-site: + path: /sites/{site_id}/form_submissions + method: GET + auth: true + docs: > + List form submissions for a given site. This endpoint differs from the + existing [List Form Submissions + endpoint](/data/reference/forms/form-submissions/list-submissions) by + accepting `siteId` as a path parameter and `elementId` as a query + parameter. You can get the `elementId` from the [List forms + endpoint](/data/reference/forms/forms/list). + + + + + Required scope | `forms:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: List Form Submissions by Site + request: + name: FormsListSubmissionsBySiteRequest + query-parameters: + elementId: + type: optional + docs: Identifier for an element + offset: + type: optional + docs: >- + Offset used for pagination if the results have more than limit + records + limit: + type: optional + docs: 'Maximum number of records to be returned (max limit: 100)' + response: + docs: Request was successful + type: root.FormSubmissionList + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.ForbiddenError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + query-parameters: + elementId: 18259716-3e5a-646a-5f41-5dc4b9405aa0 + response: + body: + formSubmissions: + - id: 6321ca84df3949bfc6752327 + displayName: Sample Form + siteId: 62749158efef318abc8d5a0f + workspaceId: 62749158efef318abc8d5a0f + dateSubmitted: '2022-09-14T12:35:16Z' + formResponse: + First Name: Arthur + Last Name: Dent + - id: 660d64fabf6e0a0d4edab981 + displayName: Sample Form + siteId: 62749158efef318abc8d5a0f + workspaceId: 62749158efef318abc8d5a0f + dateSubmitted: '2022-09-14T12:35:16Z' + formResponse: + First Name: Ford + Last Name: Prefect + pagination: + limit: 25 + offset: 0 + total: 2 source: openapi: ../../../openapi/referenced-specs/v2.yml display-name: Forms diff --git a/.mock/definition/inventory.yml b/.mock/definition/inventory.yml index 5e69c29..2c4a7c9 100644 --- a/.mock/definition/inventory.yml +++ b/.mock/definition/inventory.yml @@ -25,6 +25,7 @@ service: response: docs: Request was successful type: root.InventoryItem + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -88,6 +89,7 @@ service: response: docs: Request was successful type: root.InventoryItem + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/orders.yml b/.mock/definition/orders.yml index b2802cf..37d31bb 100644 --- a/.mock/definition/orders.yml +++ b/.mock/definition/orders.yml @@ -57,6 +57,7 @@ service: response: docs: Request was successful type: root.OrderList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -81,11 +82,6 @@ service: Please gift wrap with a personal note saying "Happy Birthday, Ford! 🎉 acceptedOn: '2024-04-10T13:16:21Z' - fulfilledOn: '2018-12-03T22:06:15Z' - refundedOn: '2018-12-03T22:06:15Z' - disputedOn: '2018-12-03T22:06:15Z' - disputeUpdatedOn: '2018-12-03T22:06:15Z' - disputeLastStatus: warning_needs_response customerPaid: unit: USD value: '5892' @@ -155,7 +151,7 @@ service: variantSKU: luxurious-fresh-ball-generic-bronze-practical-plastic variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg variantPrice: unit: USD value: '5892' @@ -180,7 +176,7 @@ service: variantSKU: incredible-bronze-towels-sleek-frozen-incredible-metal variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e26729_image16.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e26729_image16.jpeg variantPrice: unit: USD value: '5892' @@ -201,13 +197,6 @@ service: expires: year: 2025 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -235,11 +224,7 @@ service: comment: Example comment to myself orderComment: '' acceptedOn: '2024-03-29T21:29:21Z' - fulfilledOn: '2018-12-03T22:06:15Z' refundedOn: '2024-04-08T18:25:04Z' - disputedOn: '2018-12-03T22:06:15Z' - disputeUpdatedOn: '2018-12-03T22:06:15Z' - disputeLastStatus: warning_needs_response customerPaid: unit: USD value: '5892' @@ -308,7 +293,7 @@ service: variantSKU: luxurious-fresh-ball-generic-bronze-practical-plastic variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg variantPrice: unit: USD value: '5892' @@ -335,7 +320,7 @@ service: recycled-steel-gloves-electronic-granite-handcrafted-grey variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg variantPrice: unit: USD value: '5892' @@ -359,13 +344,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -436,6 +414,7 @@ service: response: docs: Request was successful type: root.Order + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -537,7 +516,7 @@ service: variantSKU: luxurious-fresh-ball-generic-bronze-practical-plastic variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg variantPrice: unit: USD value: '5892' @@ -560,7 +539,7 @@ service: variantSKU: recycled-steel-gloves-electronic-granite-handcrafted-grey variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg variantPrice: unit: USD value: '5892' @@ -571,12 +550,10 @@ service: length: 40 purchasedItemsCount: 2 stripeDetails: - subscriptionId: sub_1J6xwG2eZvKYlo2CXu9Zt0Tn paymentMethod: pm_1OzmzBJYFi4lcbXWHKNdXU7j paymentIntentId: pi_3OzmzDJYFi4lcbXW1hTBW6ft customerId: cus_PpRsNHwWdUoRKR chargeId: ch_3OzmzDJYFi4lcbXW1ndkkrH2 - disputeId: disputeId refundId: re_3OzmzDJYFi4lcbXW1kFAmlBk refundReason: fraudulent stripeCard: @@ -586,13 +563,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -677,6 +647,7 @@ service: response: docs: Request was successful type: root.Order + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -779,7 +750,7 @@ service: variantSKU: luxurious-fresh-ball-generic-bronze-practical-plastic variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg variantPrice: unit: USD value: '5892' @@ -802,7 +773,7 @@ service: variantSKU: recycled-steel-gloves-electronic-granite-handcrafted-grey variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg variantPrice: unit: USD value: '5892' @@ -813,12 +784,10 @@ service: length: 40 purchasedItemsCount: 2 stripeDetails: - subscriptionId: sub_1J6xwG2eZvKYlo2CXu9Zt0Tn paymentMethod: pm_1OzmzBJYFi4lcbXWHKNdXU7j paymentIntentId: pi_3OzmzDJYFi4lcbXW1hTBW6ft customerId: cus_PpRsNHwWdUoRKR chargeId: ch_3OzmzDJYFi4lcbXW1ndkkrH2 - disputeId: disputeId refundId: re_3OzmzDJYFi4lcbXW1kFAmlBk refundReason: fraudulent stripeCard: @@ -828,13 +797,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -909,6 +871,7 @@ service: response: docs: Request was successful type: root.Order + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -1011,7 +974,7 @@ service: variantSKU: luxurious-fresh-ball-generic-bronze-practical-plastic variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg variantPrice: unit: USD value: '5892' @@ -1034,7 +997,7 @@ service: variantSKU: recycled-steel-gloves-electronic-granite-handcrafted-grey variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg variantPrice: unit: USD value: '5892' @@ -1045,12 +1008,10 @@ service: length: 40 purchasedItemsCount: 2 stripeDetails: - subscriptionId: sub_1J6xwG2eZvKYlo2CXu9Zt0Tn paymentMethod: pm_1OzmzBJYFi4lcbXWHKNdXU7j paymentIntentId: pi_3OzmzDJYFi4lcbXW1hTBW6ft customerId: cus_PpRsNHwWdUoRKR chargeId: ch_3OzmzDJYFi4lcbXW1ndkkrH2 - disputeId: disputeId refundId: re_3OzmzDJYFi4lcbXW1kFAmlBk refundReason: fraudulent stripeCard: @@ -1060,13 +1021,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -1132,6 +1086,7 @@ service: response: docs: Request was successful type: root.Order + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -1233,7 +1188,7 @@ service: variantSKU: luxurious-fresh-ball-generic-bronze-practical-plastic variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg variantPrice: unit: USD value: '5892' @@ -1256,7 +1211,7 @@ service: variantSKU: recycled-steel-gloves-electronic-granite-handcrafted-grey variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg variantPrice: unit: USD value: '5892' @@ -1267,12 +1222,10 @@ service: length: 40 purchasedItemsCount: 2 stripeDetails: - subscriptionId: sub_1J6xwG2eZvKYlo2CXu9Zt0Tn paymentMethod: pm_1OzmzBJYFi4lcbXWHKNdXU7j paymentIntentId: pi_3OzmzDJYFi4lcbXW1hTBW6ft customerId: cus_PpRsNHwWdUoRKR chargeId: ch_3OzmzDJYFi4lcbXW1ndkkrH2 - disputeId: disputeId refundId: re_3OzmzDJYFi4lcbXW1kFAmlBk refundReason: fraudulent stripeCard: @@ -1282,13 +1235,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -1363,6 +1309,7 @@ service: response: docs: Request was successful type: root.Order + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -1465,7 +1412,7 @@ service: variantSKU: luxurious-fresh-ball-generic-bronze-practical-plastic variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg variantPrice: unit: USD value: '5892' @@ -1488,7 +1435,7 @@ service: variantSKU: recycled-steel-gloves-electronic-granite-handcrafted-grey variantImage: url: >- - https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg + https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg variantPrice: unit: USD value: '5892' @@ -1499,12 +1446,10 @@ service: length: 40 purchasedItemsCount: 2 stripeDetails: - subscriptionId: sub_1J6xwG2eZvKYlo2CXu9Zt0Tn paymentMethod: pm_1OzmzBJYFi4lcbXWHKNdXU7j paymentIntentId: pi_3OzmzDJYFi4lcbXW1hTBW6ft customerId: cus_PpRsNHwWdUoRKR chargeId: ch_3OzmzDJYFi4lcbXW1ndkkrH2 - disputeId: disputeId refundId: re_3OzmzDJYFi4lcbXW1kFAmlBk refundReason: fraudulent stripeCard: @@ -1514,13 +1459,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: diff --git a/.mock/definition/pages.yml b/.mock/definition/pages.yml index 62de7dc..1a7befe 100644 --- a/.mock/definition/pages.yml +++ b/.mock/definition/pages.yml @@ -38,6 +38,7 @@ service: response: docs: Request was successful type: root.PageList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -56,15 +57,12 @@ service: siteId: 6258612d1ee792848f805dcf title: Guide to the Galaxy slug: guide-to-the-galaxy - parentId: 6419db964a9c435aa3af6251 - collectionId: 6390c49774a71f12831a08e3 createdOn: '2024-03-11T10:42:00Z' lastUpdated: '2024-03-11T10:42:42Z' archived: false draft: false canBranch: true isBranch: false - isMembersOnly: false seo: title: The Ultimate Hitchhiker's Guide to the Galaxy description: >- @@ -83,15 +81,12 @@ service: siteId: 6258612d1ee792848f805dcf title: Towel Day Celebrations slug: towel-day - parentId: 6419db964a9c435aa3af6251 - collectionId: 6390c49774a71f12831a08e3 createdOn: '2024-05-25T09:00:00Z' lastUpdated: '2024-05-25T09:42:00Z' archived: false draft: false canBranch: true isBranch: false - isMembersOnly: false seo: title: Celebrate Towel Day - The Hitchhiker's Guide to the Galaxy description: >- @@ -138,6 +133,7 @@ service: response: docs: Request was successful type: root.Page + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -155,15 +151,12 @@ service: siteId: 6258612d1ee792848f805dcf title: Guide to the Galaxy slug: guide-to-the-galaxy - parentId: 6419db964a9c435aa3af6251 - collectionId: 6390c49774a71f12831a08e3 createdOn: '2024-03-11T10:42:00Z' lastUpdated: '2024-03-11T10:42:42Z' archived: false draft: false canBranch: true isBranch: false - isMembersOnly: false seo: title: The Ultimate Hitchhiker's Guide to the Galaxy description: >- @@ -185,6 +178,10 @@ service: docs: | Update Page-level metadata, including SEO and Open Graph fields. + + Note: When updating Page Metadata in secondary locales, you may only add `slug` to the request if your Site has the [Advanced or Enterprise Localization](https://webflow.com/localization) add-on. + + Required scope | `pages:write` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -206,6 +203,7 @@ service: response: docs: Request was successful type: root.Page + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -248,15 +246,12 @@ service: siteId: 6258612d1ee792848f805dcf title: Guide to the Galaxy slug: guide-to-the-galaxy - parentId: 6419db964a9c435aa3af6251 - collectionId: 6390c49774a71f12831a08e3 createdOn: '2024-03-11T10:42:00Z' lastUpdated: '2024-03-11T10:42:42Z' archived: false draft: false canBranch: true isBranch: false - isMembersOnly: false seo: title: The Ultimate Hitchhiker's Guide to the Galaxy description: >- @@ -276,16 +271,19 @@ service: method: GET auth: true docs: > - Get static content from a static page. This includes text nodes, image - nodes and component instances. + Get content from a static page. This includes text nodes, image nodes, + select nodes, text input nodes, submit button nodes, and component + instances with [property + overrides](https://help.webflow.com/hc/en-us/articles/33961219350547-Component-properties#how-to-modify-property-values-on-component-instances). - To retrieve the contents of components in the page use the [get - component - content](/data/reference/pages-and-components/components/get-content) + + To retrieve the static content of a component instance, use the [Get + Component + Content](/data/reference/pages-and-components/components/get-content) endpoint. - If you do not provide a Locale ID in your request, the response + If you do not include a `localeId` in your request, the response will return any content that can be localized from the Primary locale. @@ -317,6 +315,7 @@ service: response: docs: Request was successful type: root.Dom + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -325,8 +324,7 @@ service: - root.TooManyRequestsError - root.InternalServerError examples: - - name: PageDOM - path-parameters: + - path-parameters: page_id: 63c720f9347c2139b248e552 query-parameters: localeId: 65427cf400e02b306eaa04a0 @@ -334,39 +332,48 @@ service: body: pageId: 658205daa3e8206a523b5ad4 nodes: - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad623 - componentId: nodes + - id: id + text: {} + attributes: + key: value + type: text + - id: id + text: {} + attributes: + key: value + type: text + - id: id + image: {} + attributes: + key: value + type: image + - id: id + choices: + - value: value + text: text + attributes: + key: value + type: select + - id: id + placeholder: placeholder + attributes: + key: value + type: text-input + - id: id + text: {} + attributes: + key: value + type: text + - id: id + componentId: componentId propertyOverrides: - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad627 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad629 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad631 - componentId: 6258612d1ee792848f805dcf - propertyOverrides: - - propertyId: a245c12d-995b-55ee-5ec7-aa36a6cad633 - type: Plain Text - label: Catchphrase - text: - text: Don't Panic! - - propertyId: a245c12d-995b-55ee-5ec7-aa36a6cad635 - type: Rich Text - label: Tagline - text: - html:

Always know where your towel is.

+ type: component-instance pagination: limit: 4 offset: 0 total: 4 + lastUpdated: '2016-10-24T19:42:38Z' update-static-content: path: /pages/{page_id}/dom method: POST @@ -418,6 +425,7 @@ service: response: docs: Request was successful type: UpdateStaticContentResponse + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -438,6 +446,17 @@ service: text: >-

Don't Panic!

Always know where your towel is.

+ - nodeId: a245c12d-995b-55ee-5ec7-aa36a6cad635 + choices: + - value: choice-1 + text: First choice + - value: choice-2 + text: Second choice + - nodeId: a245c12d-995b-55ee-5ec7-aa36a6cad642 + placeholder: Enter something here... + - nodeId: a245c12d-995b-55ee-5ec7-aa36a6cad671 + value: Submit + waitingText: Submitting... - nodeId: a245c12d-995b-55ee-5ec7-aa36a6cad629 propertyOverrides: - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 @@ -456,8 +475,12 @@ types: PageDomWriteNodesItem: discriminated: false union: - - root.TextNodeWrite - - root.ComponentInstanceNodePropertyOverridesWrite + - type: root.Text Node + - type: root.Component Instance + - type: root.Select + - type: root.Text Input + - type: root.Submit Button + - type: root.Search Button source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true diff --git a/.mock/definition/pages/scripts.yml b/.mock/definition/pages/scripts.yml index f8ee328..d0971af 100644 --- a/.mock/definition/pages/scripts.yml +++ b/.mock/definition/pages/scripts.yml @@ -8,22 +8,8 @@ service: path: /pages/{page_id}/custom_code method: GET auth: true - docs: > - Get all registered scripts that have been applied to a specific Page. - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). - + docs: | + Get all scripts applied to a page. Required scope | `custom_code:read` source: @@ -36,6 +22,7 @@ service: response: docs: Request was successful type: root.ScriptApplyList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -59,25 +46,12 @@ service: path: /pages/{page_id}/custom_code method: PUT auth: true - docs: > - Add a registered script to a Page. - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. - - - A site can have a maximum of 800 registered scripts. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + docs: | + Apply scripts to a page. + + 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 | `custom_code:write` source: @@ -93,6 +67,7 @@ service: response: docs: Request was successful type: root.ScriptApplyList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -133,16 +108,7 @@ service: method: DELETE auth: true docs: > - Delete the custom code block that an app has created for a page - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. + Delete a custom code block that the App created on a page. Access to this endpoint requires a bearer token from a [Data diff --git a/.mock/definition/products.yml b/.mock/definition/products.yml index 4c6fcd1..71e5b9a 100644 --- a/.mock/definition/products.yml +++ b/.mock/definition/products.yml @@ -41,6 +41,7 @@ service: response: docs: Request was successful type: root.ProductAndSkUsList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -72,24 +73,35 @@ service: - id: Color name: Color enum: - - id: id + - id: royal-blue name: Royal Blue slug: royal-blue skus: - - id: 580e63fc8c9a982ac9b8b745 + - id: 66072fb71b89448912e2681c cmsLocaleId: 653ad57de882f528b32e810e lastPublished: '2023-03-17T18:47:35Z' lastUpdated: '2023-03-17T18:47:35Z' createdOn: '2023-03-17T18:47:35Z' fieldData: sku-values: - ff42fee0113744f693a764e3431a9cc2: 64a74715c456e36762fc39a1 - name: Blue T-shirt - slug: t-shirt-blue + color: blue + size: small + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default price: - value: 100 + value: 2499 unit: USD + currency: USD quantity: 10 + main-image: https://www.example.com/image.jpg + sku: '1234567890' + sku-properties: + - id: Color + name: Color + enum: + - id: royal-blue + name: Royal Blue + slug: royal-blue pagination: limit: 100 offset: 0 @@ -99,20 +111,14 @@ service: method: POST auth: true docs: > - Create a new product and SKU. + Create a new ecommerce product and defaultSKU. A product, at minimum, + must have a single SKU. - When you create a product, you will always create a SKU, since a Product - Item must have, at minimum, a single SKU. - - - To create a Product with multiple SKUs - for example a T-shirt in sizes - small, medium and large: - - Create parameters in `sku-properties`, also known as [product options and variants.](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants). - - A single `sku-property` would be `color`. Within the `color` property, list the various colors of T-shirts as an array of `enum` values: `royal-blue`, `crimson-red`, and `forrest-green`. - - Once, you've created a Product and its `sku-properties` with `enum` values, Webflow will create a **default SKU**, which will automatically be a combination of the first `sku-properties` you've created. - - In our example, the default SKU will be a Royal Blue T-Shirt, because our first `enum` of our Color `sku-property` is Royal Blue. - - After you've created your product, you can create additional SKUs using the [Create SKU endpoint.](/data/reference/ecommerce/products/create-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 @@ -132,12 +138,13 @@ service: body: properties: publishStatus: optional - product: optional - sku: optional + product: ProductSkuCreateProduct + sku: ProductSkuCreateSku content-type: application/json response: docs: Request was successful type: root.ProductAndSkUs + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -149,7 +156,50 @@ service: examples: - path-parameters: site_id: 580e63e98c9a982ac9b8b741 - request: {} + request: + publishStatus: staging + product: + fieldData: + name: Colorful T-shirt + slug: colorful-t-shirt + description: >- + Our best-selling t-shirt available in multiple colors and + sizes + sku-properties: + - id: color + name: Color + enum: + - id: red + name: Red + slug: red + - id: yellow + name: Yellow + slug: yellow + - id: blue + name: Blue + slug: blue + - id: size + name: Size + enum: + - id: small + name: Small + slug: small + - id: medium + name: Medium + slug: medium + - id: large + name: Large + slug: large + sku: + fieldData: + name: Colorful T-shirt - Red Small + slug: colorful-t-shirt-red-small + price: + 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 response: body: product: @@ -169,29 +219,40 @@ service: - id: Color name: Color enum: - - id: id + - id: royal-blue name: Royal Blue slug: royal-blue - categories: - - categories + category: + - category tax-category: standard-taxable default-sku: default-sku ec-product-type: ff42fee0113744f693a764e3431a9cc2 skus: - - id: 580e63fc8c9a982ac9b8b745 + - id: 66072fb71b89448912e2681c cmsLocaleId: 653ad57de882f528b32e810e lastPublished: '2023-03-17T18:47:35Z' lastUpdated: '2023-03-17T18:47:35Z' createdOn: '2023-03-17T18:47:35Z' fieldData: sku-values: - ff42fee0113744f693a764e3431a9cc2: 64a74715c456e36762fc39a1 - name: Blue T-shirt - slug: t-shirt-blue + color: blue + size: small + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default price: - value: 100 + value: 2499 unit: USD + currency: USD quantity: 10 + main-image: https://www.example.com/image.jpg + sku: '1234567890' + sku-properties: + - id: Color + name: Color + enum: + - id: royal-blue + name: Royal Blue + slug: royal-blue get: path: /sites/{site_id}/products/{product_id} method: GET @@ -214,6 +275,7 @@ service: response: docs: Request was successful type: root.ProductAndSkUs + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -245,29 +307,40 @@ service: - id: Color name: Color enum: - - id: id + - id: royal-blue name: Royal Blue slug: royal-blue - categories: - - categories + category: + - category tax-category: standard-taxable default-sku: default-sku ec-product-type: ff42fee0113744f693a764e3431a9cc2 skus: - - id: 580e63fc8c9a982ac9b8b745 + - id: 66072fb71b89448912e2681c cmsLocaleId: 653ad57de882f528b32e810e lastPublished: '2023-03-17T18:47:35Z' lastUpdated: '2023-03-17T18:47:35Z' createdOn: '2023-03-17T18:47:35Z' fieldData: sku-values: - ff42fee0113744f693a764e3431a9cc2: 64a74715c456e36762fc39a1 - name: Blue T-shirt - slug: t-shirt-blue + color: blue + size: small + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default price: - value: 100 + value: 2499 unit: USD + currency: USD quantity: 10 + main-image: https://www.example.com/image.jpg + sku: '1234567890' + sku-properties: + - id: Color + name: Color + enum: + - id: royal-blue + name: Royal Blue + slug: royal-blue update: path: /sites/{site_id}/products/{product_id} method: PATCH @@ -303,6 +376,7 @@ service: response: docs: Request was successful type: root.Product + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -334,11 +408,11 @@ service: - id: Color name: Color enum: - - id: id + - id: royal-blue name: Royal Blue slug: royal-blue - categories: - - categories + category: + - category tax-category: standard-taxable default-sku: default-sku ec-product-type: ff42fee0113744f693a764e3431a9cc2 @@ -366,7 +440,7 @@ service: product_id: type: string docs: Unique identifier for a Product - display-name: Create SKU + display-name: Create SKUs request: name: ProductsCreateSkuRequest body: @@ -379,6 +453,7 @@ service: response: docs: Request was successful type: ProductsCreateSkuResponse + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -393,24 +468,46 @@ service: product_id: 580e63fc8c9a982ac9b8b745 request: skus: - - {} + - id: 66072fb71b89448912e2681c + cmsLocaleId: 653ad57de882f528b32e810e + lastPublished: '2023-03-17T18:47:35Z' + lastUpdated: '2023-03-17T18:47:35Z' + createdOn: '2023-03-17T18:47:35Z' + fieldData: + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default + price: + value: 2499 + unit: USD + currency: USD response: body: skus: - - id: 580e63fc8c9a982ac9b8b745 + - id: 66072fb71b89448912e2681c cmsLocaleId: 653ad57de882f528b32e810e lastPublished: '2023-03-17T18:47:35Z' lastUpdated: '2023-03-17T18:47:35Z' createdOn: '2023-03-17T18:47:35Z' fieldData: sku-values: - ff42fee0113744f693a764e3431a9cc2: 64a74715c456e36762fc39a1 - name: Blue T-shirt - slug: t-shirt-blue + color: blue + size: small + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default price: - value: 100 + value: 2499 unit: USD + currency: USD quantity: 10 + main-image: https://www.example.com/image.jpg + sku: '1234567890' + sku-properties: + - id: Color + name: Color + enum: + - id: royal-blue + name: Royal Blue + slug: royal-blue update-sku: path: /sites/{site_id}/products/{product_id}/skus/{sku_id} method: PATCH @@ -448,6 +545,7 @@ service: response: docs: Request was successful type: root.Sku + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -462,22 +560,36 @@ service: product_id: 580e63fc8c9a982ac9b8b745 sku_id: 5e8518516e147040726cc415 request: - sku: {} + sku: + id: 66072fb71b89448912e2681c + cmsLocaleId: 653ad57de882f528b32e810e + lastPublished: '2023-03-17T18:47:35Z' + lastUpdated: '2023-03-17T18:47:35Z' + createdOn: '2023-03-17T18:47:35Z' + fieldData: + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default + price: + value: 2499 + unit: USD + currency: USD response: body: - id: 580e63fc8c9a982ac9b8b745 + id: 66072fb71b89448912e2681c cmsLocaleId: 653ad57de882f528b32e810e lastPublished: '2023-03-17T18:47:35Z' lastUpdated: '2023-03-17T18:47:35Z' createdOn: '2023-03-17T18:47:35Z' fieldData: sku-values: - ff42fee0113744f693a764e3431a9cc2: 64a74715c456e36762fc39a1 - name: Blue T-shirt - slug: t-shirt-blue + color: blue + size: small + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default price: - value: 100 + value: 2499 unit: USD + currency: USD compare-at-price: value: 100 unit: USD @@ -490,11 +602,32 @@ service: - {} track-inventory: true quantity: 10 + main-image: https://www.example.com/image.jpg + sku: '1234567890' + sku-properties: + - id: Color + name: Color + enum: + - id: royal-blue + name: Royal Blue + slug: royal-blue source: openapi: ../../../openapi/referenced-specs/v2.yml types: + ProductSkuCreateProduct: + properties: + fieldData: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + ProductSkuCreateSku: + properties: + fieldData: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true ProductsCreateSkuResponse: properties: - skus: optional> + skus: list source: openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/definition/scripts.yml b/.mock/definition/scripts.yml index 8236ed2..a2a7b4b 100644 --- a/.mock/definition/scripts.yml +++ b/.mock/definition/scripts.yml @@ -9,23 +9,13 @@ service: method: GET auth: true docs: > - List of scripts registered to a Site. + Get a list of scripts that have been registered to a site. A site can + have a maximum of 800 registered scripts. - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. - - Additionally, Scripts can be remotely hosted, or registered as inline - snippets. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:read` @@ -39,6 +29,7 @@ service: response: docs: Request was successful type: root.RegisteredScriptList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -55,7 +46,6 @@ service: canCopy: false displayName: Alert hostedLocation: https://cdn.webflow.io/.../alert-0.0.1.js - integrityHash: integrityHash createdOn: '2022-10-26T00:28:54.191Z' lastUpdated: lastUpdated version: 0.0.1 @@ -63,7 +53,6 @@ service: canCopy: false displayName: Alert hostedLocation: https://cdn.webflow.io/.../alert-0.0.2.js - integrityHash: integrityHash createdOn: '2022-10-26T00:28:54.191Z' lastUpdated: lastUpdated version: 0.0.2 @@ -76,29 +65,20 @@ service: createdOn: '2022-10-26T00:28:54.191Z' lastUpdated: lastUpdated version: 1.0.0 + pagination: + limit: 100 + offset: 0 + total: 3 register-hosted: path: /sites/{site_id}/registered_scripts/hosted method: POST auth: true - docs: > - Add a script to a Site's Custom Code registry. - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. - - Additionally, Scripts can be remotely hosted, or registered as inline - snippets. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + docs: | + 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. + Required scope | `custom_code:write` source: @@ -138,6 +118,7 @@ service: response: docs: Request was successful type: root.CustomCodeHostedResponse + status-code: 201 errors: - root.BadRequestError - root.UnauthorizedError @@ -168,21 +149,13 @@ service: method: POST auth: true docs: > - Add a script to a Site's Custom Code registry. Inline scripts can be - between 1 and 2000 characters. - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. + Register an inline script to a site. Inline scripts are limited to 2000 + characters. - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:write` @@ -225,6 +198,7 @@ service: response: docs: Created type: root.CustomCodeInlineResponse + status-code: 201 errors: - root.BadRequestError - root.UnauthorizedError @@ -245,7 +219,6 @@ service: displayName: Alert hostedLocation: >- https://uploads-ssl.webflow.com/6258612d1ee792848f805dcf%2F64b6c769ff52ba6c3d904a91%2F660d6e15b3d1696f2d2b1447%2Falert-0.0.1.js - integrityHash: integrityHash createdOn: '2022-10-26T00:28:54.191Z' lastUpdated: lastUpdated version: 0.0.1 diff --git a/.mock/definition/sites.yml b/.mock/definition/sites.yml index cea8997..602a7dc 100644 --- a/.mock/definition/sites.yml +++ b/.mock/definition/sites.yml @@ -8,8 +8,13 @@ service: path: /workspaces/{workspace_id}/sites method: POST auth: true - docs: | - Create a site. This endpoint requires an Enterprise workspace. + docs: > + Create a site. + + + This endpoint requires an Enterprise + workspace. + Required scope | `workspace:write` source: @@ -36,6 +41,7 @@ service: response: docs: Request was successful type: root.Site + status-code: 201 errors: - root.BadRequestError - root.UnauthorizedError @@ -54,37 +60,15 @@ service: id: 670ecf86817e3cc7a510eb6a workspaceId: 625860a7a6c16d624927122f createdOn: '2024-10-15T20:24:38Z' - displayName: The Hitchiker‘s Guide + displayName: The Hitchiker's Guide shortName: hitchikers-guide - lastPublished: '2016-10-24T19:43:17Z' lastUpdated: '2024-10-15T20:24:38Z' - previewUrl: >- - https://d1otoma47x30pg.cloudfront.net/580e63e98c9a982ac9b8b741/201610241243.png - timeZone: America/Los_Angeles parentFolderId: 670ece123598db72d9648be1 customDomains: - id: 589a331aa51e760df7ccb89d url: test-api-domain.com lastPublished: '2022-12-07T16:51:37Z' - locales: - primary: - id: 653fd9af6a07fc9cfd7a5e57 - cmsLocaleId: 653ad57de882f528b32e810e - enabled: false - displayName: English (United States) - displayImageId: displayImageId - redirect: true - subdirectory: '' - tag: en-US - secondary: - - id: 653fd9af6a07fc9cfd7a5e57 - cmsLocaleId: 653ad57de882f528b32e810e - enabled: false - displayName: English (United States) - redirect: true - subdirectory: '' - tag: en-US - dataCollectionEnabled: false + dataCollectionEnabled: true dataCollectionType: always list: path: /sites @@ -100,6 +84,7 @@ service: response: docs: Request was successful type: root.Sites + status-code: 200 errors: - root.UnauthorizedError - root.NotFoundError @@ -116,7 +101,7 @@ service: lastPublished: '2023-04-02T12:42:00Z' lastUpdated: '2016-10-24T19:43:17Z' previewUrl: >- - https://d1otoma47x30pg.cloudfront.net/42e63e98c9a982ac9b8b741/197910121200.png + https://dev-assets.website-files.com/42e63e98c9a982ac9b8b741/197910121200.png timeZone: DeepSpace/InfiniteImprobability parentFolderId: 1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6 customDomains: @@ -157,9 +142,8 @@ service: lastPublished: '2023-04-02T12:45:00Z' lastUpdated: '2016-10-24T19:43:17Z' previewUrl: >- - https://d1otoma47x30pg.cloudfront.net/42e63e98c9a982ac9b8b742/198110121200.png + https://dev-assets.website-files.com/42e63e98c9a982ac9b8b742/198110121200.png timeZone: DeepSpace/Depression - parentFolderId: 1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6 customDomains: - id: 589a331aa51e760df7ccb89f url: marvin.blog @@ -191,9 +175,8 @@ service: lastPublished: '2023-04-02T12:50:00Z' lastUpdated: '2016-10-24T19:43:17Z' previewUrl: >- - https://d1otoma47x30pg.cloudfront.net/42e63e98c9a982ac9b8b743/198210121200.png + https://dev-assets.website-files.com/42e63e98c9a982ac9b8b743/198210121200.png timeZone: Vogsphere/PoetryHall - parentFolderId: 1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6 customDomains: - id: 589a331aa51e760df7ccb8a0 url: vogonpoetry.galaxy @@ -235,6 +218,7 @@ service: response: docs: Request was successful type: root.Site + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -288,8 +272,13 @@ service: path: /sites/{site_id} method: DELETE auth: true - docs: | - Delete a site. This endpoint requires an Enterprise workspace. + docs: > + Delete a site. + + + This endpoint requires an Enterprise + workspace. + Required scope | `sites:write` source: @@ -313,8 +302,13 @@ service: path: /sites/{site_id} method: PATCH auth: true - docs: | - Update a site. This endpoint requires an Enterprise workspace. + docs: > + Update a site. + + + This endpoint requires an Enterprise + workspace. + Required scope | `sites:write` source: @@ -338,6 +332,7 @@ service: response: docs: Request was successful type: root.Site + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -407,6 +402,7 @@ service: response: docs: Request was successful type: root.Domains + status-code: 200 errors: - root.UnauthorizedError - root.ForbiddenError @@ -430,11 +426,15 @@ service: method: POST auth: true docs: > - Publishes a site to one or more more domains. + Publishes a site to one or more more domains. + + + To publish to a specific custom domain, use the domain IDs from the [Get + Custom Domains](/data/reference/sites/get-custom-domain) endpoint. - This endpoint has a limit of - one successful publish queue per minute. + This endpoint has a + specific rate limit of one successful publish queue per minute. Required scope | `sites:write` @@ -460,6 +460,7 @@ service: response: docs: Request accepted type: SitesPublishResponse + status-code: 202 errors: - root.BadRequestError - root.UnauthorizedError @@ -467,9 +468,14 @@ service: - root.NotFoundError - root.TooManyRequestsError examples: - - path-parameters: + - name: DomainIDs + path-parameters: site_id: 580e63e98c9a982ac9b8b741 - request: {} + request: + customDomains: + - 660c6449dd97ebc7346ac629 + - 660c6449dd97ebc7346ac62f + publishToWebflowSubdomain: false response: body: customDomains: diff --git a/.mock/definition/sites/activityLogs.yml b/.mock/definition/sites/activityLogs.yml index 1468f52..adf24a5 100644 --- a/.mock/definition/sites/activityLogs.yml +++ b/.mock/definition/sites/activityLogs.yml @@ -8,9 +8,15 @@ service: path: /sites/{site_id}/activity_logs method: GET auth: true - docs: >- - Retrieve Activity Logs for a specific Site. Requires Site to be on an - Enterprise plan.

Required scope | `site_activity:read` + docs: > + Retrieve Activity Logs for a specific Site. + + + This endpoint requires an Enterprise + workspace. + + + Required scope: `site_activity:read` source: openapi: ../../../openapi/referenced-specs/v2.yml path-parameters: @@ -32,6 +38,7 @@ service: response: docs: A list of site activity logs type: root.SiteActivityLogResponse + status-code: 200 errors: - root.ForbiddenError - root.NotFoundError @@ -53,10 +60,6 @@ service: displayName: John Doe resourceId: 654c16c7b229e56bcf26870c resourceName: foo-bar - newValue: newValue - previousValue: previousValue - payload: - key: value pagination: limit: 25 offset: 0 diff --git a/.mock/definition/sites/comments.yml b/.mock/definition/sites/comments.yml new file mode 100644 index 0000000..b14a9e5 --- /dev/null +++ b/.mock/definition/sites/comments.yml @@ -0,0 +1,323 @@ +types: + CommentsListCommentThreadsRequestSortBy: + enum: + - createdOn + - lastUpdated + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentsListCommentThreadsRequestSortOrder: + enum: + - asc + - desc + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentsGetCommentThreadRequestSortBy: + enum: + - createdOn + - lastUpdated + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentsGetCommentThreadRequestSortOrder: + enum: + - asc + - desc + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentsListCommentRepliesRequestSortBy: + enum: + - createdOn + - lastUpdated + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentsListCommentRepliesRequestSortOrder: + enum: + - asc + - desc + source: + openapi: ../../../openapi/referenced-specs/v2.yml +imports: + root: ../__package__.yml +service: + auth: false + base-path: '' + endpoints: + list-comment-threads: + path: /sites/{site_id}/comments + method: GET + auth: true + docs: | + List all comment threads for a site. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + + Required scope | `comments:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: List Comment Threads + request: + name: CommentsListCommentThreadsRequest + query-parameters: + localeId: + type: optional + docs: >- + Unique identifier for a specific locale. Applicable, when using + localization. + offset: + type: optional + docs: >- + Offset used for pagination if the results have more than limit + records + limit: + type: optional + docs: 'Maximum number of records to be returned (max limit: 100)' + sortBy: + type: optional + docs: >- + Sort results by the provided value. Only allowed when sortOrder is + provided. + sortOrder: + type: optional + docs: Sorts the results by asc or desc + response: + docs: Request was successful + type: root.CommentThreadList + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + query-parameters: + localeId: 65427cf400e02b306eaa04a0 + response: + body: + comments: + - id: 679d2ddb5196117ad04d1ffa + siteId: 679826b3b20b045e176bc4b5 + pageId: 679826b3b20b045e176bc4bc + localeId: 67993753d910db250db64b3e + breakpoint: main + url: >- + https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc + content: 'Let''s go to the pub! [[6287ec36a841b25637c663df]] ' + isResolved: false + author: + userId: 6287ec36a841b25637c663df + email: ford.prefect@heartofgold.spaceship + name: Ford Prefect + mentionedUsers: + - userId: 6287ec36a841b25637c663df + email: arthur.dent@heartofgold.spaceship + name: Arthur Dent + createdOn: '2025-01-31T20:08:59.759Z' + lastUpdated: '2025-01-31T20:08:59.759Z' + - id: 679d2ddb5196117ad04d1ffc + siteId: 679826b3b20b045e176bc4b5 + pageId: 679826b3b20b045e176bc4bc + localeId: 67993753d910db250db64b3e + breakpoint: main + url: >- + https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc + content: >- + You have five minutes left to drink it + [[6287ec36a841b25637c663df]] + isResolved: false + author: + userId: 6287ec36a841b25637c663df + email: ford.prefect@heartofgold.spaceship + name: Ford Prefect + mentionedUsers: + - userId: 6287ec36a841b25637c663df + email: arthur.dent@heartofgold.spaceship + name: Arthur Dent + createdOn: '2025-01-31T20:08:59.759Z' + lastUpdated: '2025-01-31T20:08:59.759Z' + pagination: + limit: 2 + offset: 0 + total: 2 + get-comment-thread: + path: /sites/{site_id}/comments/{comment_thread_id} + method: GET + auth: true + docs: | + Get details of a specific comment thread. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + + Required scope | `comments:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + comment_thread_id: + type: string + docs: Unique identifier for a Comment Thread + display-name: Get Comment Thread + request: + name: CommentsGetCommentThreadRequest + query-parameters: + localeId: + type: optional + docs: >- + Unique identifier for a specific locale. Applicable, when using + localization. + offset: + type: optional + docs: >- + Offset used for pagination if the results have more than limit + records + limit: + type: optional + docs: 'Maximum number of records to be returned (max limit: 100)' + sortBy: + type: optional + docs: >- + Sort results by the provided value. Only allowed when sortOrder is + provided. + sortOrder: + type: optional + docs: Sorts the results by asc or desc + response: + docs: Request was successful + type: root.CommentThread + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + comment_thread_id: 580e63e98c9a982ac9b8b741 + query-parameters: + localeId: 65427cf400e02b306eaa04a0 + response: + body: + id: 580e64008c9a982ac9b8b754 + siteId: 580e64008c9a982ac9b8b754 + pageId: 580e64008c9a982ac9b8b754 + localeId: 580e64008c9a982ac9b8b754 + itemId: 580e64008c9a982ac9b8b754 + breakpoint: main + url: >- + https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc + content: This is a comment reply + isResolved: true + author: + userId: userId + email: email + name: name + mentionedUsers: + - userId: 6287ec36a841b25637c663df + email: arthur.dent@heartofgold.spaceship + name: Arthur Dent + createdOn: '2023-03-17T18:47:35.560Z' + lastUpdated: '2023-03-17T18:47:35.560Z' + list-comment-replies: + path: /sites/{site_id}/comments/{comment_thread_id}/replies + method: GET + auth: true + docs: | + List all replies to a specific comment thread. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + + Required scope | `comments:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + comment_thread_id: + type: string + docs: Unique identifier for a Comment Thread + display-name: List Comment Replies + request: + name: CommentsListCommentRepliesRequest + query-parameters: + localeId: + type: optional + docs: >- + Unique identifier for a specific locale. Applicable, when using + localization. + offset: + type: optional + docs: >- + Offset used for pagination if the results have more than limit + records + limit: + type: optional + docs: 'Maximum number of records to be returned (max limit: 100)' + sortBy: + type: optional + docs: >- + Sort results by the provided value. Only allowed when sortOrder is + provided. + sortOrder: + type: optional + docs: Sorts the results by asc or desc + response: + docs: Request was successful + type: root.CommentReplyList + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + comment_thread_id: 580e63e98c9a982ac9b8b741 + query-parameters: + localeId: 65427cf400e02b306eaa04a0 + response: + body: + comments: + - id: 679d2ddb5196117ad04d1ffa + commentId: 679d2ddb5196117ad04d1ff8 + siteId: 679826b3b20b045e176bc4b5 + pageId: 679826b3b20b045e176bc4bc + localeId: 67993753d910db250db64b3e + breakpoint: main + content: >- + This comment mentions another user + [[6287ec36a841b25637c663df]] + isResolved: false + author: + id: id + email: email + name: name + mentionedUsers: + - id: id + email: arthur.dent@example.com + name: Arthur Dent + lastUpdated: '2025-01-31T20:08:59.759Z' + createdOn: '2025-01-31T20:08:59.759Z' + pagination: + limit: 2 + offset: 0 + total: 1 + source: + openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/definition/sites/plans.yml b/.mock/definition/sites/plans.yml index ae9de6d..f507373 100644 --- a/.mock/definition/sites/plans.yml +++ b/.mock/definition/sites/plans.yml @@ -8,9 +8,14 @@ service: path: /sites/{site_id}/plan method: GET auth: true - docs: | + docs: > Get site plan details for the specified Site. + + This endpoint requires an Enterprise + workspace. + + Required scope | `sites:read` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -22,6 +27,7 @@ service: response: docs: Request was successful type: root.SitePlan + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/sites/redirects.yml b/.mock/definition/sites/redirects.yml index b104d86..746923b 100644 --- a/.mock/definition/sites/redirects.yml +++ b/.mock/definition/sites/redirects.yml @@ -9,13 +9,16 @@ service: method: GET auth: true docs: > - Fetch a list of all URL redirect rules configured for a specific site. + 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. + This endpoint requires an Enterprise + workspace. + Required scope: `sites:read` source: @@ -24,10 +27,11 @@ service: site_id: type: string docs: Unique identifier for a Site - display-name: Get URL redirects + display-name: Get 301 redirects response: docs: Request was successful type: root.Redirects + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -55,7 +59,7 @@ service: method: POST auth: true docs: > - Add a new URL redirection rule to a site. + Add a new 301 redirection rule to a site. This endpoint allows you to define a source path (`fromUrl`) and its @@ -64,6 +68,10 @@ service: restructuring URLs, or handling outdated links. + This endpoint requires an Enterprise + workspace. + + Required scope: `sites:write` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -71,13 +79,14 @@ service: site_id: type: string docs: Unique identifier for a Site - display-name: Create a URL redirect + display-name: Create a 301 redirect request: body: root.Redirect content-type: application/json response: docs: Request was successful type: root.Redirect + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -101,12 +110,18 @@ service: method: DELETE auth: true docs: > - Remove a URL redirection rule from a site. + 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. + + This endpoint requires an Enterprise + workspace. + + Required scope: `sites:write` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -117,10 +132,11 @@ service: redirect_id: type: string docs: Unique identifier site rediect - display-name: Delete URL redirects + display-name: Delete 301 redirects response: docs: Request was successful type: root.Redirects + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -148,8 +164,14 @@ service: path: /sites/{site_id}/redirects/{redirect_id} method: PATCH auth: true - docs: | - Update a URL redirection rule from a site. + docs: > + Update a 301 redirection rule from a site. + + + This endpoint requires an Enterprise + workspace. + + Required scope: `sites:write` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -160,13 +182,14 @@ service: redirect_id: type: string docs: Unique identifier site rediect - display-name: Update URL redirect + display-name: Update 301 redirect request: body: root.Redirect content-type: application/json response: docs: Request was successful type: root.Redirect + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/sites/robotsTxt.yml b/.mock/definition/sites/robotsTxt.yml new file mode 100644 index 0000000..1259a14 --- /dev/null +++ b/.mock/definition/sites/robotsTxt.yml @@ -0,0 +1,221 @@ +imports: + root: ../__package__.yml +service: + auth: false + base-path: '' + endpoints: + get: + path: /sites/{site_id}/robots_txt + method: GET + auth: true + docs: > + Retrieve the robots.txt configuration for various user agents. + + + This endpoint requires an Enterprise + workspace. + + + Required scope: `site_config:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Get robots.txt + response: + docs: Request was successful + type: root.Robots + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + response: + body: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + put: + path: /sites/{site_id}/robots_txt + method: PUT + auth: true + docs: > + Replace the `robots.txt` configuration for various user agents. + + + This endpoint requires an Enterprise + workspace. + + + Required scope | `site_config:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Replace robots.txt + request: + body: root.Robots + content-type: application/json + response: + docs: Request was successful + type: root.Robots + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + request: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + response: + body: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + delete: + path: /sites/{site_id}/robots_txt + method: DELETE + auth: true + docs: > + 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: `site_config:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Delete robots.txt + request: + body: root.Robots + content-type: application/json + response: + docs: Request was successful + type: root.Robots + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + request: + rules: + - userAgent: '*' + allows: + - /public + disallows: + - /bubbles + response: + body: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + patch: + path: /sites/{site_id}/robots_txt + method: PATCH + auth: true + docs: > + Update the `robots.txt` configuration for various user agents. + + + This endpoint requires an Enterprise + workspace. + + + Required scope | `site_config:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Update robots.txt + request: + body: root.Robots + content-type: application/json + response: + docs: Request was successful + type: root.Robots + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + request: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + response: + body: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + source: + openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/definition/sites/scripts.yml b/.mock/definition/sites/scripts.yml index 92ad0e4..647e1ec 100644 --- a/.mock/definition/sites/scripts.yml +++ b/.mock/definition/sites/scripts.yml @@ -8,13 +8,12 @@ service: path: /sites/{site_id}/custom_code method: GET auth: true - docs: > - Get all registered scripts that have been applied to a specific Site. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + docs: | + 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. + Required scope | `custom_code:read` source: @@ -27,6 +26,7 @@ service: response: docs: Request was successful type: root.ScriptApplyList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -55,22 +55,12 @@ service: path: /sites/{site_id}/custom_code method: PUT auth: true - docs: > - Add a registered script to a Site. - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + docs: | + Apply registered scripts 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. + Required scope | `custom_code:write` source: @@ -86,6 +76,7 @@ service: response: docs: Request was successful type: root.ScriptApplyList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -125,11 +116,8 @@ service: method: DELETE auth: true docs: > - Delete the custom code block that an app created for a Site - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + Remove scripts from a site applied by the App. This endpoint will not + remove scripts from the site's registered scripts. Required scope | `custom_code:write` @@ -154,11 +142,15 @@ service: method: GET auth: true docs: > - Get all instances of Custom Code applied to a Site or Pages. + Get a list of scripts that have been applied to a site and/or individual + pages. - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:read` @@ -183,6 +175,7 @@ service: response: docs: Request was successful type: root.ListCustomCodeBlocks + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -196,7 +189,6 @@ service: body: blocks: - siteId: 6258612d1ee792848f805dcf - pageId: pageId type: site scripts: - id: chartjs diff --git a/.mock/definition/sites/wellKnown.yml b/.mock/definition/sites/wellKnown.yml new file mode 100644 index 0000000..0ba91e1 --- /dev/null +++ b/.mock/definition/sites/wellKnown.yml @@ -0,0 +1,114 @@ +types: + WellKnownFileContentType: + enum: + - value: application/json + name: ApplicationJson + - value: text/plain + name: TextPlain + docs: The content type of the file. Defaults to application/json + default: application/json + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml +imports: + root: ../__package__.yml +service: + auth: false + base-path: '' + endpoints: + put: + path: /sites/{site_id}/well_known + method: PUT + auth: true + docs: > + 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:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Set a well-known file + request: + name: WellKnownFile + body: + properties: + fileName: + type: string + docs: The name of the file + fileData: + type: string + docs: The contents of the file + contentType: + type: optional + docs: The content type of the file. Defaults to application/json + default: application/json + content-type: application/json + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + request: + fileName: fileName + fileData: fileData + delete: + path: /sites/{site_id}/well_known + method: DELETE + auth: true + docs: > + Delete existing well-known files from a site. + + + This endpoint requires an Enterprise + workspace. + + + Required scope: `site_config:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Delete a well-known file + request: + name: WellKnownDeleteRequest + body: + properties: + fileNames: + type: optional> + docs: A list of file names to delete + content-type: application/json + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + request: {} + source: + openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/definition/token.yml b/.mock/definition/token.yml index 033c5c3..4b1cc1a 100644 --- a/.mock/definition/token.yml +++ b/.mock/definition/token.yml @@ -18,6 +18,7 @@ service: response: docs: Request was successful type: root.AuthorizedUser + status-code: 200 errors: - root.UnauthorizedError - root.ForbiddenError @@ -44,6 +45,7 @@ service: response: docs: Request was successful type: root.Authorization + status-code: 200 errors: - root.UnauthorizedError examples: diff --git a/.mock/definition/users.yml b/.mock/definition/users.yml index 19a17cc..97e5801 100644 --- a/.mock/definition/users.yml +++ b/.mock/definition/users.yml @@ -33,23 +33,6 @@ types: docs: Sorts users in descending order based on their update date source: openapi: ../../../openapi/referenced-specs/v2.yml - UsersUpdateRequestData: - properties: - name: - type: optional - docs: | - The name of the user - accept-privacy: - type: optional - docs: | - Boolean indicating if the user has accepted the privacy policy - accept-communications: - type: optional - docs: | - Boolean indicating if the user has accepted to receive communications - source: - openapi: ../../../openapi/referenced-specs/v2.yml - inline: true imports: root: __package__.yml service: @@ -93,6 +76,7 @@ service: response: docs: Request was successful type: root.UserList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -181,6 +165,7 @@ service: response: docs: Request was successful type: root.User + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -262,20 +247,12 @@ service: docs: Unique identifier for a User display-name: Update User request: - name: UsersUpdateRequest - body: - properties: - data: optional - accessGroups: - type: optional> - docs: > - An array of access group slugs. Access groups are assigned to - the user as type `admin` and the user remains in the group until - removed. + body: root.User content-type: application/json response: docs: Request was successful type: root.User + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -288,14 +265,16 @@ service: site_id: 580e63e98c9a982ac9b8b741 user_id: 580e63e98c9a982ac9b8b741 request: - data: - name: Some One - accept-privacy: false - accept-communications: false + id: 6287ec36a841b25637c663df + isEmailVerified: true + lastUpdated: '2022-05-20T13:46:12Z' + invitedOn: '2022-05-20T13:46:12Z' + createdOn: '2022-05-20T13:46:12Z' + lastLogin: '2022-05-20T13:46:12Z' + status: verified accessGroups: - - webflowers - - platinum - - free-tier + - slug: webflowers + type: admin response: body: id: 6287ec36a841b25637c663df @@ -354,6 +333,7 @@ service: response: docs: Request was successful type: root.User + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -368,7 +348,7 @@ service: request: email: some.one@home.com accessGroups: - - webflowers + - accessGroups response: body: id: 6287ec36a841b25637c663df diff --git a/.mock/definition/webhooks.yml b/.mock/definition/webhooks.yml index d40e3e4..47dbfc0 100644 --- a/.mock/definition/webhooks.yml +++ b/.mock/definition/webhooks.yml @@ -22,6 +22,7 @@ service: response: docs: Request was successful type: root.WebhookList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -33,10 +34,6 @@ service: site_id: 580e63e98c9a982ac9b8b741 response: body: - pagination: - limit: 100 - offset: 0 - total: 100 webhooks: - id: 57ca0a9e418c504a6e1acbb6 triggerType: form_submission @@ -65,6 +62,10 @@ service: name: Email Form lastTriggered: '2023-02-08T23:59:28Z' createdOn: '2016-07-19T01:43:40Z' + pagination: + limit: 100 + offset: 0 + total: 100 create: path: /sites/{site_id}/webhooks method: POST @@ -93,6 +94,7 @@ service: response: docs: Request was successful type: root.Webhook + status-code: 201 errors: - root.BadRequestError - root.UnauthorizedError @@ -117,8 +119,6 @@ service: url: https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f workspaceId: 4f4e46fd476ea8c507000001 siteId: 562ac0395358780a1f5e6fbd - filter: - name: My Form lastTriggered: '2023-02-08T23:59:28Z' createdOn: '2022-11-08T23:59:28Z' get: @@ -139,6 +139,7 @@ service: response: docs: Request was successful type: root.Webhook + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -155,8 +156,6 @@ service: url: https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f workspaceId: 4f4e46fd476ea8c507000001 siteId: 562ac0395358780a1f5e6fbd - filter: - name: My Form lastTriggered: '2023-02-08T23:59:28Z' createdOn: '2022-11-08T23:59:28Z' delete: diff --git a/.mock/definition/workspaces/auditLogs.yml b/.mock/definition/workspaces/auditLogs.yml new file mode 100644 index 0000000..73ae4df --- /dev/null +++ b/.mock/definition/workspaces/auditLogs.yml @@ -0,0 +1,119 @@ +types: + AuditLogsGetWorkspaceAuditLogsRequestSortOrder: + enum: + - asc + - desc + source: + openapi: ../../../openapi/referenced-specs/v2.yml + AuditLogsGetWorkspaceAuditLogsRequestEventType: + enum: + - user_access + - custom_role + - workspace_membership + - site_membership + - workspace_invitation + source: + openapi: ../../../openapi/referenced-specs/v2.yml +imports: + root: ../__package__.yml +service: + auth: false + base-path: '' + endpoints: + get-workspace-audit_logs: + path: /workspaces/{workspace_id_or_slug}/audit_logs + method: GET + auth: true + docs: > + Get audit logs for a workspace. + + + This endpoint + requires an Enterprise workspace and a workspace token with the + `workspace_activity:read` scope. Create a workspace token from your + workspace dashboard integrations page to use this endpoint. + + + Required scope | `workspace_activity:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + workspace_id_or_slug: + type: string + docs: Unique identifier or slug for a Workspace + display-name: Get Workspace Audit Logs + request: + name: AuditLogsGetWorkspaceAuditLogsRequest + query-parameters: + limit: + type: optional + docs: 'Maximum number of records to be returned (max limit: 100)' + offset: + type: optional + docs: >- + Offset used for pagination if the results have more than limit + records + sortOrder: + type: optional + docs: Sorts the results by asc or desc + eventType: + type: optional + docs: The event type to filter by + from: + type: optional + docs: The start date to filter by + to: + type: optional + docs: The end date to filter by + response: + docs: A list of workspace audit logs + type: root.WorkspaceAuditLogResponse + status-code: 200 + errors: + - root.UnauthorizedError + - root.ForbiddenError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + workspace_id_or_slug: hitchhikers-workspace + query-parameters: + from: '2024-04-22T16:00:31Z' + to: '2024-04-22T16:00:31Z' + response: + body: + items: + - eventSubType: login + eventType: user_access + timestamp: '2025-04-29T20:30:06Z' + actor: + id: 6661ccb359b561c69f29d554 + email: someone@email.com + workspace: + id: 6621ccb459b561c69f29d57c + slug: hitchhikers-workspace + - eventSubType: user_added + eventType: workspace_membership + timestamp: '2025-04-30T20:30:06Z' + actor: + id: 60492e55bbddce079561cd7a + email: someone@webflow.com + workspace: + id: 6621ccb459b561c69f29d57c + slug: hitchhikers-workspace + - eventSubType: user_added + eventType: site_membership + timestamp: '2025-04-30T00:33:31Z' + actor: + id: 671fe00d185fc8c1ad409d37 + email: someone@webflow.com + workspace: + id: 6621ccb459b561c69f29d57c + slug: hitchhikers-workspace + pagination: + limit: 10 + offset: 0 + total: 3 + source: + openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/fern.config.json b/.mock/fern.config.json index 8b3316e..f539017 100644 --- a/.mock/fern.config.json +++ b/.mock/fern.config.json @@ -1,4 +1,4 @@ { "organization" : "webflow", - "version" : "0.46.19" + "version" : "0.64.12" } \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index a563308..1318539 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,13 +38,13 @@ trio = ["trio (>=0.26.1)"] [[package]] name = "certifi" -version = "2024.12.14" +version = "2025.7.14" description = "Python package for providing Mozilla's CA Bundle." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, - {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, + {file = "certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2"}, + {file = "certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995"}, ] [[package]] @@ -60,43 +60,46 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.2.2" +version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + [package.extras] test = ["pytest (>=6)"] [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] [[package]] name = "httpcore" -version = "1.0.7" +version = "1.0.9" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, - {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, ] [package.dependencies] certifi = "*" -h11 = ">=0.13,<0.15" +h11 = ">=0.16" [package.extras] asyncio = ["anyio (>=4.0,<5.0)"] @@ -144,13 +147,13 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2 [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] @@ -201,24 +204,24 @@ reports = ["lxml"] [[package]] name = "mypy-extensions" -version = "1.0.0" +version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, ] [[package]] name = "packaging" -version = "24.2" +version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] [[package]] @@ -238,13 +241,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pydantic" -version = "2.10.5" +version = "2.10.6" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, - {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, + {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, + {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, ] [package.dependencies] @@ -525,13 +528,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.12.2" +version = "4.13.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, + {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] [metadata] diff --git a/pyproject.toml b/pyproject.toml index 749aa8e..66a8846 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "webflow" -version = "2.0.0b1" +version = "1.2.1" description = "" readme = "README.md" authors = [] diff --git a/reference.md b/reference.md index 5001bba..9d934bd 100644 --- a/reference.md +++ b/reference.md @@ -137,7 +137,9 @@ client.token.introspect()
-Create a site. This endpoint requires an Enterprise workspace. +Create a site. + +This endpoint requires an Enterprise workspace. Required scope | `workspace:write`
@@ -368,7 +370,9 @@ client.sites.get(
-Delete a site. This endpoint requires an Enterprise workspace. +Delete a site. + +This endpoint requires an Enterprise workspace. Required scope | `sites:write`
@@ -440,7 +444,9 @@ client.sites.delete(
-Update a site. This endpoint requires an Enterprise workspace. +Update a site. + +This endpoint requires an Enterprise workspace. Required scope | `sites:write`
@@ -600,9 +606,11 @@ client.sites.get_custom_domain(
-Publishes a site to one or more more domains. +Publishes a site to one or more more domains. + +To publish to a specific custom domain, use the domain IDs from the [Get Custom Domains](/data/reference/sites/get-custom-domain) endpoint. -This endpoint has a limit of one successful publish queue per minute. +This endpoint has a specific rate limit of one successful publish queue per minute. Required scope | `sites:write`
@@ -626,6 +634,8 @@ client = Webflow( ) client.sites.publish( site_id="580e63e98c9a982ac9b8b741", + custom_domains=["660c6449dd97ebc7346ac629", "660c6449dd97ebc7346ac62f"], + publish_to_webflow_subdomain=False, ) ``` @@ -763,7 +773,9 @@ client.collections.list(
-Create a Collection for a site. +Create a Collection for a site with collection fields. + +Each collection includes the required _name_ and _slug_ fields, which are generated automatically. You can update the `displayName` of these fields, but the slug for them cannot be changed. Fields slugs are automatically converted to lowercase. Spaces in slugs are replaced with hyphens. Required scope | `cms:write`
@@ -780,7 +792,7 @@ Required scope | `cms:write`
```python -from webflow import Webflow +from webflow import ReferenceField, ReferenceFieldMetadata, StaticField, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -790,6 +802,29 @@ client.collections.create( display_name="Blog Posts", singular_name="Blog Post", slug="posts", + fields=[ + StaticField( + is_required=True, + type="PlainText", + display_name="Title", + help_text="The title of the blog post", + ), + StaticField( + is_required=True, + type="RichText", + display_name="Content", + help_text="The content of the blog post", + ), + ReferenceField( + is_required=True, + type="Reference", + display_name="Author", + help_text="The author of the blog post", + metadata=ReferenceFieldMetadata( + collection_id="23cc2d952d4e4631ffd4345d2743db4e", + ), + ), + ], ) ``` @@ -838,6 +873,14 @@ client.collections.create(
+**fields:** `typing.Optional[typing.Sequence[FieldCreate]]` — An array of custom fields to add to the collection + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -1187,6 +1230,10 @@ client.pages.get_metadata( Update Page-level metadata, including SEO and Open Graph fields. + + Note: When updating Page Metadata in secondary locales, you may only add `slug` to the request if your Site has the [Advanced or Enterprise Localization](https://webflow.com/localization) add-on. + + Required scope | `pages:write`
@@ -1262,7 +1309,7 @@ client.pages.update_page_settings(
-**id:** `str` — Unique identifier for the Page +**locale_id:** `typing.Optional[str]` — Unique identifier for a specific locale. Applicable, when using localization.
@@ -1270,7 +1317,7 @@ client.pages.update_page_settings(
-**locale_id:** `typing.Optional[str]` — Unique identifier for a specific locale. Applicable, when using localization. +**id:** `typing.Optional[str]` — Unique identifier for the Page
@@ -1366,14 +1413,6 @@ client.pages.update_page_settings(
-**is_members_only:** `typing.Optional[bool]` — Indicates whether the Page is restricted by [Memberships Controls](https://university.webflow.com/lesson/webflow-memberships-overview#how-to-manage-page-restrictions) - -
-
- -
-
- **seo:** `typing.Optional[PageSeo]` — SEO-related fields for the Page
@@ -1430,10 +1469,11 @@ client.pages.update_page_settings(
-Get static content from a static page. This includes text nodes, image nodes and component instances. -To retrieve the contents of components in the page use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint. +Get content from a static page. This includes text nodes, image nodes, select nodes, text input nodes, submit button nodes, and component instances with [property overrides](https://help.webflow.com/hc/en-us/articles/33961219350547-Component-properties#how-to-modify-property-values-on-component-instances). -If you do not provide a Locale ID in your request, the response will return any content that can be localized from the Primary locale. +To retrieve the static content of a component instance, use the [Get Component Content](/data/reference/pages-and-components/components/get-content) endpoint. + +If you do not include a `localeId` in your request, the response will return any content that can be localized from the Primary locale. Required scope | `pages:read`
@@ -1556,9 +1596,13 @@ Required scope | `pages:write` ```python from webflow import ( - ComponentInstanceNodePropertyOverridesWrite, + ComponentInstance, ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem, - TextNodeWrite, + Select, + SelectNodeWriteChoicesItem, + SubmitButton, + TextInput, + TextNode, Webflow, ) @@ -1569,15 +1613,37 @@ client.pages.update_static_content( page_id="63c720f9347c2139b248e552", locale_id="localeId", nodes=[ - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623", text="

The Hitchhiker's Guide to the Galaxy

", ), - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627", text="

Don't Panic!

Always know where your towel is.

", ), - ComponentInstanceNodePropertyOverridesWrite( + Select( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635", + choices=[ + SelectNodeWriteChoicesItem( + value="choice-1", + text="First choice", + ), + SelectNodeWriteChoicesItem( + value="choice-2", + text="Second choice", + ), + ], + ), + TextInput( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642", + placeholder="Enter something here...", + ), + SubmitButton( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671", + value="Submit", + waiting_text="Submitting...", + ), + ComponentInstance( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629", property_overrides=[ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem( @@ -1744,7 +1810,7 @@ client.components.list(
-Get static content from a component definition. This includes text nodes, image nodes and nested component instances. +Get static content from a component definition. This includes text nodes, image nodes, select nodes, text input nodes, submit button nodes, and nested component instances. To retrieve dynamic content set by component properties, use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint. If you do not provide a Locale ID in your request, the response will return any content that can be localized from the Primary locale. @@ -1879,9 +1945,13 @@ Required scope | `components:write` ```python from webflow import ( - ComponentInstanceNodePropertyOverridesWrite, + ComponentInstance, ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem, - TextNodeWrite, + Select, + SelectNodeWriteChoicesItem, + SubmitButton, + TextInput, + TextNode, Webflow, ) @@ -1893,15 +1963,37 @@ client.components.update_content( component_id="8505ba55-ef72-629e-f85c-33e4b703d48b", locale_id="65427cf400e02b306eaa04a0", nodes=[ - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623", text="

The Hitchhiker's Guide to the Galaxy

", ), - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627", text="

Don't Panic!

Always know where your towel is.

", ), - ComponentInstanceNodePropertyOverridesWrite( + Select( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635", + choices=[ + SelectNodeWriteChoicesItem( + value="choice-1", + text="First choice", + ), + SelectNodeWriteChoicesItem( + value="choice-2", + text="Second choice", + ), + ], + ), + TextInput( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642", + placeholder="Enter something here...", + ), + SubmitButton( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671", + value="Submit", + waiting_text="Submitting...", + ), + ComponentInstance( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629", property_overrides=[ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem( @@ -1987,9 +2079,9 @@ client.components.update_content(
-Get the property default values of a component definition. +Get the default property values of a component definition. -If you do not provide a Locale ID in your request, the response will return any properties that can be localized from the Primary locale. +If you do not include a `localeId` in your request, the response will return any properties that can be localized from the Primary locale. Required scope | `components:read`
@@ -2095,12 +2187,11 @@ client.components.get_properties(
-Update the property default values of a component definition in a specificed locale. +Update the default property values of a component definition in a specificed locale. -Before making updates: -1. Use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify available properties +Before making updates, use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify properties that can be updated in a secondary locale. -The request requires a secondary locale ID. If a locale is missing, the request will not be processed and will result in an error. +The request requires a secondary locale ID. If a `localeId` is missing, the request will not be processed and will result in an error. Required scope | `components:write`
@@ -2210,14 +2301,11 @@ client.components.update_properties(
-List of scripts registered to a Site. - -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. -Additionally, Scripts can be remotely hosted, or registered as inline snippets. +Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts. -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:read`
@@ -2289,14 +2377,11 @@ client.scripts.list(
-Add a script to a Site's Custom Code registry. - -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. -Additionally, Scripts can be remotely hosted, or registered as inline snippets. +Register a hosted script to a site. -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:write`
@@ -2412,13 +2497,11 @@ client.scripts.register_hosted(
-Add a script to a Site's Custom Code registry. Inline scripts can be between 1 and 2000 characters. - -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. +Register an inline script to a site. Inline scripts are limited to 2000 characters. -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:write`
@@ -2534,7 +2617,7 @@ client.scripts.register_inline(
-List assets for a given site +List of assets uploaded to a site Required scope | `assets:read`
@@ -2606,15 +2689,18 @@ client.assets.list(
-Create a new asset entry. +The first step in uploading an asset to a site. -This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`. -You can use these two properties to [upload the file to Amazon s3 by making a POST](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) -request to the `uploadUrl` with the `uploadDetails` object as your header information in the request. +This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`. - -Required scope | `assets:write` + +Use these properties in the header of a [POST request to Amazson s3](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) to complete the upload. + + +To learn more about how to upload assets to Webflow, see our [assets guide](/data/docs/working-with-assets). + + Required scope | `assets:write`
@@ -2710,7 +2796,7 @@ client.assets.create(
-Get an Asset +Get details about an asset Required scope | `assets:read`
@@ -2854,7 +2940,7 @@ client.assets.delete(
-Update an Asset +Update details of an Asset. Required scope | `assets:write`
@@ -3707,6 +3793,12 @@ 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. + + 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`
@@ -3853,7 +3945,7 @@ client.forms.get_submission(
-
client.forms.update_submission(...) +
client.forms.delete_submission(...)
@@ -3865,7 +3957,8 @@ client.forms.get_submission(
-Update hidden fields on a form submission +Delete a form submission + Required scope | `forms:write`
@@ -3887,7 +3980,7 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.forms.update_submission( +client.forms.delete_submission( form_submission_id="580e63e98c9a982ac9b8b741", ) @@ -3913,14 +4006,6 @@ client.forms.update_submission(
-**form_submission_data:** `typing.Optional[typing.Dict[str, typing.Optional[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.
@@ -3933,8 +4018,7 @@ client.forms.update_submission(
-## Users -
client.users.list(...) +
client.forms.update_submission(...)
@@ -3946,9 +4030,9 @@ client.forms.update_submission(
-Get a list of users for a site +Update hidden fields on a form submission -Required scope | `users:read` +Required scope | `forms:write`
@@ -3968,8 +4052,8 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.users.list( - site_id="580e63e98c9a982ac9b8b741", +client.forms.update_submission( + form_submission_id="580e63e98c9a982ac9b8b741", ) ``` @@ -3986,23 +4070,7 @@ client.users.list(
-**site_id:** `str` — Unique identifier for a Site - -
-
- -
-
- -**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records - -
-
- -
-
- -**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) +**form_submission_id:** `str` — Unique identifier for a Form Submission
@@ -4010,13 +4078,7 @@ client.users.list(
-**sort:** `typing.Optional[UsersListRequestSort]` - -Sort string to use when ordering users - -Example(`CreatedOn`, `Email`, `Status`, `LastLogin`, `UpdatedOn`). - -Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`) +**form_submission_data:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — An existing **hidden field** defined on the form schema, and the corresponding value to set
@@ -4036,7 +4098,7 @@ Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`)
-
client.users.get(...) +
client.forms.list_submissions_by_site(...)
@@ -4048,9 +4110,11 @@ Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`)
-Get a User by ID +List form submissions for a given site. This endpoint differs from the existing [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) by accepting `siteId` as a path parameter and `elementId` as a query parameter. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list). -Required scope | `users:read` + + +Required scope | `forms:read`
@@ -4070,9 +4134,9 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.users.get( +client.forms.list_submissions_by_site( site_id="580e63e98c9a982ac9b8b741", - user_id="580e63e98c9a982ac9b8b741", + element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0", ) ``` @@ -4097,7 +4161,23 @@ client.users.get(
-**user_id:** `str` — Unique identifier for a User +**element_id:** `typing.Optional[str]` — Identifier for an element + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100)
@@ -4117,7 +4197,8 @@ client.users.get(
-
client.users.delete(...) +## Users +
client.users.list(...)
@@ -4129,9 +4210,9 @@ client.users.get(
-Delete a User by ID +Get a list of users for a site -Required scope | `users:write` +Required scope | `users:read`
@@ -4151,9 +4232,8 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.users.delete( +client.users.list( site_id="580e63e98c9a982ac9b8b741", - user_id="580e63e98c9a982ac9b8b741", ) ``` @@ -4178,7 +4258,29 @@ client.users.delete(
-**user_id:** `str` — Unique identifier for a User +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**sort:** `typing.Optional[UsersListRequestSort]` + +Sort string to use when ordering users + +Example(`CreatedOn`, `Email`, `Status`, `LastLogin`, `UpdatedOn`). + +Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`)
@@ -4198,7 +4300,7 @@ client.users.delete(
-
client.users.update(...) +
client.users.get(...)
@@ -4210,12 +4312,9 @@ client.users.delete(
-Update a User by ID - - Required scope | `users:write` +Get a User by ID -The email and password -fields cannot be updated using this endpoint +Required scope | `users:read`
@@ -4231,20 +4330,13 @@ fields cannot be updated using this endpoint ```python from webflow import Webflow -from webflow.resources.users import UsersUpdateRequestData client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.users.update( +client.users.get( site_id="580e63e98c9a982ac9b8b741", user_id="580e63e98c9a982ac9b8b741", - data=UsersUpdateRequestData( - name="Some One", - accept_privacy=False, - accept_communications=False, - ), - access_groups=["webflowers", "platinum", "free-tier"], ) ``` @@ -4271,23 +4363,6 @@ client.users.update( **user_id:** `str` — Unique identifier for a User - -
- -
-
- -**data:** `typing.Optional[UsersUpdateRequestData]` - -
-
- -
-
- -**access_groups:** `typing.Optional[typing.Sequence[str]]` — An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. - -
@@ -4306,7 +4381,7 @@ client.users.update(
-
client.users.invite(...) +
client.users.delete(...)
@@ -4318,9 +4393,7 @@ client.users.update(
-Create and invite a user with an email address. - -The user will be sent and invite via email, which they will need to accept in order to join paid any paid access group. +Delete a User by ID Required scope | `users:write`
@@ -4342,10 +4415,9 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.users.invite( +client.users.delete( site_id="580e63e98c9a982ac9b8b741", - email="some.one@home.com", - access_groups=["webflowers"], + user_id="580e63e98c9a982ac9b8b741", ) ``` @@ -4370,16 +4442,7 @@ client.users.invite(
-**email:** `str` — Email address of user to send invite to - -
-
- -
-
- -**access_groups:** `typing.Optional[typing.Sequence[str]]` — An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. - +**user_id:** `str` — Unique identifier for a User
@@ -4399,8 +4462,7 @@ client.users.invite(
-## AccessGroups -
client.access_groups.list(...) +
client.users.update(...)
@@ -4412,9 +4474,12 @@ client.users.invite(
-Get a list of access groups for a site +Update a User by ID -Required scope | `users:read` + Required scope | `users:write` + +The email and password +fields cannot be updated using this endpoint
@@ -4429,13 +4494,37 @@ Required scope | `users:read`
```python -from webflow import Webflow +import datetime + +from webflow import UserAccessGroupsItem, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.access_groups.list( +client.users.update( site_id="580e63e98c9a982ac9b8b741", + user_id="580e63e98c9a982ac9b8b741", + id="6287ec36a841b25637c663df", + is_email_verified=True, + last_updated=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", + ), + invited_on=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", + ), + created_on=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", + ), + last_login=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", + ), + status="verified", + access_groups=[ + UserAccessGroupsItem( + slug="webflowers", + type="admin", + ) + ], ) ``` @@ -4460,7 +4549,7 @@ client.access_groups.list(
-**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records +**user_id:** `str` — Unique identifier for a User
@@ -4468,7 +4557,7 @@ client.access_groups.list(
-**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) +**id:** `typing.Optional[str]` — Unique identifier for the User
@@ -4476,10 +4565,7 @@ client.access_groups.list(
-**sort:** `typing.Optional[AccessGroupsListRequestSort]` - -Sort string to use when ordering access groups -Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`) +**is_email_verified:** `typing.Optional[bool]` — Shows whether the user has verified their email address
@@ -4487,20 +4573,75 @@ Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`)
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**last_updated:** `typing.Optional[dt.datetime]` — The timestamp the user was updated
+ +
+
+ +**invited_on:** `typing.Optional[dt.datetime]` — The timestamp the user was invited +
+
+
+**created_on:** `typing.Optional[dt.datetime]` — The timestamp the user was created +
-
-## Products -
client.products.list(...) +
+
+ +**last_login:** `typing.Optional[dt.datetime]` — The timestamp the user was logged in + +
+
+ +
+
+ +**status:** `typing.Optional[UserStatus]` — The status of the user + +
+
+ +
+
+ +**access_groups:** `typing.Optional[typing.Sequence[UserAccessGroupsItem]]` — Access groups the user belongs to + +
+
+ +
+
+ +**data:** `typing.Optional[UserData]` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ +
+ + + +
+ + +
client.users.invite(...)
@@ -4512,12 +4653,11 @@ Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`)
-Retrieve all products for a site. +Create and invite a user with an email address. -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. +The user will be sent and invite via email, which they will need to accept in order to join paid any paid access group. -Required scope | `ecommerce:read` +Required scope | `users:write`
@@ -4537,8 +4677,10 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.products.list( +client.users.invite( site_id="580e63e98c9a982ac9b8b741", + email="some.one@home.com", + access_groups=["accessGroups"], ) ``` @@ -4563,7 +4705,7 @@ client.products.list(
-**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records +**email:** `str` — Email address of user to send invite to
@@ -4571,7 +4713,7 @@ client.products.list(
-**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) +**access_groups:** `typing.Optional[typing.Sequence[str]]` — An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed.
@@ -4591,7 +4733,8 @@ client.products.list(
-
client.products.create(...) +## AccessGroups +
client.access_groups.list(...)
@@ -4603,20 +4746,9 @@ client.products.list(
-Create a new product and SKU. - -When you create a product, you will always create a SKU, since a Product Item must have, at minimum, a single SKU. - -To create a Product with multiple SKUs - for example a T-shirt in sizes small, medium and large: - - Create parameters in `sku-properties`, also known as [product options and variants.](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants). - - A single `sku-property` would be `color`. Within the `color` property, list the various colors of T-shirts as an array of `enum` values: `royal-blue`, `crimson-red`, and `forrest-green`. - - Once, you've created a Product and its `sku-properties` with `enum` values, Webflow will create a **default SKU**, which will automatically be a combination of the first `sku-properties` you've created. - - In our example, the default SKU will be a Royal Blue T-Shirt, because our first `enum` of our Color `sku-property` is Royal Blue. - - After you've created your product, you can create additional SKUs using the [Create SKU 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. +Get a list of access groups for a site -Required scope | `ecommerce:write` +Required scope | `users:read`
@@ -4636,7 +4768,7 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.products.create( +client.access_groups.list( site_id="580e63e98c9a982ac9b8b741", ) @@ -4662,7 +4794,7 @@ client.products.create(
-**publish_status:** `typing.Optional[PublishStatus]` +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records
@@ -4670,7 +4802,7 @@ client.products.create(
-**product:** `typing.Optional[Product]` +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100)
@@ -4678,7 +4810,10 @@ client.products.create(
-**sku:** `typing.Optional[Sku]` +**sort:** `typing.Optional[AccessGroupsListRequestSort]` + +Sort string to use when ordering access groups +Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`)
@@ -4698,7 +4833,8 @@ client.products.create(
-
client.products.get(...) +## Products +
client.products.list(...)
@@ -4710,8 +4846,10 @@ client.products.create(
-Retrieve a single product by its ID. All of its SKUs will also be -retrieved. +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`
@@ -4733,9 +4871,8 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.products.get( +client.products.list( site_id="580e63e98c9a982ac9b8b741", - product_id="580e63fc8c9a982ac9b8b745", ) ``` @@ -4760,7 +4897,15 @@ client.products.get(
-**product_id:** `str` — Unique identifier for a Product +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100)
@@ -4780,7 +4925,7 @@ client.products.get(
-
client.products.update(...) +
client.products.create(...)
@@ -4792,9 +4937,14 @@ client.products.get(
-Update an existing Product. +Create a new ecommerce product and defaultSKU. A product, at minimum, must have a single SKU. -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. +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`
@@ -4811,14 +4961,88 @@ Required scope | `ecommerce:write`
```python -from webflow import Webflow +from webflow import ( + ProductFieldData, + SkuFieldData, + SkuFieldDataPrice, + SkuPropertyList, + SkuPropertyListEnumItem, + Webflow, +) +from webflow.resources.products import ( + ProductSkuCreateProduct, + ProductSkuCreateSku, +) client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.products.update( +client.products.create( site_id="580e63e98c9a982ac9b8b741", - product_id="580e63fc8c9a982ac9b8b745", + 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.0, + 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", + ), + ), ) ``` @@ -4843,15 +5067,7 @@ client.products.update(
-**product_id:** `str` — Unique identifier for a Product - -
-
- -
-
- -**publish_status:** `typing.Optional[PublishStatus]` +**product:** `ProductSkuCreateProduct`
@@ -4859,7 +5075,7 @@ client.products.update(
-**product:** `typing.Optional[Product]` +**sku:** `ProductSkuCreateSku`
@@ -4867,7 +5083,7 @@ client.products.update(
-**sku:** `typing.Optional[Sku]` +**publish_status:** `typing.Optional[PublishStatus]`
@@ -4887,7 +5103,7 @@ client.products.update(
-
client.products.create_sku(...) +
client.products.get(...)
@@ -4899,11 +5115,10 @@ 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) - -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. +Retrieve a single product by its ID. All of its SKUs will also be +retrieved. -Required scope | `ecommerce:write` +Required scope | `ecommerce:read`
@@ -4918,15 +5133,14 @@ Required scope | `ecommerce:write`
```python -from webflow import Sku, Webflow +from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.products.create_sku( +client.products.get( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", - skus=[Sku()], ) ``` @@ -4959,22 +5173,6 @@ client.products.create_sku(
-**skus:** `typing.Sequence[Sku]` — An array of the SKU data your are adding - -
-
- -
-
- -**publish_status:** `typing.Optional[PublishStatus]` - -
-
- -
-
- **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -4987,7 +5185,7 @@ client.products.create_sku(
-
client.products.update_sku(...) +
client.products.update(...)
@@ -4999,9 +5197,9 @@ client.products.create_sku(
-Update a specified SKU. +Update an existing Product. -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. +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`
@@ -5018,16 +5216,14 @@ Required scope | `ecommerce:write`
```python -from webflow import Sku, Webflow +from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.products.update_sku( +client.products.update( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", - sku_id="5e8518516e147040726cc415", - sku=Sku(), ) ``` @@ -5060,7 +5256,7 @@ client.products.update_sku(
-**sku_id:** `str` — Unique identifier for a SKU +**publish_status:** `typing.Optional[PublishStatus]`
@@ -5068,7 +5264,7 @@ client.products.update_sku(
-**sku:** `Sku` +**product:** `typing.Optional[Product]`
@@ -5076,7 +5272,7 @@ client.products.update_sku(
-**publish_status:** `typing.Optional[PublishStatus]` +**sku:** `typing.Optional[Sku]`
@@ -5096,8 +5292,7 @@ client.products.update_sku(
-## Orders -
client.orders.list(...) +
client.products.create_sku(...)
@@ -5109,9 +5304,11 @@ client.products.update_sku(
-List all orders created for a given site. +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) -Required scope | `ecommerce:read` +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`
@@ -5126,13 +5323,40 @@ Required scope | `ecommerce:read`
```python -from webflow import Webflow +import datetime + +from webflow import Sku, SkuFieldData, SkuFieldDataPrice, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.orders.list( +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-17 18:47:35+00:00", + ), + last_updated=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + created_on=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ) + ], ) ``` @@ -5157,7 +5381,7 @@ client.orders.list(
-**status:** `typing.Optional[OrdersListRequestStatus]` — Filter the orders by status +**product_id:** `str` — Unique identifier for a Product
@@ -5165,7 +5389,7 @@ client.orders.list(
-**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records +**skus:** `typing.Sequence[Sku]` — An array of the SKU data your are adding
@@ -5173,7 +5397,7 @@ client.orders.list(
-**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) +**publish_status:** `typing.Optional[PublishStatus]`
@@ -5193,7 +5417,7 @@ client.orders.list(
-
client.orders.get(...) +
client.products.update_sku(...)
@@ -5205,10 +5429,11 @@ client.orders.list(
-Retrieve a single product by its ID. All of its SKUs will also be -retrieved. +Update a specified SKU. -Required scope | `ecommerce:read` +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`
@@ -5223,14 +5448,39 @@ Required scope | `ecommerce:read`
```python -from webflow import Webflow +import datetime + +from webflow import Sku, SkuFieldData, SkuFieldDataPrice, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.orders.get( +client.products.update_sku( site_id="580e63e98c9a982ac9b8b741", - order_id="5e8518516e147040726cc415", + product_id="580e63fc8c9a982ac9b8b745", + sku_id="5e8518516e147040726cc415", + sku=Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + last_updated=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + created_on=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ), ) ``` @@ -5255,7 +5505,7 @@ client.orders.get(
-**order_id:** `str` — Unique identifier for an Order +**product_id:** `str` — Unique identifier for a Product
@@ -5263,35 +5513,238 @@ client.orders.get(
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. +**sku_id:** `str` — Unique identifier for a SKU
-
-
+
+
+**sku:** `Sku` +
-
-
client.orders.update(...)
-#### 📝 Description - -
-
+**publish_status:** `typing.Optional[PublishStatus]` + +
+
-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` +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + + +
+ + +## Orders +
client.orders.list(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +List all orders created for a given site. + +Required scope | `ecommerce:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.orders.list( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**status:** `typing.Optional[OrdersListRequestStatus]` — Filter the orders by status + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.orders.get(...) +
+
+ +#### 📝 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 + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +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(...) +
+
+ +#### 📝 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`
@@ -5928,14 +6381,11 @@ client.ecommerce.get_settings(
-Create a custom field in a collection. +Create a custom field in a collection. -Slugs must be all lowercase letters without spaces. -If you pass a string with uppercase letters and/or spaces to the "Slug" property, Webflow will -convert the slug to lowercase and replace spaces with "-." +Field validation is currently not available through the API. -Only some field types can be created through the API. -This endpoint does not currently support bulk creation. +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`
@@ -5952,17 +6402,24 @@ Required scope | `cms:write`
```python -from webflow import Webflow +from webflow import ReferenceField, ReferenceFieldMetadata, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.collections.fields.create( collection_id="580e63fc8c9a982ac9b8b745", - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + request=ReferenceField( + id="562ac0395358780a1f5e6fbd", + is_editable=True, + is_required=False, + type="Reference", + display_name="Author", + help_text="Add the post author here", + metadata=ReferenceFieldMetadata( + collection_id="63692ab61fb2852f582ba8f5", + ), + ), ) ``` @@ -5987,31 +6444,7 @@ client.collections.fields.create(
-**type:** `FieldCreateType` — Choose these appropriate field type for your collection data - -
-
- -
-
- -**display_name:** `str` — The name of a field - -
-
- -
-
- -**is_required:** `typing.Optional[bool]` — define whether a field is required in a collection - -
-
- -
-
- -**help_text:** `typing.Optional[str]` — Additional text to help anyone filling out this field +**request:** `FieldCreate`
@@ -6305,7 +6738,7 @@ client.collections.items.list_items(
-**name:** `typing.Optional[str]` — The name of the item(s) +**name:** `typing.Optional[str]` — Filter by the exact name of the item(s)
@@ -6313,7 +6746,7 @@ client.collections.items.list_items(
-**slug:** `typing.Optional[str]` — The slug of the item +**slug:** `typing.Optional[str]` — Filter by the exact slug of the item
@@ -6364,7 +6797,7 @@ client.collections.items.list_items( Create Item(s) in a Collection. -To create items across multiple locales, please use [this endpoint.](/v2.0.0/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`
@@ -6437,7 +6870,15 @@ client.collections.items.create_item(
-**request:** `ItemsCreateItemRequest` +**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.
@@ -6471,7 +6912,7 @@ client.collections.items.create_item( Delete Items from a Collection. -**Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be deleted only in the primary locale. +Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write`
@@ -6489,12 +6930,20 @@ Required scope | `CMS:write` ```python from webflow import Webflow +from webflow.resources.collections.resources.items import ( + ItemsDeleteItemsRequestItemsItem, +) client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.collections.items.delete_items( collection_id="580e63fc8c9a982ac9b8b745", + items=[ + ItemsDeleteItemsRequestItemsItem( + id="580e64008c9a982ac9b8b754", + ) + ], ) ``` @@ -6519,7 +6968,7 @@ client.collections.items.delete_items(
-**items:** `typing.Optional[typing.Sequence[ItemsDeleteItemsRequestItemsItem]]` +**items:** `typing.Sequence[ItemsDeleteItemsRequestItemsItem]`
@@ -6551,9 +7000,11 @@ client.collections.items.delete_items(
-Update a single item or multiple items (up to 100) in a Collection. +Update a single item or multiple items in a Collection. -**Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. +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`
@@ -6583,35 +7034,21 @@ client.collections.items.update_items( collection_id="580e63fc8c9a982ac9b8b745", items=[ CollectionItemWithIdInput( - id="66f6ed9576ddacf3149d5ea6", - cms_locale_id="66f6e966c9e1dc700a857ca5", + id="580e64008c9a982ac9b8b754", + is_archived=False, + is_draft=False, field_data=CollectionItemWithIdInputFieldData( - name="Ne Paniquez Pas", - slug="ne-paniquez-pas", + name="Senior Data Analyst", + slug="senior-data-analyst", ), ), CollectionItemWithIdInput( - id="66f6ed9576ddacf3149d5ea6", - cms_locale_id="66f6e966c9e1dc700a857ca4", + id="580e64008c9a982ac9b8b754", + is_archived=False, + is_draft=False, 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", + name="Product Manager", + slug="product-manager", ), ), ], @@ -6639,6 +7076,14 @@ client.collections.items.update_items(
+**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. + +
+
+ +
+
+ **items:** `typing.Optional[typing.Sequence[CollectionItemWithIdInput]]`
@@ -6671,7 +7116,12 @@ client.collections.items.update_items(
-List of all live Items within a Collection. +List all published items in a collection. + + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + Required scope | `CMS:read`
@@ -6743,7 +7193,7 @@ client.collections.items.list_items_live(
-**name:** `typing.Optional[str]` — The name of the item(s) +**name:** `typing.Optional[str]` — Filter by the exact name of the item(s)
@@ -6751,7 +7201,7 @@ client.collections.items.list_items_live(
-**slug:** `typing.Optional[str]` — The slug of the item +**slug:** `typing.Optional[str]` — Filter by the exact slug of the item
@@ -6799,10 +7249,10 @@ client.collections.items.list_items_live(
-Create live Item(s) in a Collection. The Item(s) will be published to the live site. +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.](/v2.0.0/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` @@ -6872,7 +7322,15 @@ client.collections.items.create_item_live(
-**request:** `ItemsCreateItemLiveRequest` +**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.
@@ -6904,9 +7362,9 @@ client.collections.items.create_item_live(
-Remove an item or multiple items (up to 100 items) from the live site. Deleting published items will unpublish the items from the live site and set them to draft. +Unpublish up to 100 items from the live site and set the `isDraft` property to `true`. -**Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be unpublished only in the primary locale. +Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write`
@@ -6924,12 +7382,20 @@ Required scope | `CMS:write` ```python from webflow import Webflow +from webflow.resources.collections.resources.items import ( + ItemsDeleteItemsLiveRequestItemsItem, +) client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.collections.items.delete_items_live( collection_id="580e63fc8c9a982ac9b8b745", + items=[ + ItemsDeleteItemsLiveRequestItemsItem( + id="580e64008c9a982ac9b8b754", + ) + ], ) ``` @@ -6954,7 +7420,7 @@ client.collections.items.delete_items_live(
-**items:** `typing.Optional[typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem]]` +**items:** `typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem]`
@@ -6986,9 +7452,9 @@ client.collections.items.delete_items_live(
-Update a single live item or multiple live items (up to 100) in a Collection +Update a single published item or multiple published items (up to 100) in a Collection -**Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. +Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write`
@@ -7074,6 +7540,14 @@ 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. + +
+
+ +
+
+ **items:** `typing.Optional[typing.Sequence[CollectionItemWithIdInput]]`
@@ -7108,9 +7582,10 @@ client.collections.items.update_items_live( Create an item or multiple items in a CMS Collection across multiple corresponding locales. -**Notes:** + - This endpoint can create up to 100 items in a request. - - If the `cmsLocaleIds` parameter is undefined or empty and localization is enabled, items will only be created in the primary locale. + - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale. + Required scope | `CMS:write`
@@ -7178,6 +7653,14 @@ client.collections.items.create_items(
+**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.Sequence[str]]` — Array of identifiers for the locales where the item will be created
@@ -7315,7 +7798,7 @@ client.collections.items.get_item(
-Delete an Item from a Collection. This endpoint does not currently support bulk deletion. +Delete an item from a collection. Required scope | `CMS:write`
@@ -7467,6 +7950,14 @@ client.collections.items.update_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. + +
+
+ +
+
+ **id:** `typing.Optional[str]` — Unique identifier for the Item
@@ -7557,6 +8048,11 @@ client.collections.items.update_item( Get details of a selected Collection live Item. + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + + Required scope | `CMS:read`
@@ -7644,9 +8140,9 @@ client.collections.items.get_item_live(
-Remove a live item from the site. Removing a published item will unpublish the item from the live site and set it to draft. +Unpublish a live item from the site and set the `isDraft` property to `true`. -This endpoint does not currently support bulk deletion. +For bulk unpublishing, please use [this endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live) Required scope | `CMS:write`
@@ -7798,6 +8294,14 @@ client.collections.items.update_item_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. + +
+
+ +
+
+ **id:** `typing.Optional[str]` — Unique identifier for the Item
@@ -7904,13 +8408,28 @@ Required scope | `cms:write` ```python from webflow import Webflow +from webflow.resources.collections.resources.items import ( + ItemIDsWithLocales, + ItemsPublishItemRequestItemsItemsItem, +) client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.collections.items.publish_item( collection_id="580e63fc8c9a982ac9b8b745", - item_ids=["itemIds"], + request=ItemIDsWithLocales( + items=[ + ItemsPublishItemRequestItemsItemsItem( + id="643fd856d66b6528195ee2ca", + cms_locale_ids=[ + "653ad57de882f528b32e810e", + "6514390aea353fc691d69827", + "65143930ea353fc691d69cd8", + ], + ) + ], + ), ) ``` @@ -7935,7 +8454,7 @@ client.collections.items.publish_item(
-**item_ids:** `typing.Sequence[str]` +**request:** `ItemsPublishItemRequest`
@@ -7968,13 +8487,7 @@ client.collections.items.publish_item(
-Get all registered scripts that have been applied to a specific Page. - -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. - -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). +Get all scripts applied to a page. Required scope | `custom_code:read`
@@ -8046,15 +8559,11 @@ client.pages.scripts.get_custom_code(
-Add a registered script to a Page. - -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. +Apply scripts to a page. -A site can have a maximum of 800 registered scripts. - -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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 | `custom_code:write`
@@ -8163,11 +8672,7 @@ client.pages.scripts.upsert_custom_code(
-Delete the custom code block that an app has created for a page - -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. +Delete a custom code block that the App created on a page. Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). @@ -8242,10 +8747,11 @@ client.pages.scripts.delete_custom_code(
-Fetch a list of all URL redirect rules configured for a specific site. +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. +This endpoint requires an Enterprise workspace. Required scope: `sites:read`
@@ -8317,10 +8823,12 @@ client.sites.redirects.list(
-Add a new URL redirection rule to a site. +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. +This endpoint requires an Enterprise workspace. + Required scope: `sites:write`
@@ -8418,8 +8926,12 @@ client.sites.redirects.create(
-Remove a URL redirection rule from a site. +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. + +This endpoint requires an Enterprise workspace. + Required scope: `sites:write`
@@ -8499,7 +9011,10 @@ client.sites.redirects.delete(
-Update a URL redirection rule from a site. +Update a 301 redirection rule from a site. + +This endpoint requires an Enterprise workspace. + Required scope: `sites:write`
@@ -8609,6 +9124,8 @@ client.sites.redirects.update( Get site plan details for the specified Site. +This endpoint requires an Enterprise workspace. + Required scope | `sites:read`
@@ -8667,8 +9184,8 @@ client.sites.plans.get_site_plan(
-## Sites ActivityLogs -
client.sites.activity_logs.list(...) +## Sites RobotsTxt +
client.sites.robots_txt.get(...)
@@ -8680,7 +9197,11 @@ client.sites.plans.get_site_plan(
-Retrieve Activity Logs for a specific Site. Requires Site to be on an Enterprise plan.

Required scope | `site_activity:read` +Retrieve the robots.txt configuration for various user agents. + +This endpoint requires an Enterprise workspace. + +Required scope: `site_config:read`
@@ -8700,7 +9221,7 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.sites.activity_logs.list( +client.sites.robots_txt.get( site_id="580e63e98c9a982ac9b8b741", ) @@ -8726,15 +9247,97 @@ client.sites.activity_logs.list(
-**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+ +
+ + + +
+ +
client.sites.robots_txt.put(...)
-**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records +#### 📝 Description + +
+
+ +
+
+ +Replace the `robots.txt` configuration for various user agents. + +This endpoint requires an Enterprise workspace. + +Required scope | `site_config:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import RobotsRulesItem, Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.robots_txt.put( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=["/public"], + disallows=["/vogon-poetry", "/total-perspective-vortex"], + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**rules:** `typing.Optional[typing.Sequence[RobotsRulesItem]]` — List of rules for user agents. + +
+
+ +
+
+ +**sitemap:** `typing.Optional[str]` — URL to the sitemap.
@@ -8754,8 +9357,7 @@ client.sites.activity_logs.list(
-## Sites Scripts -
client.sites.scripts.get_custom_code(...) +
client.sites.robots_txt.delete(...)
@@ -8767,11 +9369,13 @@ client.sites.activity_logs.list(
-Get all registered scripts that have been applied to a specific 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. -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). +**Note:** Deleting a user-agent with no rules will make the user-agent's access unrestricted unless other directives apply. -Required scope | `custom_code:read` +This endpoint requires an Enterprise workspace. + +Required scope: `site_config:write`
@@ -8786,13 +9390,20 @@ Required scope | `custom_code:read`
```python -from webflow import Webflow +from webflow import RobotsRulesItem, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.sites.scripts.get_custom_code( +client.sites.robots_txt.delete( site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="*", + allows=["/public"], + disallows=["/bubbles"], + ) + ], ) ``` @@ -8817,6 +9428,22 @@ client.sites.scripts.get_custom_code(
+**rules:** `typing.Optional[typing.Sequence[RobotsRulesItem]]` — List of rules for user agents. + +
+
+ +
+
+ +**sitemap:** `typing.Optional[str]` — URL to the sitemap. + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -8829,7 +9456,7 @@ client.sites.scripts.get_custom_code(
-
client.sites.scripts.upsert_custom_code(...) +
client.sites.robots_txt.patch(...)
@@ -8841,15 +9468,11 @@ client.sites.scripts.get_custom_code(
-Add a registered script to a Site. - -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. +Update the `robots.txt` configuration for various user agents. -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). +This endpoint requires an Enterprise workspace. -Required scope | `custom_code:write` +Required scope | `site_config:write`
@@ -8864,26 +9487,21 @@ Required scope | `custom_code:write`
```python -from webflow import ScriptApply, Webflow +from webflow import RobotsRulesItem, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.sites.scripts.upsert_custom_code( +client.sites.robots_txt.patch( site_id="580e63e98c9a982ac9b8b741", - 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", - ), + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=["/public"], + disallows=["/vogon-poetry", "/total-perspective-vortex"], + ) ], + sitemap="https://heartofgold.ship/sitemap.xml", ) ``` @@ -8908,15 +9526,7 @@ client.sites.scripts.upsert_custom_code(
-**scripts:** `typing.Optional[typing.Sequence[ScriptApply]]` — A list of scripts applied to a Site or a Page - -
-
- -
-
- -**last_updated:** `typing.Optional[str]` — Date when the Site's scripts were last updated +**rules:** `typing.Optional[typing.Sequence[RobotsRulesItem]]` — List of rules for user agents.
@@ -8924,7 +9534,7 @@ client.sites.scripts.upsert_custom_code(
-**created_on:** `typing.Optional[str]` — Date when the Site's scripts were created +**sitemap:** `typing.Optional[str]` — URL to the sitemap.
@@ -8944,7 +9554,8 @@ client.sites.scripts.upsert_custom_code(
-
client.sites.scripts.delete_custom_code(...) +## Sites WellKnown +
client.sites.well_known.put(...)
@@ -8956,11 +9567,20 @@ client.sites.scripts.upsert_custom_code(
-Delete the custom code block that an app created for a Site +Upload a supported well-known file to a site. -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). +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. + -Required scope | `custom_code:write` +This endpoint requires an Enterprise workspace. + +Required scope: `site_config:write`
@@ -8980,8 +9600,10 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.sites.scripts.delete_custom_code( +client.sites.well_known.put( site_id="580e63e98c9a982ac9b8b741", + file_name="fileName", + file_data="fileData", ) ``` @@ -9006,6 +9628,30 @@ client.sites.scripts.delete_custom_code(
+**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.
@@ -9018,7 +9664,7 @@ client.sites.scripts.delete_custom_code(
-
client.sites.scripts.list_custom_code_blocks(...) +
client.sites.well_known.delete(...)
@@ -9030,11 +9676,11 @@ client.sites.scripts.delete_custom_code(
-Get all instances of Custom Code applied to a Site or Pages. +Delete existing well-known files from a site. -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). +This endpoint requires an Enterprise workspace. -Required scope | `custom_code:read` +Required scope: `site_config:write`
@@ -9054,7 +9700,7 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.sites.scripts.list_custom_code_blocks( +client.sites.well_known.delete( site_id="580e63e98c9a982ac9b8b741", ) @@ -9080,7 +9726,7 @@ client.sites.scripts.list_custom_code_blocks(
-**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records +**file_names:** `typing.Optional[typing.Sequence[str]]` — A list of file names to delete
@@ -9088,7 +9734,947 @@ client.sites.scripts.list_custom_code_blocks(
-**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ +
+ + + +
+ + +## Sites ActivityLogs +
client.sites.activity_logs.list(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve Activity Logs for a specific Site. + +This endpoint requires an Enterprise workspace. + +Required scope: `site_activity:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.activity_logs.list( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +## Sites Comments +
client.sites.comments.list_comment_threads(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +List all comment threads for a site. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + +Required scope | `comments:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.comments.list_comment_threads( + site_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**locale_id:** `typing.Optional[str]` — Unique identifier for a specific locale. Applicable, when using localization. + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**sort_by:** `typing.Optional[CommentsListCommentThreadsRequestSortBy]` — Sort results by the provided value. Only allowed when sortOrder is provided. + +
+
+ +
+
+ +**sort_order:** `typing.Optional[CommentsListCommentThreadsRequestSortOrder]` — Sorts the results by asc or desc + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.sites.comments.get_comment_thread(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get details of a specific comment thread. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + +Required scope | `comments:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.comments.get_comment_thread( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**comment_thread_id:** `str` — Unique identifier for a Comment Thread + +
+
+ +
+
+ +**locale_id:** `typing.Optional[str]` — Unique identifier for a specific locale. Applicable, when using localization. + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**sort_by:** `typing.Optional[CommentsGetCommentThreadRequestSortBy]` — Sort results by the provided value. Only allowed when sortOrder is provided. + +
+
+ +
+
+ +**sort_order:** `typing.Optional[CommentsGetCommentThreadRequestSortOrder]` — Sorts the results by asc or desc + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.sites.comments.list_comment_replies(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +List all replies to a specific comment thread. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + +Required scope | `comments:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.comments.list_comment_replies( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**comment_thread_id:** `str` — Unique identifier for a Comment Thread + +
+
+ +
+
+ +**locale_id:** `typing.Optional[str]` — Unique identifier for a specific locale. Applicable, when using localization. + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**sort_by:** `typing.Optional[CommentsListCommentRepliesRequestSortBy]` — Sort results by the provided value. Only allowed when sortOrder is provided. + +
+
+ +
+
+ +**sort_order:** `typing.Optional[CommentsListCommentRepliesRequestSortOrder]` — Sorts the results by asc or desc + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +## Sites Scripts +
client.sites.scripts.get_custom_code(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +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. + + +Required scope | `custom_code:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.scripts.get_custom_code( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.sites.scripts.upsert_custom_code(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Apply registered scripts 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. + + +Required scope | `custom_code:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import ScriptApply, Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.scripts.upsert_custom_code( + site_id="580e63e98c9a982ac9b8b741", + 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", + ), + ], +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**scripts:** `typing.Optional[typing.Sequence[ScriptApply]]` — A list of scripts applied to a Site or a Page + +
+
+ +
+
+ +**last_updated:** `typing.Optional[str]` — Date when the Site's scripts were last updated + +
+
+ +
+
+ +**created_on:** `typing.Optional[str]` — Date when the Site's scripts were created + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.sites.scripts.delete_custom_code(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Remove scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts. + +Required scope | `custom_code:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.scripts.delete_custom_code( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.sites.scripts.list_custom_code_blocks(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get a list of scripts that have been applied to a site and/or individual pages. + + + 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. + + +Required scope | `custom_code:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.scripts.list_custom_code_blocks( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +## Workspaces AuditLogs +
client.workspaces.audit_logs.get_workspace_audit_logs(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get audit logs for a workspace. + +This endpoint requires an Enterprise workspace and a workspace token with the `workspace_activity:read` scope. Create a workspace token from your workspace dashboard integrations page to use this endpoint. + +Required scope | `workspace_activity:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +import datetime + +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.workspaces.audit_logs.get_workspace_audit_logs( + workspace_id_or_slug="hitchhikers-workspace", + from_=datetime.datetime.fromisoformat( + "2024-04-22 16:00:31+00:00", + ), + to=datetime.datetime.fromisoformat( + "2024-04-22 16:00:31+00:00", + ), +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**workspace_id_or_slug:** `str` — Unique identifier or slug for a Workspace + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**sort_order:** `typing.Optional[AuditLogsGetWorkspaceAuditLogsRequestSortOrder]` — Sorts the results by asc or desc + +
+
+ +
+
+ +**event_type:** `typing.Optional[AuditLogsGetWorkspaceAuditLogsRequestEventType]` — The event type to filter by + +
+
+ +
+
+ +**from_:** `typing.Optional[dt.datetime]` — The start date to filter by + +
+
+ +
+
+ +**to:** `typing.Optional[dt.datetime]` — The end date to filter by
diff --git a/src/webflow/__init__.py b/src/webflow/__init__.py index 0d82d59..dc97a63 100644 --- a/src/webflow/__init__.py +++ b/src/webflow/__init__.py @@ -32,20 +32,34 @@ CollectionItemWithIdInputFieldData, CollectionList, CollectionListArrayItem, + CommentReply, + CommentReplyAuthor, + CommentReplyList, + CommentReplyListPagination, + CommentReplyMentionedUsersItem, + CommentThread, + CommentThreadAuthor, + CommentThreadList, + CommentThreadListPagination, + CommentThreadMentionedUsersItem, Component, ComponentDom, - ComponentInstanceNodePropertyOverridesWrite, + ComponentInstance, ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem, ComponentList, ComponentNode, ComponentProperties, ComponentProperty, ComponentPropertyType, + Conflict, ConflictErrorBody, CustomCodeBlock, CustomCodeBlockType, CustomCodeHostedResponse, CustomCodeInlineResponse, + CustomRole, + CustomRoleAuditLogItem, + CustomRoleAuditLogItemEventSubType, Dom, Domain, Domains, @@ -54,7 +68,11 @@ Error, ErrorCode, Field, + FieldCreate, FieldType, + FieldValidations, + FieldValidationsAdditionalProperties, + FieldValidationsAdditionalPropertiesAdditionalProperties, ForbiddenErrorBody, Form, FormField, @@ -73,17 +91,27 @@ ListCustomCodeBlocks, Locale, Locales, + Metadata, + MetadataOptionsItem, NoDomains, Node, Node_ComponentInstance, Node_Image, + Node_SearchButton, + Node_Select, + Node_SubmitButton, Node_Text, + Node_TextInput, NotEnterprisePlanSite, NotEnterprisePlanWorkspace, + OptionField, Order, OrderAddress, OrderAddressJapanType, OrderAddressType, + OrderBillingAddress, + OrderBillingAddressJapanType, + OrderBillingAddressType, OrderCustomerInfo, OrderDisputeLastStatus, OrderDownloadFilesItem, @@ -94,6 +122,9 @@ OrderPurchasedItemVariantImage, OrderPurchasedItemVariantImageFile, OrderPurchasedItemVariantImageFileVariantsItem, + OrderShippingAddress, + OrderShippingAddressJapanType, + OrderShippingAddressType, OrderStatus, OrderTotals, OrderTotalsExtrasItem, @@ -113,11 +144,22 @@ PublishStatus, Redirect, Redirects, + ReferenceField, + ReferenceFieldMetadata, + ReferenceFieldType, RegisteredScriptList, + Robots, + RobotsRulesItem, ScriptApply, ScriptApplyList, ScriptApplyLocation, Scripts, + SearchButton, + SearchButtonNode, + Select, + SelectNode, + SelectNodeChoicesItem, + SelectNodeWriteChoicesItem, Site, SiteActivityLogItem, SiteActivityLogItemEvent, @@ -125,6 +167,9 @@ SiteActivityLogItemUser, SiteActivityLogResponse, SiteDataCollectionType, + SiteMembership, + SiteMembershipAuditLogItem, + SiteMembershipAuditLogItemEventSubType, SitePlan, SitePlanId, SitePlanName, @@ -141,16 +186,24 @@ SkuPropertyList, SkuPropertyListEnumItem, SkuValueList, + StaticField, + StaticFieldType, StripeCard, StripeCardBrand, StripeCardExpires, StripeDetails, + SubmitButton, + SubmitButtonNode, Text, + TextInput, + TextInputNode, TextNode, TextNodeText, - TextNodeWrite, TriggerType, User, + UserAccess, + UserAccessAuditLogItem, + UserAccessAuditLogItemEventSubType, UserAccessGroupsItem, UserAccessGroupsItemType, UserData, @@ -162,6 +215,32 @@ Webhook, WebhookFilter, WebhookList, + WorkspaceAuditLogItem, + WorkspaceAuditLogItemActor, + WorkspaceAuditLogItemPayloadSiteMembershipMethod, + WorkspaceAuditLogItemPayloadSiteMembershipSite, + WorkspaceAuditLogItemPayloadSiteMembershipTargetUser, + WorkspaceAuditLogItemPayloadSiteMembershipUserType, + WorkspaceAuditLogItemPayloadUserAccessMethod, + WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod, + WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser, + WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType, + WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod, + WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser, + WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType, + WorkspaceAuditLogItemWorkspace, + WorkspaceAuditLogItem_CustomRole, + WorkspaceAuditLogItem_SiteMembership, + WorkspaceAuditLogItem_UserAccess, + WorkspaceAuditLogItem_WorkspaceInvitation, + WorkspaceAuditLogItem_WorkspaceMembership, + WorkspaceAuditLogResponse, + WorkspaceInvitation, + WorkspaceInvitationAuditLogItem, + WorkspaceInvitationAuditLogItemEventSubType, + WorkspaceMembership, + WorkspaceMembershipAuditLogItem, + WorkspaceMembershipAuditLogItemEventSubType, ) from .errors import ( BadRequestError, @@ -182,11 +261,12 @@ OrdersListRequestStatus, OrdersRefundRequestReason, PageDomWriteNodesItem, + ProductSkuCreateProduct, + ProductSkuCreateSku, ProductsCreateSkuResponse, SitesPublishResponse, UpdateStaticContentResponse, UsersListRequestSort, - UsersUpdateRequestData, access_groups, assets, collections, @@ -202,6 +282,7 @@ token, users, webhooks, + workspaces, ) from .client import AsyncWebflow, Webflow from .environment import WebflowEnvironment @@ -242,10 +323,20 @@ "CollectionItemWithIdInputFieldData", "CollectionList", "CollectionListArrayItem", + "CommentReply", + "CommentReplyAuthor", + "CommentReplyList", + "CommentReplyListPagination", + "CommentReplyMentionedUsersItem", + "CommentThread", + "CommentThreadAuthor", + "CommentThreadList", + "CommentThreadListPagination", + "CommentThreadMentionedUsersItem", "Component", "ComponentDom", "ComponentDomWriteNodesItem", - "ComponentInstanceNodePropertyOverridesWrite", + "ComponentInstance", "ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem", "ComponentList", "ComponentNode", @@ -255,12 +346,16 @@ "ComponentPropertyType", "ComponentsUpdateContentResponse", "ComponentsUpdatePropertiesResponse", + "Conflict", "ConflictError", "ConflictErrorBody", "CustomCodeBlock", "CustomCodeBlockType", "CustomCodeHostedResponse", "CustomCodeInlineResponse", + "CustomRole", + "CustomRoleAuditLogItem", + "CustomRoleAuditLogItemEventSubType", "Dom", "Domain", "Domains", @@ -269,7 +364,11 @@ "Error", "ErrorCode", "Field", + "FieldCreate", "FieldType", + "FieldValidations", + "FieldValidationsAdditionalProperties", + "FieldValidationsAdditionalPropertiesAdditionalProperties", "ForbiddenError", "ForbiddenErrorBody", "Form", @@ -291,18 +390,28 @@ "ListCustomCodeBlocks", "Locale", "Locales", + "Metadata", + "MetadataOptionsItem", "NoDomains", "Node", "Node_ComponentInstance", "Node_Image", + "Node_SearchButton", + "Node_Select", + "Node_SubmitButton", "Node_Text", + "Node_TextInput", "NotEnterprisePlanSite", "NotEnterprisePlanWorkspace", "NotFoundError", + "OptionField", "Order", "OrderAddress", "OrderAddressJapanType", "OrderAddressType", + "OrderBillingAddress", + "OrderBillingAddressJapanType", + "OrderBillingAddressType", "OrderCustomerInfo", "OrderDisputeLastStatus", "OrderDownloadFilesItem", @@ -313,6 +422,9 @@ "OrderPurchasedItemVariantImage", "OrderPurchasedItemVariantImageFile", "OrderPurchasedItemVariantImageFileVariantsItem", + "OrderShippingAddress", + "OrderShippingAddressJapanType", + "OrderShippingAddressType", "OrderStatus", "OrderTotals", "OrderTotalsExtrasItem", @@ -332,15 +444,28 @@ "ProductFieldData", "ProductFieldDataEcProductType", "ProductFieldDataTaxCategory", + "ProductSkuCreateProduct", + "ProductSkuCreateSku", "ProductsCreateSkuResponse", "PublishStatus", "Redirect", "Redirects", + "ReferenceField", + "ReferenceFieldMetadata", + "ReferenceFieldType", "RegisteredScriptList", + "Robots", + "RobotsRulesItem", "ScriptApply", "ScriptApplyList", "ScriptApplyLocation", "Scripts", + "SearchButton", + "SearchButtonNode", + "Select", + "SelectNode", + "SelectNodeChoicesItem", + "SelectNodeWriteChoicesItem", "Site", "SiteActivityLogItem", "SiteActivityLogItemEvent", @@ -348,6 +473,9 @@ "SiteActivityLogItemUser", "SiteActivityLogResponse", "SiteDataCollectionType", + "SiteMembership", + "SiteMembershipAuditLogItem", + "SiteMembershipAuditLogItemEventSubType", "SitePlan", "SitePlanId", "SitePlanName", @@ -365,19 +493,27 @@ "SkuPropertyList", "SkuPropertyListEnumItem", "SkuValueList", + "StaticField", + "StaticFieldType", "StripeCard", "StripeCardBrand", "StripeCardExpires", "StripeDetails", + "SubmitButton", + "SubmitButtonNode", "Text", + "TextInput", + "TextInputNode", "TextNode", "TextNodeText", - "TextNodeWrite", "TooManyRequestsError", "TriggerType", "UnauthorizedError", "UpdateStaticContentResponse", "User", + "UserAccess", + "UserAccessAuditLogItem", + "UserAccessAuditLogItemEventSubType", "UserAccessGroupsItem", "UserAccessGroupsItemType", "UserData", @@ -387,12 +523,37 @@ "UserStatus", "UsersListRequestSort", "UsersNotEnabled", - "UsersUpdateRequestData", "Webflow", "WebflowEnvironment", "Webhook", "WebhookFilter", "WebhookList", + "WorkspaceAuditLogItem", + "WorkspaceAuditLogItemActor", + "WorkspaceAuditLogItemPayloadSiteMembershipMethod", + "WorkspaceAuditLogItemPayloadSiteMembershipSite", + "WorkspaceAuditLogItemPayloadSiteMembershipTargetUser", + "WorkspaceAuditLogItemPayloadSiteMembershipUserType", + "WorkspaceAuditLogItemPayloadUserAccessMethod", + "WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod", + "WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser", + "WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType", + "WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod", + "WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser", + "WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType", + "WorkspaceAuditLogItemWorkspace", + "WorkspaceAuditLogItem_CustomRole", + "WorkspaceAuditLogItem_SiteMembership", + "WorkspaceAuditLogItem_UserAccess", + "WorkspaceAuditLogItem_WorkspaceInvitation", + "WorkspaceAuditLogItem_WorkspaceMembership", + "WorkspaceAuditLogResponse", + "WorkspaceInvitation", + "WorkspaceInvitationAuditLogItem", + "WorkspaceInvitationAuditLogItemEventSubType", + "WorkspaceMembership", + "WorkspaceMembershipAuditLogItem", + "WorkspaceMembershipAuditLogItemEventSubType", "__version__", "access_groups", "assets", @@ -409,4 +570,5 @@ "token", "users", "webhooks", + "workspaces", ] diff --git a/src/webflow/client.py b/src/webflow/client.py index 90c233d..88d7a1a 100644 --- a/src/webflow/client.py +++ b/src/webflow/client.py @@ -1,7 +1,7 @@ # This file was auto-generated by Fern from our API Definition. -import typing from .environment import WebflowEnvironment +import typing import httpx from .core.client_wrapper import SyncClientWrapper from .resources.token.client import TokenClient @@ -19,6 +19,7 @@ from .resources.orders.client import OrdersClient from .resources.inventory.client import InventoryClient from .resources.ecommerce.client import EcommerceClient +from .resources.workspaces.client import WorkspacesClient from .core.client_wrapper import AsyncClientWrapper from .resources.token.client import AsyncTokenClient from .resources.sites.client import AsyncSitesClient @@ -35,6 +36,7 @@ from .resources.orders.client import AsyncOrdersClient from .resources.inventory.client import AsyncInventoryClient from .resources.ecommerce.client import AsyncEcommerceClient +from .resources.workspaces.client import AsyncWorkspacesClient class Webflow: @@ -43,15 +45,12 @@ class Webflow: Parameters ---------- - base_url : typing.Optional[str] - The base url to use for requests from the client. - environment : WebflowEnvironment The environment to use for requests from the client. from .environment import WebflowEnvironment - Defaults to WebflowEnvironment.DEFAULT + Defaults to WebflowEnvironment.DATA_API @@ -77,8 +76,7 @@ class Webflow: def __init__( self, *, - base_url: typing.Optional[str] = None, - environment: WebflowEnvironment = WebflowEnvironment.DEFAULT, + environment: WebflowEnvironment = WebflowEnvironment.DATA_API, access_token: typing.Union[str, typing.Callable[[], str]], timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, @@ -86,7 +84,7 @@ def __init__( ): _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None self._client_wrapper = SyncClientWrapper( - base_url=_get_base_url(base_url=base_url, environment=environment), + environment=environment, access_token=access_token, httpx_client=httpx_client if httpx_client is not None @@ -110,6 +108,7 @@ def __init__( self.orders = OrdersClient(client_wrapper=self._client_wrapper) self.inventory = InventoryClient(client_wrapper=self._client_wrapper) self.ecommerce = EcommerceClient(client_wrapper=self._client_wrapper) + self.workspaces = WorkspacesClient(client_wrapper=self._client_wrapper) class AsyncWebflow: @@ -118,15 +117,12 @@ class AsyncWebflow: Parameters ---------- - base_url : typing.Optional[str] - The base url to use for requests from the client. - environment : WebflowEnvironment The environment to use for requests from the client. from .environment import WebflowEnvironment - Defaults to WebflowEnvironment.DEFAULT + Defaults to WebflowEnvironment.DATA_API @@ -152,8 +148,7 @@ class AsyncWebflow: def __init__( self, *, - base_url: typing.Optional[str] = None, - environment: WebflowEnvironment = WebflowEnvironment.DEFAULT, + environment: WebflowEnvironment = WebflowEnvironment.DATA_API, access_token: typing.Union[str, typing.Callable[[], str]], timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, @@ -161,7 +156,7 @@ def __init__( ): _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None self._client_wrapper = AsyncClientWrapper( - base_url=_get_base_url(base_url=base_url, environment=environment), + environment=environment, access_token=access_token, httpx_client=httpx_client if httpx_client is not None @@ -185,12 +180,4 @@ def __init__( self.orders = AsyncOrdersClient(client_wrapper=self._client_wrapper) self.inventory = AsyncInventoryClient(client_wrapper=self._client_wrapper) self.ecommerce = AsyncEcommerceClient(client_wrapper=self._client_wrapper) - - -def _get_base_url(*, base_url: typing.Optional[str] = None, environment: WebflowEnvironment) -> str: - if base_url is not None: - return base_url - elif environment is not None: - return environment.value - else: - raise Exception("Please pass in either base_url or environment to construct the client") + self.workspaces = AsyncWorkspacesClient(client_wrapper=self._client_wrapper) diff --git a/src/webflow/core/client_wrapper.py b/src/webflow/core/client_wrapper.py index 84ed6fb..e363dd0 100644 --- a/src/webflow/core/client_wrapper.py +++ b/src/webflow/core/client_wrapper.py @@ -1,6 +1,7 @@ # This file was auto-generated by Fern from our API Definition. import typing +from ..environment import WebflowEnvironment import httpx from .http_client import HttpClient from .http_client import AsyncHttpClient @@ -11,18 +12,18 @@ def __init__( self, *, access_token: typing.Union[str, typing.Callable[[], str]], - base_url: str, + environment: WebflowEnvironment, timeout: typing.Optional[float] = None, ): self._access_token = access_token - self._base_url = base_url + self._environment = environment self._timeout = timeout def get_headers(self) -> typing.Dict[str, str]: headers: typing.Dict[str, str] = { "X-Fern-Language": "Python", "X-Fern-SDK-Name": "webflow", - "X-Fern-SDK-Version": "2.0.0b1", + "X-Fern-SDK-Version": "1.2.1", } headers["Authorization"] = f"Bearer {self._get_access_token()}" return headers @@ -33,8 +34,8 @@ def _get_access_token(self) -> str: else: return self._access_token() - def get_base_url(self) -> str: - return self._base_url + def get_environment(self) -> WebflowEnvironment: + return self._environment def get_timeout(self) -> typing.Optional[float]: return self._timeout @@ -45,16 +46,13 @@ def __init__( self, *, access_token: typing.Union[str, typing.Callable[[], str]], - base_url: str, + environment: WebflowEnvironment, timeout: typing.Optional[float] = None, httpx_client: httpx.Client, ): - super().__init__(access_token=access_token, base_url=base_url, timeout=timeout) + super().__init__(access_token=access_token, environment=environment, timeout=timeout) self.httpx_client = HttpClient( - httpx_client=httpx_client, - base_headers=self.get_headers, - base_timeout=self.get_timeout, - base_url=self.get_base_url, + httpx_client=httpx_client, base_headers=self.get_headers, base_timeout=self.get_timeout ) @@ -63,14 +61,11 @@ def __init__( self, *, access_token: typing.Union[str, typing.Callable[[], str]], - base_url: str, + environment: WebflowEnvironment, timeout: typing.Optional[float] = None, httpx_client: httpx.AsyncClient, ): - super().__init__(access_token=access_token, base_url=base_url, timeout=timeout) + super().__init__(access_token=access_token, environment=environment, timeout=timeout) self.httpx_client = AsyncHttpClient( - httpx_client=httpx_client, - base_headers=self.get_headers, - base_timeout=self.get_timeout, - base_url=self.get_base_url, + httpx_client=httpx_client, base_headers=self.get_headers, base_timeout=self.get_timeout ) diff --git a/src/webflow/environment.py b/src/webflow/environment.py index ed0e03d..e6fd331 100644 --- a/src/webflow/environment.py +++ b/src/webflow/environment.py @@ -1,7 +1,23 @@ # This file was auto-generated by Fern from our API Definition. -import enum +from __future__ import annotations -class WebflowEnvironment(enum.Enum): - DEFAULT = "https://api.webflow.com/v2" +class WebflowEnvironment: + DATA_API: WebflowEnvironment + + def __init__(self, *, base: str, data_api: str, content_delivery_api: str, production: str, cdn: str): + self.base = base + self.data_api = data_api + self.content_delivery_api = content_delivery_api + self.production = production + self.cdn = cdn + + +WebflowEnvironment.DATA_API = WebflowEnvironment( + base="https://api.webflow.com/v2", + data_api="https://api.webflow.com/v2", + content_delivery_api="https://api-cdn.webflow.com/v2", + production="https://api.webflow.com/v2", + cdn="https://api-cdn.webflow.com/v2", +) diff --git a/src/webflow/resources/__init__.py b/src/webflow/resources/__init__.py index 9122eee..d2cf359 100644 --- a/src/webflow/resources/__init__.py +++ b/src/webflow/resources/__init__.py @@ -16,6 +16,7 @@ token, users, webhooks, + workspaces, ) from .access_groups import AccessGroupsListRequestSort from .components import ( @@ -27,9 +28,9 @@ from .inventory import InventoryUpdateRequestInventoryType from .orders import OrdersListRequestStatus, OrdersRefundRequestReason from .pages import PageDomWriteNodesItem, UpdateStaticContentResponse -from .products import ProductsCreateSkuResponse +from .products import ProductSkuCreateProduct, ProductSkuCreateSku, ProductsCreateSkuResponse from .sites import SitesPublishResponse -from .users import UsersListRequestSort, UsersUpdateRequestData +from .users import UsersListRequestSort __all__ = [ "AccessGroupsListRequestSort", @@ -41,11 +42,12 @@ "OrdersListRequestStatus", "OrdersRefundRequestReason", "PageDomWriteNodesItem", + "ProductSkuCreateProduct", + "ProductSkuCreateSku", "ProductsCreateSkuResponse", "SitesPublishResponse", "UpdateStaticContentResponse", "UsersListRequestSort", - "UsersUpdateRequestData", "access_groups", "assets", "collections", @@ -61,4 +63,5 @@ "token", "users", "webhooks", + "workspaces", ] diff --git a/src/webflow/resources/access_groups/client.py b/src/webflow/resources/access_groups/client.py index ee7668a..71654e3 100644 --- a/src/webflow/resources/access_groups/client.py +++ b/src/webflow/resources/access_groups/client.py @@ -73,6 +73,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/accessgroups", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -218,6 +219,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/accessgroups", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, diff --git a/src/webflow/resources/assets/client.py b/src/webflow/resources/assets/client.py index 61e141a..c6e39ef 100644 --- a/src/webflow/resources/assets/client.py +++ b/src/webflow/resources/assets/client.py @@ -30,7 +30,7 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Assets: """ - List assets for a given site + List of assets uploaded to a site Required scope | `assets:read` @@ -60,6 +60,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/assets", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -137,15 +138,18 @@ def create( request_options: typing.Optional[RequestOptions] = None, ) -> AssetUpload: """ - Create a new asset entry. + The first step in uploading an asset to a site. This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`. - You can use these two properties to [upload the file to Amazon s3 by making a POST](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) - request to the `uploadUrl` with the `uploadDetails` object as your header information in the request. - Required scope | `assets:write` + Use these properties in the header of a [POST request to Amazson s3](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) to complete the upload. + + + To learn more about how to upload assets to Webflow, see our [assets guide](/data/docs/working-with-assets). + + Required scope | `assets:write` Parameters ---------- @@ -184,6 +188,7 @@ def create( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/assets", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "fileName": file_name, @@ -262,7 +267,7 @@ def create( def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Asset: """ - Get an Asset + Get details about an asset Required scope | `assets:read` @@ -292,6 +297,7 @@ def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -390,6 +396,7 @@ def delete(self, asset_id: str, *, request_options: typing.Optional[RequestOptio """ _response = self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -460,7 +467,7 @@ def update( request_options: typing.Optional[RequestOptions] = None, ) -> Asset: """ - Update an Asset + Update details of an Asset. Required scope | `assets:write` @@ -496,6 +503,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "localeId": locale_id, @@ -603,6 +611,7 @@ def list_folders(self, site_id: str, *, request_options: typing.Optional[Request """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/asset_folders", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -716,6 +725,7 @@ def create_folder( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/asset_folders", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "displayName": display_name, @@ -825,6 +835,7 @@ def get_folder( """ _response = self._client_wrapper.httpx_client.request( f"asset_folders/{jsonable_encoder(asset_folder_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -899,7 +910,7 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): async def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Assets: """ - List assets for a given site + List of assets uploaded to a site Required scope | `assets:read` @@ -937,6 +948,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/assets", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1014,15 +1026,18 @@ async def create( request_options: typing.Optional[RequestOptions] = None, ) -> AssetUpload: """ - Create a new asset entry. + The first step in uploading an asset to a site. This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`. - You can use these two properties to [upload the file to Amazon s3 by making a POST](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) - request to the `uploadUrl` with the `uploadDetails` object as your header information in the request. - Required scope | `assets:write` + Use these properties in the header of a [POST request to Amazson s3](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) to complete the upload. + + + To learn more about how to upload assets to Webflow, see our [assets guide](/data/docs/working-with-assets). + + Required scope | `assets:write` Parameters ---------- @@ -1069,6 +1084,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/assets", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "fileName": file_name, @@ -1147,7 +1163,7 @@ async def main() -> None: async def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Asset: """ - Get an Asset + Get details about an asset Required scope | `assets:read` @@ -1185,6 +1201,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1291,6 +1308,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -1361,7 +1379,7 @@ async def update( request_options: typing.Optional[RequestOptions] = None, ) -> Asset: """ - Update an Asset + Update details of an Asset. Required scope | `assets:write` @@ -1405,6 +1423,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "localeId": locale_id, @@ -1522,6 +1541,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/asset_folders", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1643,6 +1663,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/asset_folders", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "displayName": display_name, @@ -1760,6 +1781,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"asset_folders/{jsonable_encoder(asset_folder_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) diff --git a/src/webflow/resources/collections/__init__.py b/src/webflow/resources/collections/__init__.py index cb6aaf8..3796806 100644 --- a/src/webflow/resources/collections/__init__.py +++ b/src/webflow/resources/collections/__init__.py @@ -3,16 +3,20 @@ from .resources import ( CreateBulkCollectionItemRequestBodyFieldData, CreateBulkCollectionItemRequestBodyFieldDataItem, - FieldCreateType, - ItemsCreateItemLiveRequest, - ItemsCreateItemRequest, + ItemIDs, + ItemIDsWithLocales, + ItemsCreateItemLiveRequestBody, + ItemsCreateItemRequestBody, ItemsDeleteItemsLiveRequestItemsItem, ItemsDeleteItemsRequestItemsItem, ItemsListItemsLiveRequestSortBy, ItemsListItemsLiveRequestSortOrder, ItemsListItemsRequestSortBy, ItemsListItemsRequestSortOrder, + ItemsPublishItemRequest, + ItemsPublishItemRequestItemsItemsItem, ItemsPublishItemResponse, + ItemsUpdateItemsResponse, MultipleItems, MultipleLiveItems, SingleCmsItem, @@ -23,16 +27,20 @@ __all__ = [ "CreateBulkCollectionItemRequestBodyFieldData", "CreateBulkCollectionItemRequestBodyFieldDataItem", - "FieldCreateType", - "ItemsCreateItemLiveRequest", - "ItemsCreateItemRequest", + "ItemIDs", + "ItemIDsWithLocales", + "ItemsCreateItemLiveRequestBody", + "ItemsCreateItemRequestBody", "ItemsDeleteItemsLiveRequestItemsItem", "ItemsDeleteItemsRequestItemsItem", "ItemsListItemsLiveRequestSortBy", "ItemsListItemsLiveRequestSortOrder", "ItemsListItemsRequestSortBy", "ItemsListItemsRequestSortOrder", + "ItemsPublishItemRequest", + "ItemsPublishItemRequestItemsItemsItem", "ItemsPublishItemResponse", + "ItemsUpdateItemsResponse", "MultipleItems", "MultipleLiveItems", "SingleCmsItem", diff --git a/src/webflow/resources/collections/client.py b/src/webflow/resources/collections/client.py index 1e44aae..61495ae 100644 --- a/src/webflow/resources/collections/client.py +++ b/src/webflow/resources/collections/client.py @@ -16,7 +16,10 @@ from ...errors.internal_server_error import InternalServerError from json.decoder import JSONDecodeError from ...core.api_error import ApiError +from ...types.field_create import FieldCreate from ...types.collection import Collection +from ...core.serialization import convert_and_respect_annotation_metadata +from ...errors.conflict_error import ConflictError from ...core.client_wrapper import AsyncClientWrapper from .resources.fields.client import AsyncFieldsClient from .resources.items.client import AsyncItemsClient @@ -63,6 +66,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/collections", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -137,10 +141,13 @@ def create( display_name: str, singular_name: str, slug: typing.Optional[str] = OMIT, + fields: typing.Optional[typing.Sequence[FieldCreate]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> Collection: """ - Create a Collection for a site. + Create a Collection for a site with collection fields. + + Each collection includes the required _name_ and _slug_ fields, which are generated automatically. You can update the `displayName` of these fields, but the slug for them cannot be changed. Fields slugs are automatically converted to lowercase. Spaces in slugs are replaced with hyphens. Required scope | `cms:write` @@ -158,6 +165,9 @@ def create( slug : typing.Optional[str] Part of a URL that identifier + fields : typing.Optional[typing.Sequence[FieldCreate]] + An array of custom fields to add to the collection + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -168,7 +178,7 @@ def create( Examples -------- - from webflow import Webflow + from webflow import ReferenceField, ReferenceFieldMetadata, StaticField, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -178,15 +188,42 @@ def create( display_name="Blog Posts", singular_name="Blog Post", slug="posts", + fields=[ + StaticField( + is_required=True, + type="PlainText", + display_name="Title", + help_text="The title of the blog post", + ), + StaticField( + is_required=True, + type="RichText", + display_name="Content", + help_text="The content of the blog post", + ), + ReferenceField( + is_required=True, + type="Reference", + display_name="Author", + help_text="The author of the blog post", + metadata=ReferenceFieldMetadata( + collection_id="23cc2d952d4e4631ffd4345d2743db4e", + ), + ), + ], ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/collections", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "displayName": display_name, "singularName": singular_name, "slug": slug, + "fields": convert_and_respect_annotation_metadata( + object_=fields, annotation=typing.Sequence[FieldCreate], direction="write" + ), }, headers={ "content-type": "application/json", @@ -233,6 +270,16 @@ def create( ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -290,6 +337,7 @@ def get(self, collection_id: str, *, request_options: typing.Optional[RequestOpt """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -388,6 +436,7 @@ def delete(self, collection_id: str, *, request_options: typing.Optional[Request """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -496,6 +545,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/collections", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -570,10 +620,13 @@ async def create( display_name: str, singular_name: str, slug: typing.Optional[str] = OMIT, + fields: typing.Optional[typing.Sequence[FieldCreate]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> Collection: """ - Create a Collection for a site. + Create a Collection for a site with collection fields. + + Each collection includes the required _name_ and _slug_ fields, which are generated automatically. You can update the `displayName` of these fields, but the slug for them cannot be changed. Fields slugs are automatically converted to lowercase. Spaces in slugs are replaced with hyphens. Required scope | `cms:write` @@ -591,6 +644,9 @@ async def create( slug : typing.Optional[str] Part of a URL that identifier + fields : typing.Optional[typing.Sequence[FieldCreate]] + An array of custom fields to add to the collection + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -603,7 +659,12 @@ async def create( -------- import asyncio - from webflow import AsyncWebflow + from webflow import ( + AsyncWebflow, + ReferenceField, + ReferenceFieldMetadata, + StaticField, + ) client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -616,6 +677,29 @@ async def main() -> None: display_name="Blog Posts", singular_name="Blog Post", slug="posts", + fields=[ + StaticField( + is_required=True, + type="PlainText", + display_name="Title", + help_text="The title of the blog post", + ), + StaticField( + is_required=True, + type="RichText", + display_name="Content", + help_text="The content of the blog post", + ), + ReferenceField( + is_required=True, + type="Reference", + display_name="Author", + help_text="The author of the blog post", + metadata=ReferenceFieldMetadata( + collection_id="23cc2d952d4e4631ffd4345d2743db4e", + ), + ), + ], ) @@ -623,11 +707,15 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/collections", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "displayName": display_name, "singularName": singular_name, "slug": slug, + "fields": convert_and_respect_annotation_metadata( + object_=fields, annotation=typing.Sequence[FieldCreate], direction="write" + ), }, headers={ "content-type": "application/json", @@ -674,6 +762,16 @@ async def main() -> None: ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -739,6 +837,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -845,6 +944,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) diff --git a/src/webflow/resources/collections/resources/__init__.py b/src/webflow/resources/collections/resources/__init__.py index f9325ee..4ad4d58 100644 --- a/src/webflow/resources/collections/resources/__init__.py +++ b/src/webflow/resources/collections/resources/__init__.py @@ -1,19 +1,23 @@ # This file was auto-generated by Fern from our API Definition. from . import fields, items -from .fields import FieldCreateType from .items import ( CreateBulkCollectionItemRequestBodyFieldData, CreateBulkCollectionItemRequestBodyFieldDataItem, - ItemsCreateItemLiveRequest, - ItemsCreateItemRequest, + ItemIDs, + ItemIDsWithLocales, + ItemsCreateItemLiveRequestBody, + ItemsCreateItemRequestBody, ItemsDeleteItemsLiveRequestItemsItem, ItemsDeleteItemsRequestItemsItem, ItemsListItemsLiveRequestSortBy, ItemsListItemsLiveRequestSortOrder, ItemsListItemsRequestSortBy, ItemsListItemsRequestSortOrder, + ItemsPublishItemRequest, + ItemsPublishItemRequestItemsItemsItem, ItemsPublishItemResponse, + ItemsUpdateItemsResponse, MultipleItems, MultipleLiveItems, SingleCmsItem, @@ -22,16 +26,20 @@ __all__ = [ "CreateBulkCollectionItemRequestBodyFieldData", "CreateBulkCollectionItemRequestBodyFieldDataItem", - "FieldCreateType", - "ItemsCreateItemLiveRequest", - "ItemsCreateItemRequest", + "ItemIDs", + "ItemIDsWithLocales", + "ItemsCreateItemLiveRequestBody", + "ItemsCreateItemRequestBody", "ItemsDeleteItemsLiveRequestItemsItem", "ItemsDeleteItemsRequestItemsItem", "ItemsListItemsLiveRequestSortBy", "ItemsListItemsLiveRequestSortOrder", "ItemsListItemsRequestSortBy", "ItemsListItemsRequestSortOrder", + "ItemsPublishItemRequest", + "ItemsPublishItemRequestItemsItemsItem", "ItemsPublishItemResponse", + "ItemsUpdateItemsResponse", "MultipleItems", "MultipleLiveItems", "SingleCmsItem", diff --git a/src/webflow/resources/collections/resources/fields/__init__.py b/src/webflow/resources/collections/resources/fields/__init__.py index 5a5b167..f3ea265 100644 --- a/src/webflow/resources/collections/resources/fields/__init__.py +++ b/src/webflow/resources/collections/resources/fields/__init__.py @@ -1,5 +1,2 @@ # This file was auto-generated by Fern from our API Definition. -from .types import FieldCreateType - -__all__ = ["FieldCreateType"] diff --git a/src/webflow/resources/collections/resources/fields/client.py b/src/webflow/resources/collections/resources/fields/client.py index 40b66cf..c2b7ebc 100644 --- a/src/webflow/resources/collections/resources/fields/client.py +++ b/src/webflow/resources/collections/resources/fields/client.py @@ -2,19 +2,21 @@ import typing from .....core.client_wrapper import SyncClientWrapper -from .types.field_create_type import FieldCreateType +from .....types.field_create import FieldCreate from .....core.request_options import RequestOptions -from .....types.field import Field from .....core.jsonable_encoder import jsonable_encoder +from .....core.serialization import convert_and_respect_annotation_metadata from .....core.pydantic_utilities import parse_obj_as from .....errors.bad_request_error import BadRequestError from .....errors.unauthorized_error import UnauthorizedError from .....types.error import Error from .....errors.not_found_error import NotFoundError +from .....errors.conflict_error import ConflictError from .....errors.too_many_requests_error import TooManyRequestsError from .....errors.internal_server_error import InternalServerError from json.decoder import JSONDecodeError from .....core.api_error import ApiError +from .....types.field import Field from .....core.client_wrapper import AsyncClientWrapper # this is used as the default value for optional parameters @@ -26,24 +28,14 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper def create( - self, - collection_id: str, - *, - type: FieldCreateType, - display_name: str, - is_required: typing.Optional[bool] = OMIT, - help_text: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Field: + self, collection_id: str, *, request: FieldCreate, request_options: typing.Optional[RequestOptions] = None + ) -> FieldCreate: """ Create a custom field in a collection. - Slugs must be all lowercase letters without spaces. - If you pass a string with uppercase letters and/or spaces to the "Slug" property, Webflow will - convert the slug to lowercase and replace spaces with "-." + Field validation is currently not available through the API. - Only some field types can be created through the API. - This endpoint does not currently support bulk creation. + 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` @@ -52,62 +44,49 @@ def create( collection_id : str Unique identifier for a Collection - type : FieldCreateType - Choose these appropriate field type for your collection data - - display_name : str - The name of a field - - is_required : typing.Optional[bool] - define whether a field is required in a collection - - help_text : typing.Optional[str] - Additional text to help anyone filling out this field + request : FieldCreate request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Field + FieldCreate Request was successful Examples -------- - from webflow import Webflow + from webflow import StaticField, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.collections.fields.create( collection_id="580e63fc8c9a982ac9b8b745", - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + 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", + ), ) """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields", + base_url=self._client_wrapper.get_environment().base, method="POST", - json={ - "isRequired": is_required, - "type": type, - "displayName": display_name, - "helpText": help_text, - }, - headers={ - "content-type": "application/json", - }, + json=convert_and_respect_annotation_metadata(object_=request, annotation=FieldCreate, direction="write"), request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: return typing.cast( - Field, + FieldCreate, parse_obj_as( - type_=Field, # type: ignore + type_=FieldCreate, # type: ignore object_=_response.json(), ), ) @@ -141,6 +120,16 @@ def create( ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -203,6 +192,7 @@ def delete( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -321,6 +311,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "isRequired": is_required, @@ -403,24 +394,14 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper async def create( - self, - collection_id: str, - *, - type: FieldCreateType, - display_name: str, - is_required: typing.Optional[bool] = OMIT, - help_text: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Field: + self, collection_id: str, *, request: FieldCreate, request_options: typing.Optional[RequestOptions] = None + ) -> FieldCreate: """ Create a custom field in a collection. - Slugs must be all lowercase letters without spaces. - If you pass a string with uppercase letters and/or spaces to the "Slug" property, Webflow will - convert the slug to lowercase and replace spaces with "-." + Field validation is currently not available through the API. - Only some field types can be created through the API. - This endpoint does not currently support bulk creation. + 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` @@ -429,31 +410,21 @@ async def create( collection_id : str Unique identifier for a Collection - type : FieldCreateType - Choose these appropriate field type for your collection data - - display_name : str - The name of a field - - is_required : typing.Optional[bool] - define whether a field is required in a collection - - help_text : typing.Optional[str] - Additional text to help anyone filling out this field + request : FieldCreate request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Field + FieldCreate Request was successful Examples -------- import asyncio - from webflow import AsyncWebflow + from webflow import AsyncWebflow, StaticField client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -463,10 +434,14 @@ async def create( async def main() -> None: await client.collections.fields.create( collection_id="580e63fc8c9a982ac9b8b745", - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + 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", + ), ) @@ -474,25 +449,18 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields", + base_url=self._client_wrapper.get_environment().base, method="POST", - json={ - "isRequired": is_required, - "type": type, - "displayName": display_name, - "helpText": help_text, - }, - headers={ - "content-type": "application/json", - }, + json=convert_and_respect_annotation_metadata(object_=request, annotation=FieldCreate, direction="write"), request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: return typing.cast( - Field, + FieldCreate, parse_obj_as( - type_=Field, # type: ignore + type_=FieldCreate, # type: ignore object_=_response.json(), ), ) @@ -526,6 +494,16 @@ async def main() -> None: ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -596,6 +574,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -722,6 +701,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "isRequired": is_required, diff --git a/src/webflow/resources/collections/resources/fields/types/__init__.py b/src/webflow/resources/collections/resources/fields/types/__init__.py deleted file mode 100644 index c17230e..0000000 --- a/src/webflow/resources/collections/resources/fields/types/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .field_create_type import FieldCreateType - -__all__ = ["FieldCreateType"] diff --git a/src/webflow/resources/collections/resources/items/__init__.py b/src/webflow/resources/collections/resources/items/__init__.py index fbccd1b..7dce40c 100644 --- a/src/webflow/resources/collections/resources/items/__init__.py +++ b/src/webflow/resources/collections/resources/items/__init__.py @@ -3,15 +3,20 @@ from .types import ( CreateBulkCollectionItemRequestBodyFieldData, CreateBulkCollectionItemRequestBodyFieldDataItem, - ItemsCreateItemLiveRequest, - ItemsCreateItemRequest, + ItemIDs, + ItemIDsWithLocales, + ItemsCreateItemLiveRequestBody, + ItemsCreateItemRequestBody, ItemsDeleteItemsLiveRequestItemsItem, ItemsDeleteItemsRequestItemsItem, ItemsListItemsLiveRequestSortBy, ItemsListItemsLiveRequestSortOrder, ItemsListItemsRequestSortBy, ItemsListItemsRequestSortOrder, + ItemsPublishItemRequest, + ItemsPublishItemRequestItemsItemsItem, ItemsPublishItemResponse, + ItemsUpdateItemsResponse, MultipleItems, MultipleLiveItems, SingleCmsItem, @@ -20,15 +25,20 @@ __all__ = [ "CreateBulkCollectionItemRequestBodyFieldData", "CreateBulkCollectionItemRequestBodyFieldDataItem", - "ItemsCreateItemLiveRequest", - "ItemsCreateItemRequest", + "ItemIDs", + "ItemIDsWithLocales", + "ItemsCreateItemLiveRequestBody", + "ItemsCreateItemRequestBody", "ItemsDeleteItemsLiveRequestItemsItem", "ItemsDeleteItemsRequestItemsItem", "ItemsListItemsLiveRequestSortBy", "ItemsListItemsLiveRequestSortOrder", "ItemsListItemsRequestSortBy", "ItemsListItemsRequestSortOrder", + "ItemsPublishItemRequest", + "ItemsPublishItemRequestItemsItemsItem", "ItemsPublishItemResponse", + "ItemsUpdateItemsResponse", "MultipleItems", "MultipleLiveItems", "SingleCmsItem", diff --git a/src/webflow/resources/collections/resources/items/client.py b/src/webflow/resources/collections/resources/items/client.py index 47f8f90..b53d4df 100644 --- a/src/webflow/resources/collections/resources/items/client.py +++ b/src/webflow/resources/collections/resources/items/client.py @@ -16,20 +16,22 @@ from .....errors.internal_server_error import InternalServerError from json.decoder import JSONDecodeError from .....core.api_error import ApiError -from .types.items_create_item_request import ItemsCreateItemRequest +from .types.items_create_item_request_body import ItemsCreateItemRequestBody from .....types.collection_item import CollectionItem from .....core.serialization import convert_and_respect_annotation_metadata from .types.items_delete_items_request_items_item import ItemsDeleteItemsRequestItemsItem from .....errors.conflict_error import ConflictError from .....types.collection_item_with_id_input import CollectionItemWithIdInput +from .types.items_update_items_response import ItemsUpdateItemsResponse from .types.items_list_items_live_request_sort_by import ItemsListItemsLiveRequestSortBy from .types.items_list_items_live_request_sort_order import ItemsListItemsLiveRequestSortOrder -from .types.items_create_item_live_request import ItemsCreateItemLiveRequest +from .types.items_create_item_live_request_body import ItemsCreateItemLiveRequestBody from .types.items_delete_items_live_request_items_item import ItemsDeleteItemsLiveRequestItemsItem from .....types.collection_item_list_no_pagination import CollectionItemListNoPagination from .types.create_bulk_collection_item_request_body_field_data import CreateBulkCollectionItemRequestBodyFieldData from .....types.bulk_collection_item import BulkCollectionItem from .....types.collection_item_patch_single_field_data import CollectionItemPatchSingleFieldData +from .types.items_publish_item_request import ItemsPublishItemRequest from .types.items_publish_item_response import ItemsPublishItemResponse from .....core.client_wrapper import AsyncClientWrapper @@ -74,10 +76,10 @@ def list_items( Maximum number of records to be returned (max limit: 100) name : typing.Optional[str] - The name of the item(s) + Filter by the exact name of the item(s) slug : typing.Optional[str] - The slug of the item + Filter by the exact slug of the item sort_by : typing.Optional[ItemsListItemsRequestSortBy] Sort results by the provided value @@ -106,6 +108,7 @@ def list_items( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -186,14 +189,15 @@ def create_item( self, collection_id: str, *, - request: ItemsCreateItemRequest, + request: ItemsCreateItemRequestBody, + skip_invalid_files: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItem: """ Create Item(s) in a Collection. - To create items across multiple locales, please use [this endpoint.](/v2.0.0/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` @@ -202,7 +206,10 @@ def create_item( collection_id : str Unique identifier for a Collection - request : ItemsCreateItemRequest + 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. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -237,9 +244,13 @@ def create_item( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="POST", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json=convert_and_respect_annotation_metadata( - object_=request, annotation=ItemsCreateItemRequest, direction="write" + object_=request, annotation=ItemsCreateItemRequestBody, direction="write" ), request_options=request_options, omit=OMIT, @@ -312,13 +323,13 @@ def delete_items( self, collection_id: str, *, - items: typing.Optional[typing.Sequence[ItemsDeleteItemsRequestItemsItem]] = OMIT, + items: typing.Sequence[ItemsDeleteItemsRequestItemsItem], request_options: typing.Optional[RequestOptions] = None, ) -> None: """ Delete Items from a Collection. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be deleted only in the primary locale. + Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -327,7 +338,7 @@ def delete_items( collection_id : str Unique identifier for a Collection - items : typing.Optional[typing.Sequence[ItemsDeleteItemsRequestItemsItem]] + items : typing.Sequence[ItemsDeleteItemsRequestItemsItem] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -339,16 +350,25 @@ def delete_items( Examples -------- from webflow import Webflow + from webflow.resources.collections.resources.items import ( + ItemsDeleteItemsRequestItemsItem, + ) client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.collections.items.delete_items( collection_id="580e63fc8c9a982ac9b8b745", + items=[ + ItemsDeleteItemsRequestItemsItem( + id="580e64008c9a982ac9b8b754", + ) + ], ) """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="DELETE", json={ "items": convert_and_respect_annotation_metadata( @@ -433,13 +453,16 @@ def update_items( self, collection_id: str, *, + skip_invalid_files: typing.Optional[bool] = None, items: typing.Optional[typing.Sequence[CollectionItemWithIdInput]] = OMIT, request_options: typing.Optional[RequestOptions] = None, - ) -> CollectionItem: + ) -> ItemsUpdateItemsResponse: """ - Update a single item or multiple items (up to 100) in a Collection. + Update a single item or multiple items in a Collection. + + The limit for this endpoint is 100 items. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. + Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -448,6 +471,9 @@ def update_items( collection_id : str Unique identifier for a Collection + 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. + items : typing.Optional[typing.Sequence[CollectionItemWithIdInput]] request_options : typing.Optional[RequestOptions] @@ -455,7 +481,7 @@ def update_items( Returns ------- - CollectionItem + ItemsUpdateItemsResponse Request was successful Examples @@ -509,7 +535,11 @@ def update_items( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="PATCH", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json={ "items": convert_and_respect_annotation_metadata( object_=items, annotation=typing.Sequence[CollectionItemWithIdInput], direction="write" @@ -524,9 +554,9 @@ def update_items( try: if 200 <= _response.status_code < 300: return typing.cast( - CollectionItem, + ItemsUpdateItemsResponse, parse_obj_as( - type_=CollectionItem, # type: ignore + type_=ItemsUpdateItemsResponse, # type: ignore object_=_response.json(), ), ) @@ -599,7 +629,12 @@ def list_items_live( request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItemList: """ - List of all live Items within a Collection. + List all published items in a collection. + + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + Required scope | `CMS:read` @@ -618,10 +653,10 @@ def list_items_live( Maximum number of records to be returned (max limit: 100) name : typing.Optional[str] - The name of the item(s) + Filter by the exact name of the item(s) slug : typing.Optional[str] - The slug of the item + Filter by the exact slug of the item sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy] Sort results by the provided value @@ -650,6 +685,7 @@ def list_items_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().data_api, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -730,14 +766,15 @@ def create_item_live( self, collection_id: str, *, - request: ItemsCreateItemLiveRequest, + request: ItemsCreateItemLiveRequestBody, + skip_invalid_files: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItem: """ - Create live Item(s) in a Collection. The Item(s) will be published to the live site. + 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.](/v2.0.0/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` @@ -747,7 +784,10 @@ def create_item_live( collection_id : str Unique identifier for a Collection - request : ItemsCreateItemLiveRequest + 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. @@ -778,9 +818,13 @@ def create_item_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="POST", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json=convert_and_respect_annotation_metadata( - object_=request, annotation=ItemsCreateItemLiveRequest, direction="write" + object_=request, annotation=ItemsCreateItemLiveRequestBody, direction="write" ), request_options=request_options, omit=OMIT, @@ -853,13 +897,13 @@ def delete_items_live( self, collection_id: str, *, - items: typing.Optional[typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem]] = OMIT, + items: typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem], request_options: typing.Optional[RequestOptions] = None, ) -> None: """ - Remove an item or multiple items (up to 100 items) from the live site. Deleting published items will unpublish the items from the live site and set them to draft. + Unpublish up to 100 items from the live site and set the `isDraft` property to `true`. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be unpublished only in the primary locale. + Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -868,7 +912,7 @@ def delete_items_live( collection_id : str Unique identifier for a Collection - items : typing.Optional[typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem]] + items : typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -880,16 +924,25 @@ def delete_items_live( Examples -------- from webflow import Webflow + from webflow.resources.collections.resources.items import ( + ItemsDeleteItemsLiveRequestItemsItem, + ) client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.collections.items.delete_items_live( collection_id="580e63fc8c9a982ac9b8b745", + items=[ + ItemsDeleteItemsLiveRequestItemsItem( + id="580e64008c9a982ac9b8b754", + ) + ], ) """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="DELETE", json={ "items": convert_and_respect_annotation_metadata( @@ -964,13 +1017,14 @@ def update_items_live( self, collection_id: str, *, + skip_invalid_files: typing.Optional[bool] = None, items: typing.Optional[typing.Sequence[CollectionItemWithIdInput]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItemListNoPagination: """ - Update a single live item or multiple live items (up to 100) in a Collection + Update a single published item or multiple published items (up to 100) in a Collection - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. + Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -979,6 +1033,9 @@ def update_items_live( collection_id : str Unique identifier for a Collection + 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. + items : typing.Optional[typing.Sequence[CollectionItemWithIdInput]] request_options : typing.Optional[RequestOptions] @@ -1040,7 +1097,11 @@ def update_items_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="PATCH", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json={ "items": convert_and_respect_annotation_metadata( object_=items, annotation=typing.Sequence[CollectionItemWithIdInput], direction="write" @@ -1091,6 +1152,16 @@ def update_items_live( ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -1121,6 +1192,7 @@ def create_items( collection_id: str, *, field_data: CreateBulkCollectionItemRequestBodyFieldData, + skip_invalid_files: typing.Optional[bool] = None, cms_locale_ids: typing.Optional[typing.Sequence[str]] = OMIT, is_archived: typing.Optional[bool] = OMIT, is_draft: typing.Optional[bool] = OMIT, @@ -1129,9 +1201,10 @@ def create_items( """ Create an item or multiple items in a CMS Collection across multiple corresponding locales. - **Notes:** + - This endpoint can create up to 100 items in a request. - - If the `cmsLocaleIds` parameter is undefined or empty and localization is enabled, items will only be created in the primary locale. + - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale. + Required scope | `CMS:write` @@ -1142,6 +1215,9 @@ def 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.Sequence[str]] Array of identifiers for the locales where the item will be created @@ -1184,7 +1260,11 @@ def create_items( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/bulk", + base_url=self._client_wrapper.get_environment().base, method="POST", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json={ "cmsLocaleIds": cms_locale_ids, "isArchived": is_archived, @@ -1309,6 +1389,7 @@ def get_item( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().production, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -1388,7 +1469,7 @@ def delete_item( request_options: typing.Optional[RequestOptions] = None, ) -> None: """ - Delete an Item from a Collection. This endpoint does not currently support bulk deletion. + Delete an item from a collection. Required scope | `CMS:write` @@ -1424,6 +1505,7 @@ def delete_item( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", params={ "cmsLocaleId": cms_locale_id, @@ -1493,6 +1575,7 @@ def update_item( collection_id: str, item_id: str, *, + skip_invalid_files: typing.Optional[bool] = None, id: typing.Optional[str] = OMIT, cms_locale_id: typing.Optional[str] = OMIT, last_published: typing.Optional[str] = OMIT, @@ -1516,6 +1599,9 @@ def update_item( item_id : str Unique identifier for an 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. + id : typing.Optional[str] Unique identifier for the Item @@ -1567,7 +1653,11 @@ def update_item( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json={ "id": id, "cmsLocaleId": cms_locale_id, @@ -1658,6 +1748,11 @@ def get_item_live( """ Get details of a selected Collection live Item. + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + + Required scope | `CMS:read` Parameters @@ -1693,6 +1788,7 @@ def get_item_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().data_api, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -1772,9 +1868,9 @@ def delete_item_live( request_options: typing.Optional[RequestOptions] = None, ) -> None: """ - Remove a live item from the site. Removing a published item will unpublish the item from the live site and set it to draft. + Unpublish a live item from the site and set the `isDraft` property to `true`. - This endpoint does not currently support bulk deletion. + For bulk unpublishing, please use [this endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live) Required scope | `CMS:write` @@ -1810,6 +1906,7 @@ def delete_item_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().base, method="DELETE", params={ "cmsLocaleId": cms_locale_id, @@ -1879,6 +1976,7 @@ def update_item_live( collection_id: str, item_id: str, *, + skip_invalid_files: typing.Optional[bool] = None, id: typing.Optional[str] = OMIT, cms_locale_id: typing.Optional[str] = OMIT, last_published: typing.Optional[str] = OMIT, @@ -1902,6 +2000,9 @@ def update_item_live( item_id : str Unique identifier for an 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. + id : typing.Optional[str] Unique identifier for the Item @@ -1953,7 +2054,11 @@ def update_item_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().base, method="PATCH", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json={ "id": id, "cmsLocaleId": cms_locale_id, @@ -2008,6 +2113,16 @@ def update_item_live( ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -2037,7 +2152,7 @@ def publish_item( self, collection_id: str, *, - item_ids: typing.Sequence[str], + request: ItemsPublishItemRequest, request_options: typing.Optional[RequestOptions] = None, ) -> ItemsPublishItemResponse: """ @@ -2050,7 +2165,7 @@ def publish_item( collection_id : str Unique identifier for a Collection - item_ids : typing.Sequence[str] + request : ItemsPublishItemRequest request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -2063,24 +2178,29 @@ def publish_item( Examples -------- from webflow import Webflow + from webflow.resources.collections.resources.items import ItemIDs client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.collections.items.publish_item( collection_id="580e63fc8c9a982ac9b8b745", - item_ids=["itemIds"], + request=ItemIDs( + item_ids=[ + "643fd856d66b6528195ee2ca", + "643fd856d66b6528195ee2cb", + "643fd856d66b6528195ee2cc", + ], + ), ) """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/publish", + base_url=self._client_wrapper.get_environment().base, method="POST", - json={ - "itemIds": item_ids, - }, - headers={ - "content-type": "application/json", - }, + json=convert_and_respect_annotation_metadata( + object_=request, annotation=ItemsPublishItemRequest, direction="write" + ), request_options=request_options, omit=OMIT, ) @@ -2196,10 +2316,10 @@ async def list_items( Maximum number of records to be returned (max limit: 100) name : typing.Optional[str] - The name of the item(s) + Filter by the exact name of the item(s) slug : typing.Optional[str] - The slug of the item + Filter by the exact slug of the item sort_by : typing.Optional[ItemsListItemsRequestSortBy] Sort results by the provided value @@ -2236,6 +2356,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -2316,14 +2437,15 @@ async def create_item( self, collection_id: str, *, - request: ItemsCreateItemRequest, + request: ItemsCreateItemRequestBody, + skip_invalid_files: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItem: """ Create Item(s) in a Collection. - To create items across multiple locales, please use [this endpoint.](/v2.0.0/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` @@ -2332,7 +2454,10 @@ async def create_item( collection_id : str Unique identifier for a Collection - request : ItemsCreateItemRequest + 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. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -2375,9 +2500,13 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="POST", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json=convert_and_respect_annotation_metadata( - object_=request, annotation=ItemsCreateItemRequest, direction="write" + object_=request, annotation=ItemsCreateItemRequestBody, direction="write" ), request_options=request_options, omit=OMIT, @@ -2450,13 +2579,13 @@ async def delete_items( self, collection_id: str, *, - items: typing.Optional[typing.Sequence[ItemsDeleteItemsRequestItemsItem]] = OMIT, + items: typing.Sequence[ItemsDeleteItemsRequestItemsItem], request_options: typing.Optional[RequestOptions] = None, ) -> None: """ Delete Items from a Collection. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be deleted only in the primary locale. + Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -2465,7 +2594,7 @@ async def delete_items( collection_id : str Unique identifier for a Collection - items : typing.Optional[typing.Sequence[ItemsDeleteItemsRequestItemsItem]] + items : typing.Sequence[ItemsDeleteItemsRequestItemsItem] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -2479,6 +2608,9 @@ async def delete_items( import asyncio from webflow import AsyncWebflow + from webflow.resources.collections.resources.items import ( + ItemsDeleteItemsRequestItemsItem, + ) client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -2488,6 +2620,11 @@ async def delete_items( async def main() -> None: await client.collections.items.delete_items( collection_id="580e63fc8c9a982ac9b8b745", + items=[ + ItemsDeleteItemsRequestItemsItem( + id="580e64008c9a982ac9b8b754", + ) + ], ) @@ -2495,6 +2632,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="DELETE", json={ "items": convert_and_respect_annotation_metadata( @@ -2579,13 +2717,16 @@ async def update_items( self, collection_id: str, *, + skip_invalid_files: typing.Optional[bool] = None, items: typing.Optional[typing.Sequence[CollectionItemWithIdInput]] = OMIT, request_options: typing.Optional[RequestOptions] = None, - ) -> CollectionItem: + ) -> ItemsUpdateItemsResponse: """ - Update a single item or multiple items (up to 100) in a Collection. + Update a single item or multiple items in a Collection. + + The limit for this endpoint is 100 items. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. + Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -2594,6 +2735,9 @@ async def update_items( collection_id : str Unique identifier for a Collection + 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. + items : typing.Optional[typing.Sequence[CollectionItemWithIdInput]] request_options : typing.Optional[RequestOptions] @@ -2601,7 +2745,7 @@ async def update_items( Returns ------- - CollectionItem + ItemsUpdateItemsResponse Request was successful Examples @@ -2663,7 +2807,11 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="PATCH", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json={ "items": convert_and_respect_annotation_metadata( object_=items, annotation=typing.Sequence[CollectionItemWithIdInput], direction="write" @@ -2678,9 +2826,9 @@ async def main() -> None: try: if 200 <= _response.status_code < 300: return typing.cast( - CollectionItem, + ItemsUpdateItemsResponse, parse_obj_as( - type_=CollectionItem, # type: ignore + type_=ItemsUpdateItemsResponse, # type: ignore object_=_response.json(), ), ) @@ -2753,7 +2901,12 @@ async def list_items_live( request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItemList: """ - List of all live Items within a Collection. + List all published items in a collection. + + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + Required scope | `CMS:read` @@ -2772,10 +2925,10 @@ async def list_items_live( Maximum number of records to be returned (max limit: 100) name : typing.Optional[str] - The name of the item(s) + Filter by the exact name of the item(s) slug : typing.Optional[str] - The slug of the item + Filter by the exact slug of the item sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy] Sort results by the provided value @@ -2812,6 +2965,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().data_api, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -2892,14 +3046,15 @@ async def create_item_live( self, collection_id: str, *, - request: ItemsCreateItemLiveRequest, + request: ItemsCreateItemLiveRequestBody, + skip_invalid_files: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItem: """ - Create live Item(s) in a Collection. The Item(s) will be published to the live site. + 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.](/v2.0.0/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` @@ -2909,7 +3064,10 @@ async def create_item_live( collection_id : str Unique identifier for a Collection - request : ItemsCreateItemLiveRequest + 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. @@ -2948,9 +3106,13 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="POST", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json=convert_and_respect_annotation_metadata( - object_=request, annotation=ItemsCreateItemLiveRequest, direction="write" + object_=request, annotation=ItemsCreateItemLiveRequestBody, direction="write" ), request_options=request_options, omit=OMIT, @@ -3023,13 +3185,13 @@ async def delete_items_live( self, collection_id: str, *, - items: typing.Optional[typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem]] = OMIT, + items: typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem], request_options: typing.Optional[RequestOptions] = None, ) -> None: """ - Remove an item or multiple items (up to 100 items) from the live site. Deleting published items will unpublish the items from the live site and set them to draft. + Unpublish up to 100 items from the live site and set the `isDraft` property to `true`. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be unpublished only in the primary locale. + Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -3038,7 +3200,7 @@ async def delete_items_live( collection_id : str Unique identifier for a Collection - items : typing.Optional[typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem]] + items : typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -3052,6 +3214,9 @@ async def delete_items_live( import asyncio from webflow import AsyncWebflow + from webflow.resources.collections.resources.items import ( + ItemsDeleteItemsLiveRequestItemsItem, + ) client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -3061,6 +3226,11 @@ async def delete_items_live( async def main() -> None: await client.collections.items.delete_items_live( collection_id="580e63fc8c9a982ac9b8b745", + items=[ + ItemsDeleteItemsLiveRequestItemsItem( + id="580e64008c9a982ac9b8b754", + ) + ], ) @@ -3068,6 +3238,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="DELETE", json={ "items": convert_and_respect_annotation_metadata( @@ -3142,13 +3313,14 @@ async def update_items_live( self, collection_id: str, *, + skip_invalid_files: typing.Optional[bool] = None, items: typing.Optional[typing.Sequence[CollectionItemWithIdInput]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItemListNoPagination: """ - Update a single live item or multiple live items (up to 100) in a Collection + Update a single published item or multiple published items (up to 100) in a Collection - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. + Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -3157,6 +3329,9 @@ async def update_items_live( collection_id : str Unique identifier for a Collection + 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. + items : typing.Optional[typing.Sequence[CollectionItemWithIdInput]] request_options : typing.Optional[RequestOptions] @@ -3226,7 +3401,11 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="PATCH", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json={ "items": convert_and_respect_annotation_metadata( object_=items, annotation=typing.Sequence[CollectionItemWithIdInput], direction="write" @@ -3277,6 +3456,16 @@ async def main() -> None: ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -3307,6 +3496,7 @@ async def create_items( collection_id: str, *, field_data: CreateBulkCollectionItemRequestBodyFieldData, + skip_invalid_files: typing.Optional[bool] = None, cms_locale_ids: typing.Optional[typing.Sequence[str]] = OMIT, is_archived: typing.Optional[bool] = OMIT, is_draft: typing.Optional[bool] = OMIT, @@ -3315,9 +3505,10 @@ async def create_items( """ Create an item or multiple items in a CMS Collection across multiple corresponding locales. - **Notes:** + - This endpoint can create up to 100 items in a request. - - If the `cmsLocaleIds` parameter is undefined or empty and localization is enabled, items will only be created in the primary locale. + - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale. + Required scope | `CMS:write` @@ -3328,6 +3519,9 @@ async def 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.Sequence[str]] Array of identifiers for the locales where the item will be created @@ -3378,7 +3572,11 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/bulk", + base_url=self._client_wrapper.get_environment().base, method="POST", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json={ "cmsLocaleIds": cms_locale_ids, "isArchived": is_archived, @@ -3511,6 +3709,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().production, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -3590,7 +3789,7 @@ async def delete_item( request_options: typing.Optional[RequestOptions] = None, ) -> None: """ - Delete an Item from a Collection. This endpoint does not currently support bulk deletion. + Delete an item from a collection. Required scope | `CMS:write` @@ -3634,6 +3833,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", params={ "cmsLocaleId": cms_locale_id, @@ -3703,6 +3903,7 @@ async def update_item( collection_id: str, item_id: str, *, + skip_invalid_files: typing.Optional[bool] = None, id: typing.Optional[str] = OMIT, cms_locale_id: typing.Optional[str] = OMIT, last_published: typing.Optional[str] = OMIT, @@ -3726,6 +3927,9 @@ async def update_item( item_id : str Unique identifier for an 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. + id : typing.Optional[str] Unique identifier for the Item @@ -3785,7 +3989,11 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json={ "id": id, "cmsLocaleId": cms_locale_id, @@ -3876,6 +4084,11 @@ async def get_item_live( """ Get details of a selected Collection live Item. + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + + Required scope | `CMS:read` Parameters @@ -3919,6 +4132,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().data_api, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -3998,9 +4212,9 @@ async def delete_item_live( request_options: typing.Optional[RequestOptions] = None, ) -> None: """ - Remove a live item from the site. Removing a published item will unpublish the item from the live site and set it to draft. + Unpublish a live item from the site and set the `isDraft` property to `true`. - This endpoint does not currently support bulk deletion. + For bulk unpublishing, please use [this endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live) Required scope | `CMS:write` @@ -4044,6 +4258,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().base, method="DELETE", params={ "cmsLocaleId": cms_locale_id, @@ -4113,6 +4328,7 @@ async def update_item_live( collection_id: str, item_id: str, *, + skip_invalid_files: typing.Optional[bool] = None, id: typing.Optional[str] = OMIT, cms_locale_id: typing.Optional[str] = OMIT, last_published: typing.Optional[str] = OMIT, @@ -4136,6 +4352,9 @@ async def update_item_live( item_id : str Unique identifier for an 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. + id : typing.Optional[str] Unique identifier for the Item @@ -4195,7 +4414,11 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().base, method="PATCH", + params={ + "skipInvalidFiles": skip_invalid_files, + }, json={ "id": id, "cmsLocaleId": cms_locale_id, @@ -4250,6 +4473,16 @@ async def main() -> None: ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -4279,7 +4512,7 @@ async def publish_item( self, collection_id: str, *, - item_ids: typing.Sequence[str], + request: ItemsPublishItemRequest, request_options: typing.Optional[RequestOptions] = None, ) -> ItemsPublishItemResponse: """ @@ -4292,7 +4525,7 @@ async def publish_item( collection_id : str Unique identifier for a Collection - item_ids : typing.Sequence[str] + request : ItemsPublishItemRequest request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -4307,6 +4540,7 @@ async def publish_item( import asyncio from webflow import AsyncWebflow + from webflow.resources.collections.resources.items import ItemIDs client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -4316,7 +4550,13 @@ async def publish_item( async def main() -> None: await client.collections.items.publish_item( collection_id="580e63fc8c9a982ac9b8b745", - item_ids=["itemIds"], + request=ItemIDs( + item_ids=[ + "643fd856d66b6528195ee2ca", + "643fd856d66b6528195ee2cb", + "643fd856d66b6528195ee2cc", + ], + ), ) @@ -4324,13 +4564,11 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/publish", + base_url=self._client_wrapper.get_environment().base, method="POST", - json={ - "itemIds": item_ids, - }, - headers={ - "content-type": "application/json", - }, + json=convert_and_respect_annotation_metadata( + object_=request, annotation=ItemsPublishItemRequest, direction="write" + ), request_options=request_options, omit=OMIT, ) diff --git a/src/webflow/resources/collections/resources/items/types/__init__.py b/src/webflow/resources/collections/resources/items/types/__init__.py index 67040fb..2d9a604 100644 --- a/src/webflow/resources/collections/resources/items/types/__init__.py +++ b/src/webflow/resources/collections/resources/items/types/__init__.py @@ -2,15 +2,20 @@ from .create_bulk_collection_item_request_body_field_data import CreateBulkCollectionItemRequestBodyFieldData from .create_bulk_collection_item_request_body_field_data_item import CreateBulkCollectionItemRequestBodyFieldDataItem -from .items_create_item_live_request import ItemsCreateItemLiveRequest -from .items_create_item_request import ItemsCreateItemRequest +from .item_i_ds import ItemIDs +from .item_i_ds_with_locales import ItemIDsWithLocales +from .items_create_item_live_request_body import ItemsCreateItemLiveRequestBody +from .items_create_item_request_body import ItemsCreateItemRequestBody from .items_delete_items_live_request_items_item import ItemsDeleteItemsLiveRequestItemsItem from .items_delete_items_request_items_item import ItemsDeleteItemsRequestItemsItem from .items_list_items_live_request_sort_by import ItemsListItemsLiveRequestSortBy from .items_list_items_live_request_sort_order import ItemsListItemsLiveRequestSortOrder from .items_list_items_request_sort_by import ItemsListItemsRequestSortBy from .items_list_items_request_sort_order import ItemsListItemsRequestSortOrder +from .items_publish_item_request import ItemsPublishItemRequest +from .items_publish_item_request_items_items_item import ItemsPublishItemRequestItemsItemsItem from .items_publish_item_response import ItemsPublishItemResponse +from .items_update_items_response import ItemsUpdateItemsResponse from .multiple_items import MultipleItems from .multiple_live_items import MultipleLiveItems from .single_cms_item import SingleCmsItem @@ -18,15 +23,20 @@ __all__ = [ "CreateBulkCollectionItemRequestBodyFieldData", "CreateBulkCollectionItemRequestBodyFieldDataItem", - "ItemsCreateItemLiveRequest", - "ItemsCreateItemRequest", + "ItemIDs", + "ItemIDsWithLocales", + "ItemsCreateItemLiveRequestBody", + "ItemsCreateItemRequestBody", "ItemsDeleteItemsLiveRequestItemsItem", "ItemsDeleteItemsRequestItemsItem", "ItemsListItemsLiveRequestSortBy", "ItemsListItemsLiveRequestSortOrder", "ItemsListItemsRequestSortBy", "ItemsListItemsRequestSortOrder", + "ItemsPublishItemRequest", + "ItemsPublishItemRequestItemsItemsItem", "ItemsPublishItemResponse", + "ItemsUpdateItemsResponse", "MultipleItems", "MultipleLiveItems", "SingleCmsItem", diff --git a/src/webflow/resources/collections/resources/items/types/item_i_ds.py b/src/webflow/resources/collections/resources/items/types/item_i_ds.py new file mode 100644 index 0000000..b9b138e --- /dev/null +++ b/src/webflow/resources/collections/resources/items/types/item_i_ds.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +from ......core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from ......core.serialization import FieldMetadata +from ......core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ItemIDs(UniversalBaseModel): + """ + An array of Item IDs in a single locale + """ + + item_ids: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="itemIds")] = 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/resources/collections/resources/items/types/item_i_ds_with_locales.py b/src/webflow/resources/collections/resources/items/types/item_i_ds_with_locales.py new file mode 100644 index 0000000..ba98ae7 --- /dev/null +++ b/src/webflow/resources/collections/resources/items/types/item_i_ds_with_locales.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +from ......core.pydantic_utilities import UniversalBaseModel +import typing +from .items_publish_item_request_items_items_item import ItemsPublishItemRequestItemsItemsItem +from ......core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ItemIDsWithLocales(UniversalBaseModel): + """ + An array of Item IDs with included `cmsLocaleIds` + """ + + items: typing.Optional[typing.List[ItemsPublishItemRequestItemsItemsItem]] = 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/resources/collections/resources/items/types/items_create_item_live_request.py b/src/webflow/resources/collections/resources/items/types/items_create_item_live_request_body.py similarity index 69% rename from src/webflow/resources/collections/resources/items/types/items_create_item_live_request.py rename to src/webflow/resources/collections/resources/items/types/items_create_item_live_request_body.py index dc2f963..348e0be 100644 --- a/src/webflow/resources/collections/resources/items/types/items_create_item_live_request.py +++ b/src/webflow/resources/collections/resources/items/types/items_create_item_live_request_body.py @@ -4,4 +4,4 @@ from ......types.collection_item import CollectionItem from .multiple_live_items import MultipleLiveItems -ItemsCreateItemLiveRequest = typing.Union[CollectionItem, MultipleLiveItems] +ItemsCreateItemLiveRequestBody = typing.Union[CollectionItem, MultipleLiveItems] diff --git a/src/webflow/resources/collections/resources/items/types/items_create_item_request.py b/src/webflow/resources/collections/resources/items/types/items_create_item_request_body.py similarity index 70% rename from src/webflow/resources/collections/resources/items/types/items_create_item_request.py rename to src/webflow/resources/collections/resources/items/types/items_create_item_request_body.py index 7627c55..af4860a 100644 --- a/src/webflow/resources/collections/resources/items/types/items_create_item_request.py +++ b/src/webflow/resources/collections/resources/items/types/items_create_item_request_body.py @@ -4,4 +4,4 @@ from ......types.collection_item_post_single import CollectionItemPostSingle from .multiple_items import MultipleItems -ItemsCreateItemRequest = typing.Union[CollectionItemPostSingle, MultipleItems] +ItemsCreateItemRequestBody = typing.Union[CollectionItemPostSingle, MultipleItems] diff --git a/src/webflow/resources/collections/resources/items/types/items_delete_items_live_request_items_item.py b/src/webflow/resources/collections/resources/items/types/items_delete_items_live_request_items_item.py index 63e00bc..544df88 100644 --- a/src/webflow/resources/collections/resources/items/types/items_delete_items_live_request_items_item.py +++ b/src/webflow/resources/collections/resources/items/types/items_delete_items_live_request_items_item.py @@ -1,15 +1,15 @@ # This file was auto-generated by Fern from our API Definition. from ......core.pydantic_utilities import UniversalBaseModel -import typing_extensions -from ......core.serialization import FieldMetadata import pydantic +import typing_extensions import typing +from ......core.serialization import FieldMetadata from ......core.pydantic_utilities import IS_PYDANTIC_V2 class ItemsDeleteItemsLiveRequestItemsItem(UniversalBaseModel): - item_id: typing_extensions.Annotated[str, FieldMetadata(alias="itemId")] = pydantic.Field() + id: str = pydantic.Field() """ Unique identifier for the Item """ diff --git a/src/webflow/resources/collections/resources/items/types/items_publish_item_request.py b/src/webflow/resources/collections/resources/items/types/items_publish_item_request.py new file mode 100644 index 0000000..4f7a82b --- /dev/null +++ b/src/webflow/resources/collections/resources/items/types/items_publish_item_request.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from .item_i_ds import ItemIDs +from .item_i_ds_with_locales import ItemIDsWithLocales + +ItemsPublishItemRequest = typing.Union[ItemIDs, ItemIDsWithLocales] diff --git a/src/webflow/resources/collections/resources/items/types/items_publish_item_request_items_items_item.py b/src/webflow/resources/collections/resources/items/types/items_publish_item_request_items_items_item.py new file mode 100644 index 0000000..08b2e17 --- /dev/null +++ b/src/webflow/resources/collections/resources/items/types/items_publish_item_request_items_items_item.py @@ -0,0 +1,31 @@ +# This file was auto-generated by Fern from our API Definition. + +from ......core.pydantic_utilities import UniversalBaseModel +import pydantic +import typing_extensions +import typing +from ......core.serialization import FieldMetadata +from ......core.pydantic_utilities import IS_PYDANTIC_V2 + + +class ItemsPublishItemRequestItemsItemsItem(UniversalBaseModel): + id: str = pydantic.Field() + """ + The ID of the CMS item + """ + + cms_locale_ids: typing_extensions.Annotated[ + typing.Optional[typing.List[str]], FieldMetadata(alias="cmsLocaleIds") + ] = pydantic.Field(default=None) + """ + Array of identifiers for the locales where the item will be published + """ + + 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/collections/resources/items/types/items_update_items_response.py b/src/webflow/resources/collections/resources/items/types/items_update_items_response.py new file mode 100644 index 0000000..c073f18 --- /dev/null +++ b/src/webflow/resources/collections/resources/items/types/items_update_items_response.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from ......types.collection_item import CollectionItem +from ......types.collection_item_list import CollectionItemList + +ItemsUpdateItemsResponse = typing.Union[CollectionItem, CollectionItemList] diff --git a/src/webflow/resources/components/client.py b/src/webflow/resources/components/client.py index ef50ac9..abd7331 100644 --- a/src/webflow/resources/components/client.py +++ b/src/webflow/resources/components/client.py @@ -77,6 +77,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, @@ -159,7 +160,7 @@ def get_content( request_options: typing.Optional[RequestOptions] = None, ) -> ComponentDom: """ - Get static content from a component definition. This includes text nodes, image nodes and nested component instances. + Get static content from a component definition. This includes text nodes, image nodes, select nodes, text input nodes, submit button nodes, and nested component instances. To retrieve dynamic content set by component properties, use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint. If you do not provide a Locale ID in your request, the response will return any content that can be localized from the Primary locale. @@ -206,6 +207,7 @@ def get_content( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -325,9 +327,13 @@ def update_content( Examples -------- from webflow import ( - ComponentInstanceNodePropertyOverridesWrite, + ComponentInstance, ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem, - TextNodeWrite, + Select, + SelectNodeWriteChoicesItem, + SubmitButton, + TextInput, + TextNode, Webflow, ) @@ -339,15 +345,37 @@ def update_content( component_id="8505ba55-ef72-629e-f85c-33e4b703d48b", locale_id="65427cf400e02b306eaa04a0", nodes=[ - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623", text="

The Hitchhiker's Guide to the Galaxy

", ), - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627", text="

Don't Panic!

Always know where your towel is.

", ), - ComponentInstanceNodePropertyOverridesWrite( + Select( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635", + choices=[ + SelectNodeWriteChoicesItem( + value="choice-1", + text="First choice", + ), + SelectNodeWriteChoicesItem( + value="choice-2", + text="Second choice", + ), + ], + ), + TextInput( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642", + placeholder="Enter something here...", + ), + SubmitButton( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671", + value="Submit", + waiting_text="Submitting...", + ), + ComponentInstance( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629", property_overrides=[ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem( @@ -365,6 +393,7 @@ def update_content( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, @@ -465,9 +494,9 @@ def get_properties( request_options: typing.Optional[RequestOptions] = None, ) -> ComponentProperties: """ - Get the property default values of a component definition. + Get the default property values of a component definition. - If you do not provide a Locale ID in your request, the response will return any properties that can be localized from the Primary locale. + If you do not include a `localeId` in your request, the response will return any properties that can be localized from the Primary locale. Required scope | `components:read` @@ -511,6 +540,7 @@ def get_properties( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/properties", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -593,12 +623,11 @@ def update_properties( request_options: typing.Optional[RequestOptions] = None, ) -> ComponentsUpdatePropertiesResponse: """ - Update the property default values of a component definition in a specificed locale. + Update the default property values of a component definition in a specificed locale. - Before making updates: - 1. Use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify available properties + Before making updates, use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify properties that can be updated in a secondary locale. - The request requires a secondary locale ID. If a locale is missing, the request will not be processed and will result in an error. + The request requires a secondary locale ID. If a `localeId` is missing, the request will not be processed and will result in an error. Required scope | `components:write` @@ -650,6 +679,7 @@ def update_properties( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/properties", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, @@ -789,6 +819,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, @@ -871,7 +902,7 @@ async def get_content( request_options: typing.Optional[RequestOptions] = None, ) -> ComponentDom: """ - Get static content from a component definition. This includes text nodes, image nodes and nested component instances. + Get static content from a component definition. This includes text nodes, image nodes, select nodes, text input nodes, submit button nodes, and nested component instances. To retrieve dynamic content set by component properties, use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint. If you do not provide a Locale ID in your request, the response will return any content that can be localized from the Primary locale. @@ -926,6 +957,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -1048,9 +1080,13 @@ async def update_content( from webflow import ( AsyncWebflow, - ComponentInstanceNodePropertyOverridesWrite, + ComponentInstance, ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem, - TextNodeWrite, + Select, + SelectNodeWriteChoicesItem, + SubmitButton, + TextInput, + TextNode, ) client = AsyncWebflow( @@ -1064,15 +1100,37 @@ async def main() -> None: component_id="8505ba55-ef72-629e-f85c-33e4b703d48b", locale_id="65427cf400e02b306eaa04a0", nodes=[ - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623", text="

The Hitchhiker's Guide to the Galaxy

", ), - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627", text="

Don't Panic!

Always know where your towel is.

", ), - ComponentInstanceNodePropertyOverridesWrite( + Select( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635", + choices=[ + SelectNodeWriteChoicesItem( + value="choice-1", + text="First choice", + ), + SelectNodeWriteChoicesItem( + value="choice-2", + text="Second choice", + ), + ], + ), + TextInput( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642", + placeholder="Enter something here...", + ), + SubmitButton( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671", + value="Submit", + waiting_text="Submitting...", + ), + ComponentInstance( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629", property_overrides=[ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem( @@ -1093,6 +1151,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, @@ -1193,9 +1252,9 @@ async def get_properties( request_options: typing.Optional[RequestOptions] = None, ) -> ComponentProperties: """ - Get the property default values of a component definition. + Get the default property values of a component definition. - If you do not provide a Locale ID in your request, the response will return any properties that can be localized from the Primary locale. + If you do not include a `localeId` in your request, the response will return any properties that can be localized from the Primary locale. Required scope | `components:read` @@ -1247,6 +1306,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/properties", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -1329,12 +1389,11 @@ async def update_properties( request_options: typing.Optional[RequestOptions] = None, ) -> ComponentsUpdatePropertiesResponse: """ - Update the property default values of a component definition in a specificed locale. + Update the default property values of a component definition in a specificed locale. - Before making updates: - 1. Use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify available properties + Before making updates, use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify properties that can be updated in a secondary locale. - The request requires a secondary locale ID. If a locale is missing, the request will not be processed and will result in an error. + The request requires a secondary locale ID. If a `localeId` is missing, the request will not be processed and will result in an error. Required scope | `components:write` @@ -1394,6 +1453,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/properties", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, diff --git a/src/webflow/resources/components/types/component_dom_write_nodes_item.py b/src/webflow/resources/components/types/component_dom_write_nodes_item.py index 27888e6..7bc7435 100644 --- a/src/webflow/resources/components/types/component_dom_write_nodes_item.py +++ b/src/webflow/resources/components/types/component_dom_write_nodes_item.py @@ -1,7 +1,11 @@ # This file was auto-generated by Fern from our API Definition. import typing -from ....types.text_node_write import TextNodeWrite -from ....types.component_instance_node_property_overrides_write import ComponentInstanceNodePropertyOverridesWrite +from ....types.text_node import TextNode +from ....types.component_instance import ComponentInstance +from ....types.select import Select +from ....types.text_input import TextInput +from ....types.submit_button import SubmitButton +from ....types.search_button import SearchButton -ComponentDomWriteNodesItem = typing.Union[TextNodeWrite, ComponentInstanceNodePropertyOverridesWrite] +ComponentDomWriteNodesItem = typing.Union[TextNode, ComponentInstance, Select, TextInput, SubmitButton, SearchButton] diff --git a/src/webflow/resources/ecommerce/client.py b/src/webflow/resources/ecommerce/client.py index bbd3a5d..04ddba6 100644 --- a/src/webflow/resources/ecommerce/client.py +++ b/src/webflow/resources/ecommerce/client.py @@ -57,6 +57,7 @@ def get_settings( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/ecommerce/settings", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -191,6 +192,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/ecommerce/settings", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) diff --git a/src/webflow/resources/forms/client.py b/src/webflow/resources/forms/client.py index 515b631..05b3da5 100644 --- a/src/webflow/resources/forms/client.py +++ b/src/webflow/resources/forms/client.py @@ -74,6 +74,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/forms", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, @@ -197,6 +198,7 @@ def get(self, form_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"forms/{jsonable_encoder(form_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -285,6 +287,12 @@ def list_submissions( """ 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` Parameters @@ -319,6 +327,7 @@ def list_submissions( """ _response = self._client_wrapper.httpx_client.request( f"forms/{jsonable_encoder(form_id)}/submissions", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -434,6 +443,7 @@ def get_submission( """ _response = self._client_wrapper.httpx_client.request( f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -511,6 +521,122 @@ def get_submission( raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + def delete_submission( + self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Delete a form submission + + + Required scope | `forms:write` + + Parameters + ---------- + form_submission_id : str + Unique identifier for a Form Submission + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.forms.delete_submission( + form_submission_id="580e63e98c9a982ac9b8b741", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + def update_submission( self, form_submission_id: str, @@ -552,6 +678,7 @@ def update_submission( """ _response = self._client_wrapper.httpx_client.request( f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "formSubmissionData": form_submission_data, @@ -646,6 +773,141 @@ def update_submission( raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + def list_submissions_by_site( + self, + site_id: str, + *, + element_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> FormSubmissionList: + """ + List form submissions for a given site. This endpoint differs from the existing [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) by accepting `siteId` as a path parameter and `elementId` as a query parameter. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list). + + + + Required scope | `forms:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + element_id : typing.Optional[str] + Identifier for an element + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + FormSubmissionList + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.forms.list_submissions_by_site( + site_id="580e63e98c9a982ac9b8b741", + element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/form_submissions", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "elementId": element_id, + "offset": offset, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + FormSubmissionList, + parse_obj_as( + type_=FormSubmissionList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + class AsyncFormsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): @@ -704,6 +966,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/forms", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, @@ -835,6 +1098,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"forms/{jsonable_encoder(form_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -923,6 +1187,12 @@ async def list_submissions( """ 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` Parameters @@ -965,6 +1235,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"forms/{jsonable_encoder(form_id)}/submissions", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -1088,6 +1359,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1165,6 +1437,130 @@ async def main() -> None: raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + async def delete_submission( + self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Delete a form submission + + + Required scope | `forms:write` + + Parameters + ---------- + form_submission_id : str + Unique identifier for a Form Submission + + 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.forms.delete_submission( + form_submission_id="580e63e98c9a982ac9b8b741", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + async def update_submission( self, form_submission_id: str, @@ -1214,6 +1610,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "formSubmissionData": form_submission_data, @@ -1307,3 +1704,146 @@ async def main() -> None: except JSONDecodeError: raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + + async def list_submissions_by_site( + self, + site_id: str, + *, + element_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> FormSubmissionList: + """ + List form submissions for a given site. This endpoint differs from the existing [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) by accepting `siteId` as a path parameter and `elementId` as a query parameter. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list). + + + + Required scope | `forms:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + element_id : typing.Optional[str] + Identifier for an element + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + FormSubmissionList + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.forms.list_submissions_by_site( + site_id="580e63e98c9a982ac9b8b741", + element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/form_submissions", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "elementId": element_id, + "offset": offset, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + FormSubmissionList, + parse_obj_as( + type_=FormSubmissionList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/webflow/resources/inventory/client.py b/src/webflow/resources/inventory/client.py index 27e4f3c..4f51334 100644 --- a/src/webflow/resources/inventory/client.py +++ b/src/webflow/resources/inventory/client.py @@ -65,6 +65,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -211,6 +212,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "inventoryType": inventory_type, @@ -358,6 +360,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -512,6 +515,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "inventoryType": inventory_type, diff --git a/src/webflow/resources/orders/client.py b/src/webflow/resources/orders/client.py index 4aa4b77..9b79918 100644 --- a/src/webflow/resources/orders/client.py +++ b/src/webflow/resources/orders/client.py @@ -78,6 +78,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "status": status, @@ -207,6 +208,7 @@ def get(self, site_id: str, order_id: str, *, request_options: typing.Optional[R """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -354,6 +356,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "comment": comment, @@ -497,6 +500,7 @@ def update_fulfill( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/fulfill", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "sendOrderFulfilledEmail": send_order_fulfilled_email, @@ -629,6 +633,7 @@ def update_unfulfill( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/unfulfill", + base_url=self._client_wrapper.get_environment().base, method="POST", request_options=request_options, ) @@ -763,6 +768,7 @@ def refund( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/refund", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "reason": reason, @@ -919,6 +925,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "status": status, @@ -1058,6 +1065,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1213,6 +1221,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "comment": comment, @@ -1364,6 +1373,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/fulfill", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "sendOrderFulfilledEmail": send_order_fulfilled_email, @@ -1504,6 +1514,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/unfulfill", + base_url=self._client_wrapper.get_environment().base, method="POST", request_options=request_options, ) @@ -1646,6 +1657,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/refund", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "reason": reason, diff --git a/src/webflow/resources/pages/client.py b/src/webflow/resources/pages/client.py index 851f4e7..40b5208 100644 --- a/src/webflow/resources/pages/client.py +++ b/src/webflow/resources/pages/client.py @@ -86,6 +86,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/pages", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -200,6 +201,7 @@ def get_metadata( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -274,8 +276,8 @@ def update_page_settings( self, page_id: str, *, - id: str, locale_id: typing.Optional[str] = None, + id: typing.Optional[str] = OMIT, site_id: typing.Optional[str] = OMIT, title: typing.Optional[str] = OMIT, slug: typing.Optional[str] = OMIT, @@ -287,7 +289,6 @@ def update_page_settings( draft: typing.Optional[bool] = OMIT, can_branch: typing.Optional[bool] = OMIT, is_branch: typing.Optional[bool] = OMIT, - is_members_only: typing.Optional[bool] = OMIT, seo: typing.Optional[PageSeo] = OMIT, open_graph: typing.Optional[PageOpenGraph] = OMIT, page_locale_id: typing.Optional[str] = OMIT, @@ -297,6 +298,10 @@ def update_page_settings( """ Update Page-level metadata, including SEO and Open Graph fields. + + Note: When updating Page Metadata in secondary locales, you may only add `slug` to the request if your Site has the [Advanced or Enterprise Localization](https://webflow.com/localization) add-on. + + Required scope | `pages:write` Parameters @@ -304,12 +309,12 @@ def update_page_settings( page_id : str Unique identifier for a Page - id : str - Unique identifier for the Page - locale_id : typing.Optional[str] Unique identifier for a specific locale. Applicable, when using localization. + id : typing.Optional[str] + Unique identifier for the Page + site_id : typing.Optional[str] Unique identifier for the Site @@ -343,9 +348,6 @@ def update_page_settings( is_branch : typing.Optional[bool] Indicates whether the Page is a Branch of another Page [Page Branching](https://university.webflow.com/lesson/page-branching) - is_members_only : typing.Optional[bool] - Indicates whether the Page is restricted by [Memberships Controls](https://university.webflow.com/lesson/webflow-memberships-overview#how-to-manage-page-restrictions) - seo : typing.Optional[PageSeo] SEO-related fields for the Page @@ -408,6 +410,7 @@ def update_page_settings( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}", + base_url=self._client_wrapper.get_environment().base, method="PUT", params={ "localeId": locale_id, @@ -425,7 +428,6 @@ def update_page_settings( "draft": draft, "canBranch": can_branch, "isBranch": is_branch, - "isMembersOnly": is_members_only, "seo": convert_and_respect_annotation_metadata(object_=seo, annotation=PageSeo, direction="write"), "openGraph": convert_and_respect_annotation_metadata( object_=open_graph, annotation=PageOpenGraph, direction="write" @@ -510,10 +512,11 @@ def get_content( request_options: typing.Optional[RequestOptions] = None, ) -> Dom: """ - Get static content from a static page. This includes text nodes, image nodes and component instances. - To retrieve the contents of components in the page use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint. + Get content from a static page. This includes text nodes, image nodes, select nodes, text input nodes, submit button nodes, and component instances with [property overrides](https://help.webflow.com/hc/en-us/articles/33961219350547-Component-properties#how-to-modify-property-values-on-component-instances). - If you do not provide a Locale ID in your request, the response will return any content that can be localized from the Primary locale. + To retrieve the static content of a component instance, use the [Get Component Content](/data/reference/pages-and-components/components/get-content) endpoint. + + If you do not include a `localeId` in your request, the response will return any content that can be localized from the Primary locale. Required scope | `pages:read` @@ -553,6 +556,7 @@ def get_content( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -678,9 +682,13 @@ def update_static_content( Examples -------- from webflow import ( - ComponentInstanceNodePropertyOverridesWrite, + ComponentInstance, ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem, - TextNodeWrite, + Select, + SelectNodeWriteChoicesItem, + SubmitButton, + TextInput, + TextNode, Webflow, ) @@ -691,15 +699,37 @@ def update_static_content( page_id="63c720f9347c2139b248e552", locale_id="localeId", nodes=[ - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623", text="

The Hitchhiker's Guide to the Galaxy

", ), - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627", text="

Don't Panic!

Always know where your towel is.

", ), - ComponentInstanceNodePropertyOverridesWrite( + Select( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635", + choices=[ + SelectNodeWriteChoicesItem( + value="choice-1", + text="First choice", + ), + SelectNodeWriteChoicesItem( + value="choice-2", + text="Second choice", + ), + ], + ), + TextInput( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642", + placeholder="Enter something here...", + ), + SubmitButton( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671", + value="Submit", + waiting_text="Submitting...", + ), + ComponentInstance( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629", property_overrides=[ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem( @@ -717,6 +747,7 @@ def update_static_content( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, @@ -870,6 +901,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/pages", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -992,6 +1024,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -1066,8 +1099,8 @@ async def update_page_settings( self, page_id: str, *, - id: str, locale_id: typing.Optional[str] = None, + id: typing.Optional[str] = OMIT, site_id: typing.Optional[str] = OMIT, title: typing.Optional[str] = OMIT, slug: typing.Optional[str] = OMIT, @@ -1079,7 +1112,6 @@ async def update_page_settings( draft: typing.Optional[bool] = OMIT, can_branch: typing.Optional[bool] = OMIT, is_branch: typing.Optional[bool] = OMIT, - is_members_only: typing.Optional[bool] = OMIT, seo: typing.Optional[PageSeo] = OMIT, open_graph: typing.Optional[PageOpenGraph] = OMIT, page_locale_id: typing.Optional[str] = OMIT, @@ -1089,6 +1121,10 @@ async def update_page_settings( """ Update Page-level metadata, including SEO and Open Graph fields. + + Note: When updating Page Metadata in secondary locales, you may only add `slug` to the request if your Site has the [Advanced or Enterprise Localization](https://webflow.com/localization) add-on. + + Required scope | `pages:write` Parameters @@ -1096,12 +1132,12 @@ async def update_page_settings( page_id : str Unique identifier for a Page - id : str - Unique identifier for the Page - locale_id : typing.Optional[str] Unique identifier for a specific locale. Applicable, when using localization. + id : typing.Optional[str] + Unique identifier for the Page + site_id : typing.Optional[str] Unique identifier for the Site @@ -1135,9 +1171,6 @@ async def update_page_settings( is_branch : typing.Optional[bool] Indicates whether the Page is a Branch of another Page [Page Branching](https://university.webflow.com/lesson/page-branching) - is_members_only : typing.Optional[bool] - Indicates whether the Page is restricted by [Memberships Controls](https://university.webflow.com/lesson/webflow-memberships-overview#how-to-manage-page-restrictions) - seo : typing.Optional[PageSeo] SEO-related fields for the Page @@ -1207,6 +1240,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}", + base_url=self._client_wrapper.get_environment().base, method="PUT", params={ "localeId": locale_id, @@ -1224,7 +1258,6 @@ async def main() -> None: "draft": draft, "canBranch": can_branch, "isBranch": is_branch, - "isMembersOnly": is_members_only, "seo": convert_and_respect_annotation_metadata(object_=seo, annotation=PageSeo, direction="write"), "openGraph": convert_and_respect_annotation_metadata( object_=open_graph, annotation=PageOpenGraph, direction="write" @@ -1309,10 +1342,11 @@ async def get_content( request_options: typing.Optional[RequestOptions] = None, ) -> Dom: """ - Get static content from a static page. This includes text nodes, image nodes and component instances. - To retrieve the contents of components in the page use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint. + Get content from a static page. This includes text nodes, image nodes, select nodes, text input nodes, submit button nodes, and component instances with [property overrides](https://help.webflow.com/hc/en-us/articles/33961219350547-Component-properties#how-to-modify-property-values-on-component-instances). - If you do not provide a Locale ID in your request, the response will return any content that can be localized from the Primary locale. + To retrieve the static content of a component instance, use the [Get Component Content](/data/reference/pages-and-components/components/get-content) endpoint. + + If you do not include a `localeId` in your request, the response will return any content that can be localized from the Primary locale. Required scope | `pages:read` @@ -1360,6 +1394,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -1488,9 +1523,13 @@ async def update_static_content( from webflow import ( AsyncWebflow, - ComponentInstanceNodePropertyOverridesWrite, + ComponentInstance, ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem, - TextNodeWrite, + Select, + SelectNodeWriteChoicesItem, + SubmitButton, + TextInput, + TextNode, ) client = AsyncWebflow( @@ -1503,15 +1542,37 @@ async def main() -> None: page_id="63c720f9347c2139b248e552", locale_id="localeId", nodes=[ - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623", text="

The Hitchhiker's Guide to the Galaxy

", ), - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627", text="

Don't Panic!

Always know where your towel is.

", ), - ComponentInstanceNodePropertyOverridesWrite( + Select( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635", + choices=[ + SelectNodeWriteChoicesItem( + value="choice-1", + text="First choice", + ), + SelectNodeWriteChoicesItem( + value="choice-2", + text="Second choice", + ), + ], + ), + TextInput( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642", + placeholder="Enter something here...", + ), + SubmitButton( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671", + value="Submit", + waiting_text="Submitting...", + ), + ComponentInstance( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629", property_overrides=[ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem( @@ -1532,6 +1593,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, diff --git a/src/webflow/resources/pages/resources/scripts/client.py b/src/webflow/resources/pages/resources/scripts/client.py index 56bd39a..a0e22e8 100644 --- a/src/webflow/resources/pages/resources/scripts/client.py +++ b/src/webflow/resources/pages/resources/scripts/client.py @@ -31,13 +31,7 @@ def get_custom_code( self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> ScriptApplyList: """ - Get all registered scripts that have been applied to a specific Page. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Get all scripts applied to a page. Required scope | `custom_code:read` @@ -67,6 +61,7 @@ def get_custom_code( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -144,15 +139,11 @@ def upsert_custom_code( request_options: typing.Optional[RequestOptions] = None, ) -> ScriptApplyList: """ - Add a registered script to a Page. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Apply scripts to a page. - A site can have a maximum of 800 registered scripts. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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 | `custom_code:write` @@ -204,6 +195,7 @@ def upsert_custom_code( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="PUT", json={ "scripts": convert_and_respect_annotation_metadata( @@ -291,11 +283,7 @@ def upsert_custom_code( def delete_custom_code(self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: """ - Delete the custom code block that an app has created for a page - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Delete a custom code block that the App created on a page. Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). @@ -326,6 +314,7 @@ def delete_custom_code(self, page_id: str, *, request_options: typing.Optional[R """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -396,13 +385,7 @@ async def get_custom_code( self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> ScriptApplyList: """ - Get all registered scripts that have been applied to a specific Page. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Get all scripts applied to a page. Required scope | `custom_code:read` @@ -440,6 +423,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -517,15 +501,11 @@ async def upsert_custom_code( request_options: typing.Optional[RequestOptions] = None, ) -> ScriptApplyList: """ - Add a registered script to a Page. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Apply scripts to a page. - A site can have a maximum of 800 registered scripts. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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 | `custom_code:write` @@ -585,6 +565,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="PUT", json={ "scripts": convert_and_respect_annotation_metadata( @@ -674,11 +655,7 @@ async def delete_custom_code( self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> None: """ - Delete the custom code block that an app has created for a page - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Delete a custom code block that the App created on a page. Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). @@ -717,6 +694,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) diff --git a/src/webflow/resources/pages/types/page_dom_write_nodes_item.py b/src/webflow/resources/pages/types/page_dom_write_nodes_item.py index 05d1f3f..15615be 100644 --- a/src/webflow/resources/pages/types/page_dom_write_nodes_item.py +++ b/src/webflow/resources/pages/types/page_dom_write_nodes_item.py @@ -1,7 +1,11 @@ # This file was auto-generated by Fern from our API Definition. import typing -from ....types.text_node_write import TextNodeWrite -from ....types.component_instance_node_property_overrides_write import ComponentInstanceNodePropertyOverridesWrite +from ....types.text_node import TextNode +from ....types.component_instance import ComponentInstance +from ....types.select import Select +from ....types.text_input import TextInput +from ....types.submit_button import SubmitButton +from ....types.search_button import SearchButton -PageDomWriteNodesItem = typing.Union[TextNodeWrite, ComponentInstanceNodePropertyOverridesWrite] +PageDomWriteNodesItem = typing.Union[TextNode, ComponentInstance, Select, TextInput, SubmitButton, SearchButton] diff --git a/src/webflow/resources/products/__init__.py b/src/webflow/resources/products/__init__.py index 9fced2c..adf933b 100644 --- a/src/webflow/resources/products/__init__.py +++ b/src/webflow/resources/products/__init__.py @@ -1,5 +1,5 @@ # This file was auto-generated by Fern from our API Definition. -from .types import ProductsCreateSkuResponse +from .types import ProductSkuCreateProduct, ProductSkuCreateSku, ProductsCreateSkuResponse -__all__ = ["ProductsCreateSkuResponse"] +__all__ = ["ProductSkuCreateProduct", "ProductSkuCreateSku", "ProductsCreateSkuResponse"] diff --git a/src/webflow/resources/products/client.py b/src/webflow/resources/products/client.py index c856fef..ab262b5 100644 --- a/src/webflow/resources/products/client.py +++ b/src/webflow/resources/products/client.py @@ -16,11 +16,13 @@ from ...errors.internal_server_error import InternalServerError from json.decoder import JSONDecodeError from ...core.api_error import ApiError +from .types.product_sku_create_product import ProductSkuCreateProduct +from .types.product_sku_create_sku import ProductSkuCreateSku from ...types.publish_status import PublishStatus -from ...types.product import Product -from ...types.sku import Sku from ...types.product_and_sk_us import ProductAndSkUs from ...core.serialization import convert_and_respect_annotation_metadata +from ...types.product import Product +from ...types.sku import Sku from .types.products_create_sku_response import ProductsCreateSkuResponse from ...core.client_wrapper import AsyncClientWrapper @@ -80,6 +82,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -175,22 +178,18 @@ def create( self, site_id: str, *, + product: ProductSkuCreateProduct, + sku: ProductSkuCreateSku, publish_status: typing.Optional[PublishStatus] = OMIT, - product: typing.Optional[Product] = OMIT, - sku: typing.Optional[Sku] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> ProductAndSkUs: """ - Create a new product and SKU. - - When you create a product, you will always create a SKU, since a Product Item must have, at minimum, a single SKU. + Create a new ecommerce product and defaultSKU. A product, at minimum, must have a single SKU. - To create a Product with multiple SKUs - for example a T-shirt in sizes small, medium and large: - - Create parameters in `sku-properties`, also known as [product options and variants.](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants). - - A single `sku-property` would be `color`. Within the `color` property, list the various colors of T-shirts as an array of `enum` values: `royal-blue`, `crimson-red`, and `forrest-green`. - - Once, you've created a Product and its `sku-properties` with `enum` values, Webflow will create a **default SKU**, which will automatically be a combination of the first `sku-properties` you've created. - - In our example, the default SKU will be a Royal Blue T-Shirt, because our first `enum` of our Color `sku-property` is Royal Blue. - - After you've created your product, you can create additional SKUs using the [Create SKU endpoint.](/data/reference/ecommerce/products/create-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. @@ -201,11 +200,11 @@ def create( site_id : str Unique identifier for a Site - publish_status : typing.Optional[PublishStatus] + product : ProductSkuCreateProduct - product : typing.Optional[Product] + sku : ProductSkuCreateSku - sku : typing.Optional[Sku] + publish_status : typing.Optional[PublishStatus] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -217,24 +216,102 @@ def create( Examples -------- - from webflow import Webflow + from webflow import ( + ProductFieldData, + SkuFieldData, + SkuFieldDataPrice, + SkuPropertyList, + SkuPropertyListEnumItem, + Webflow, + ) + from webflow.resources.products import ( + ProductSkuCreateProduct, + ProductSkuCreateSku, + ) client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) 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.0, + 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", + ), + ), ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "publishStatus": publish_status, "product": convert_and_respect_annotation_metadata( - object_=product, annotation=Product, direction="write" + object_=product, annotation=ProductSkuCreateProduct, direction="write" + ), + "sku": convert_and_respect_annotation_metadata( + object_=sku, annotation=ProductSkuCreateSku, direction="write" ), - "sku": convert_and_respect_annotation_metadata(object_=sku, annotation=Sku, direction="write"), }, headers={ "content-type": "application/json", @@ -365,6 +442,7 @@ def get( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -505,6 +583,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "publishStatus": publish_status, @@ -642,7 +721,9 @@ def create_sku( Examples -------- - from webflow import Sku, Webflow + import datetime + + from webflow import Sku, SkuFieldData, SkuFieldDataPrice, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -650,11 +731,35 @@ def create_sku( client.products.create_sku( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", - skus=[Sku()], + skus=[ + Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + last_updated=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + created_on=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ) + ], ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "publishStatus": publish_status, @@ -794,7 +899,9 @@ def update_sku( Examples -------- - from webflow import Sku, Webflow + import datetime + + from webflow import Sku, SkuFieldData, SkuFieldDataPrice, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -803,11 +910,33 @@ def update_sku( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", sku_id="5e8518516e147040726cc415", - sku=Sku(), + sku=Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + last_updated=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + created_on=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ), ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus/{jsonable_encoder(sku_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "publishStatus": publish_status, @@ -964,6 +1093,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -1059,22 +1189,18 @@ async def create( self, site_id: str, *, + product: ProductSkuCreateProduct, + sku: ProductSkuCreateSku, publish_status: typing.Optional[PublishStatus] = OMIT, - product: typing.Optional[Product] = OMIT, - sku: typing.Optional[Sku] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> ProductAndSkUs: """ - Create a new product and SKU. + Create a new ecommerce product and defaultSKU. A product, at minimum, must have a single SKU. - When you create a product, you will always create a SKU, since a Product Item must have, at minimum, a single SKU. - - To create a Product with multiple SKUs - for example a T-shirt in sizes small, medium and large: - - Create parameters in `sku-properties`, also known as [product options and variants.](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants). - - A single `sku-property` would be `color`. Within the `color` property, list the various colors of T-shirts as an array of `enum` values: `royal-blue`, `crimson-red`, and `forrest-green`. - - Once, you've created a Product and its `sku-properties` with `enum` values, Webflow will create a **default SKU**, which will automatically be a combination of the first `sku-properties` you've created. - - In our example, the default SKU will be a Royal Blue T-Shirt, because our first `enum` of our Color `sku-property` is Royal Blue. - - After you've created your product, you can create additional SKUs using the [Create SKU endpoint.](/data/reference/ecommerce/products/create-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. @@ -1085,11 +1211,11 @@ async def create( site_id : str Unique identifier for a Site - publish_status : typing.Optional[PublishStatus] + product : ProductSkuCreateProduct - product : typing.Optional[Product] + sku : ProductSkuCreateSku - sku : typing.Optional[Sku] + publish_status : typing.Optional[PublishStatus] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1103,7 +1229,18 @@ async def create( -------- import asyncio - from webflow import AsyncWebflow + from webflow import ( + AsyncWebflow, + ProductFieldData, + SkuFieldData, + SkuFieldDataPrice, + SkuPropertyList, + SkuPropertyListEnumItem, + ) + from webflow.resources.products import ( + ProductSkuCreateProduct, + ProductSkuCreateSku, + ) client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -1113,6 +1250,70 @@ async def create( async def main() -> None: await 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.0, + 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", + ), + ), ) @@ -1120,13 +1321,16 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "publishStatus": publish_status, "product": convert_and_respect_annotation_metadata( - object_=product, annotation=Product, direction="write" + object_=product, annotation=ProductSkuCreateProduct, direction="write" + ), + "sku": convert_and_respect_annotation_metadata( + object_=sku, annotation=ProductSkuCreateSku, direction="write" ), - "sku": convert_and_respect_annotation_metadata(object_=sku, annotation=Sku, direction="write"), }, headers={ "content-type": "application/json", @@ -1265,6 +1469,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1413,6 +1618,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "publishStatus": publish_status, @@ -1551,8 +1757,9 @@ async def create_sku( Examples -------- import asyncio + import datetime - from webflow import AsyncWebflow, Sku + from webflow import AsyncWebflow, Sku, SkuFieldData, SkuFieldDataPrice client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -1563,7 +1770,30 @@ async def main() -> None: await client.products.create_sku( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", - skus=[Sku()], + skus=[ + Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + last_updated=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + created_on=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ) + ], ) @@ -1571,6 +1801,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "publishStatus": publish_status, @@ -1711,8 +1942,9 @@ async def update_sku( Examples -------- import asyncio + import datetime - from webflow import AsyncWebflow, Sku + from webflow import AsyncWebflow, Sku, SkuFieldData, SkuFieldDataPrice client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -1724,7 +1956,28 @@ async def main() -> None: site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", sku_id="5e8518516e147040726cc415", - sku=Sku(), + sku=Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + last_updated=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + created_on=datetime.datetime.fromisoformat( + "2023-03-17 18:47:35+00:00", + ), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ), ) @@ -1732,6 +1985,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus/{jsonable_encoder(sku_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "publishStatus": publish_status, diff --git a/src/webflow/resources/products/types/__init__.py b/src/webflow/resources/products/types/__init__.py index b078afe..5b6d9b4 100644 --- a/src/webflow/resources/products/types/__init__.py +++ b/src/webflow/resources/products/types/__init__.py @@ -1,5 +1,7 @@ # This file was auto-generated by Fern from our API Definition. +from .product_sku_create_product import ProductSkuCreateProduct +from .product_sku_create_sku import ProductSkuCreateSku from .products_create_sku_response import ProductsCreateSkuResponse -__all__ = ["ProductsCreateSkuResponse"] +__all__ = ["ProductSkuCreateProduct", "ProductSkuCreateSku", "ProductsCreateSkuResponse"] diff --git a/src/webflow/resources/products/types/product_sku_create_product.py b/src/webflow/resources/products/types/product_sku_create_product.py new file mode 100644 index 0000000..750e5f4 --- /dev/null +++ b/src/webflow/resources/products/types/product_sku_create_product.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from ....types.product_field_data import ProductFieldData +from ....core.serialization import FieldMetadata +from ....core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProductSkuCreateProduct(UniversalBaseModel): + field_data: typing_extensions.Annotated[typing.Optional[ProductFieldData], FieldMetadata(alias="fieldData")] = 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/resources/products/types/product_sku_create_sku.py b/src/webflow/resources/products/types/product_sku_create_sku.py new file mode 100644 index 0000000..2762a9a --- /dev/null +++ b/src/webflow/resources/products/types/product_sku_create_sku.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from ....types.sku_field_data import SkuFieldData +from ....core.serialization import FieldMetadata +from ....core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProductSkuCreateSku(UniversalBaseModel): + field_data: typing_extensions.Annotated[typing.Optional[SkuFieldData], FieldMetadata(alias="fieldData")] = 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/resources/products/types/products_create_sku_response.py b/src/webflow/resources/products/types/products_create_sku_response.py index e694930..cd68c3d 100644 --- a/src/webflow/resources/products/types/products_create_sku_response.py +++ b/src/webflow/resources/products/types/products_create_sku_response.py @@ -8,7 +8,7 @@ class ProductsCreateSkuResponse(UniversalBaseModel): - skus: typing.Optional[typing.List[Sku]] = None + skus: typing.List[Sku] 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/scripts/client.py b/src/webflow/resources/scripts/client.py index e9112fb..80026d9 100644 --- a/src/webflow/resources/scripts/client.py +++ b/src/webflow/resources/scripts/client.py @@ -28,14 +28,11 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> RegisteredScriptList: """ - List of scripts registered to a Site. + Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts. - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - Additionally, Scripts can be remotely hosted, or registered as inline snippets. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:read` @@ -65,6 +62,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -144,14 +142,11 @@ def register_hosted( request_options: typing.Optional[RequestOptions] = None, ) -> CustomCodeHostedResponse: """ - Add a script to a Site's Custom Code registry. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - Additionally, Scripts can be remotely hosted, or registered as inline snippets. + Register a hosted script to a site. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:write` @@ -200,6 +195,7 @@ def register_hosted( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts/hosted", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "hostedLocation": hosted_location, @@ -290,13 +286,11 @@ def register_inline( request_options: typing.Optional[RequestOptions] = None, ) -> CustomCodeInlineResponse: """ - Add a script to a Site's Custom Code registry. Inline scripts can be between 1 and 2000 characters. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Register an inline script to a site. Inline scripts are limited to 2000 characters. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:write` @@ -344,6 +338,7 @@ def register_inline( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts/inline", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "sourceCode": source_code, @@ -431,14 +426,11 @@ async def list( self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> RegisteredScriptList: """ - List of scripts registered to a Site. + Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts. - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - Additionally, Scripts can be remotely hosted, or registered as inline snippets. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:read` @@ -476,6 +468,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -555,14 +548,11 @@ async def register_hosted( request_options: typing.Optional[RequestOptions] = None, ) -> CustomCodeHostedResponse: """ - Add a script to a Site's Custom Code registry. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - Additionally, Scripts can be remotely hosted, or registered as inline snippets. + Register a hosted script to a site. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:write` @@ -619,6 +609,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts/hosted", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "hostedLocation": hosted_location, @@ -709,13 +700,11 @@ async def register_inline( request_options: typing.Optional[RequestOptions] = None, ) -> CustomCodeInlineResponse: """ - Add a script to a Site's Custom Code registry. Inline scripts can be between 1 and 2000 characters. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Register an inline script to a site. Inline scripts are limited to 2000 characters. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:write` @@ -771,6 +760,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts/inline", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "sourceCode": source_code, diff --git a/src/webflow/resources/sites/__init__.py b/src/webflow/resources/sites/__init__.py index 3ec19db..8a61137 100644 --- a/src/webflow/resources/sites/__init__.py +++ b/src/webflow/resources/sites/__init__.py @@ -1,6 +1,37 @@ # This file was auto-generated by Fern from our API Definition. from .types import SitesPublishResponse -from .resources import activity_logs, plans, redirects, scripts +from .resources import ( + CommentsGetCommentThreadRequestSortBy, + CommentsGetCommentThreadRequestSortOrder, + CommentsListCommentRepliesRequestSortBy, + CommentsListCommentRepliesRequestSortOrder, + CommentsListCommentThreadsRequestSortBy, + CommentsListCommentThreadsRequestSortOrder, + WellKnownFileContentType, + activity_logs, + comments, + plans, + redirects, + robots_txt, + scripts, + well_known, +) -__all__ = ["SitesPublishResponse", "activity_logs", "plans", "redirects", "scripts"] +__all__ = [ + "CommentsGetCommentThreadRequestSortBy", + "CommentsGetCommentThreadRequestSortOrder", + "CommentsListCommentRepliesRequestSortBy", + "CommentsListCommentRepliesRequestSortOrder", + "CommentsListCommentThreadsRequestSortBy", + "CommentsListCommentThreadsRequestSortOrder", + "SitesPublishResponse", + "WellKnownFileContentType", + "activity_logs", + "comments", + "plans", + "redirects", + "robots_txt", + "scripts", + "well_known", +] diff --git a/src/webflow/resources/sites/client.py b/src/webflow/resources/sites/client.py index c2a4468..26ef50b 100644 --- a/src/webflow/resources/sites/client.py +++ b/src/webflow/resources/sites/client.py @@ -4,7 +4,10 @@ from ...core.client_wrapper import SyncClientWrapper from .resources.redirects.client import RedirectsClient from .resources.plans.client import PlansClient +from .resources.robots_txt.client import RobotsTxtClient +from .resources.well_known.client import WellKnownClient from .resources.activity_logs.client import ActivityLogsClient +from .resources.comments.client import CommentsClient from .resources.scripts.client import ScriptsClient from ...core.request_options import RequestOptions from ...types.site import Site @@ -25,7 +28,10 @@ from ...core.client_wrapper import AsyncClientWrapper from .resources.redirects.client import AsyncRedirectsClient from .resources.plans.client import AsyncPlansClient +from .resources.robots_txt.client import AsyncRobotsTxtClient +from .resources.well_known.client import AsyncWellKnownClient from .resources.activity_logs.client import AsyncActivityLogsClient +from .resources.comments.client import AsyncCommentsClient from .resources.scripts.client import AsyncScriptsClient # this is used as the default value for optional parameters @@ -37,7 +43,10 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper self.redirects = RedirectsClient(client_wrapper=self._client_wrapper) self.plans = PlansClient(client_wrapper=self._client_wrapper) + self.robots_txt = RobotsTxtClient(client_wrapper=self._client_wrapper) + self.well_known = WellKnownClient(client_wrapper=self._client_wrapper) self.activity_logs = ActivityLogsClient(client_wrapper=self._client_wrapper) + self.comments = CommentsClient(client_wrapper=self._client_wrapper) self.scripts = ScriptsClient(client_wrapper=self._client_wrapper) def create( @@ -50,7 +59,9 @@ def create( request_options: typing.Optional[RequestOptions] = None, ) -> Site: """ - Create a site. This endpoint requires an Enterprise workspace. + Create a site. + + This endpoint requires an Enterprise workspace. Required scope | `workspace:write` @@ -90,6 +101,7 @@ def create( """ _response = self._client_wrapper.httpx_client.request( f"workspaces/{jsonable_encoder(workspace_id)}/sites", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "name": name, @@ -203,6 +215,7 @@ def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> Si """ _response = self._client_wrapper.httpx_client.request( "sites", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -282,6 +295,7 @@ def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -351,7 +365,9 @@ def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] def delete(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: """ - Delete a site. This endpoint requires an Enterprise workspace. + Delete a site. + + This endpoint requires an Enterprise workspace. Required scope | `sites:write` @@ -380,6 +396,7 @@ def delete(self, site_id: str, *, request_options: typing.Optional[RequestOption """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -460,7 +477,9 @@ def update( request_options: typing.Optional[RequestOptions] = None, ) -> Site: """ - Update a site. This endpoint requires an Enterprise workspace. + Update a site. + + This endpoint requires an Enterprise workspace. Required scope | `sites:write` @@ -496,6 +515,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "name": name, @@ -613,6 +633,7 @@ def get_custom_domain(self, site_id: str, *, request_options: typing.Optional[Re """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_domains", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -691,7 +712,9 @@ def publish( """ Publishes a site to one or more more domains. - This endpoint has a limit of one successful publish queue per minute. + To publish to a specific custom domain, use the domain IDs from the [Get Custom Domains](/data/reference/sites/get-custom-domain) endpoint. + + This endpoint has a specific rate limit of one successful publish queue per minute. Required scope | `sites:write` @@ -723,10 +746,13 @@ def publish( ) client.sites.publish( site_id="580e63e98c9a982ac9b8b741", + custom_domains=["660c6449dd97ebc7346ac629", "660c6449dd97ebc7346ac62f"], + publish_to_webflow_subdomain=False, ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/publish", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "customDomains": custom_domains, @@ -808,7 +834,10 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper self.redirects = AsyncRedirectsClient(client_wrapper=self._client_wrapper) self.plans = AsyncPlansClient(client_wrapper=self._client_wrapper) + self.robots_txt = AsyncRobotsTxtClient(client_wrapper=self._client_wrapper) + self.well_known = AsyncWellKnownClient(client_wrapper=self._client_wrapper) self.activity_logs = AsyncActivityLogsClient(client_wrapper=self._client_wrapper) + self.comments = AsyncCommentsClient(client_wrapper=self._client_wrapper) self.scripts = AsyncScriptsClient(client_wrapper=self._client_wrapper) async def create( @@ -821,7 +850,9 @@ async def create( request_options: typing.Optional[RequestOptions] = None, ) -> Site: """ - Create a site. This endpoint requires an Enterprise workspace. + Create a site. + + This endpoint requires an Enterprise workspace. Required scope | `workspace:write` @@ -869,6 +900,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"workspaces/{jsonable_encoder(workspace_id)}/sites", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "name": name, @@ -990,6 +1022,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( "sites", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1077,6 +1110,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1146,7 +1180,9 @@ async def main() -> None: async def delete(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: """ - Delete a site. This endpoint requires an Enterprise workspace. + Delete a site. + + This endpoint requires an Enterprise workspace. Required scope | `sites:write` @@ -1183,6 +1219,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -1263,7 +1300,9 @@ async def update( request_options: typing.Optional[RequestOptions] = None, ) -> Site: """ - Update a site. This endpoint requires an Enterprise workspace. + Update a site. + + This endpoint requires an Enterprise workspace. Required scope | `sites:write` @@ -1307,6 +1346,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "name": name, @@ -1434,6 +1474,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_domains", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1512,7 +1553,9 @@ async def publish( """ Publishes a site to one or more more domains. - This endpoint has a limit of one successful publish queue per minute. + To publish to a specific custom domain, use the domain IDs from the [Get Custom Domains](/data/reference/sites/get-custom-domain) endpoint. + + This endpoint has a specific rate limit of one successful publish queue per minute. Required scope | `sites:write` @@ -1549,6 +1592,8 @@ async def publish( async def main() -> None: await client.sites.publish( site_id="580e63e98c9a982ac9b8b741", + custom_domains=["660c6449dd97ebc7346ac629", "660c6449dd97ebc7346ac62f"], + publish_to_webflow_subdomain=False, ) @@ -1556,6 +1601,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/publish", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "customDomains": custom_domains, diff --git a/src/webflow/resources/sites/resources/__init__.py b/src/webflow/resources/sites/resources/__init__.py index 1197a83..2de1e0b 100644 --- a/src/webflow/resources/sites/resources/__init__.py +++ b/src/webflow/resources/sites/resources/__init__.py @@ -1,5 +1,29 @@ # This file was auto-generated by Fern from our API Definition. -from . import activity_logs, plans, redirects, scripts +from . import activity_logs, comments, plans, redirects, robots_txt, scripts, well_known +from .comments import ( + CommentsGetCommentThreadRequestSortBy, + CommentsGetCommentThreadRequestSortOrder, + CommentsListCommentRepliesRequestSortBy, + CommentsListCommentRepliesRequestSortOrder, + CommentsListCommentThreadsRequestSortBy, + CommentsListCommentThreadsRequestSortOrder, +) +from .well_known import WellKnownFileContentType -__all__ = ["activity_logs", "plans", "redirects", "scripts"] +__all__ = [ + "CommentsGetCommentThreadRequestSortBy", + "CommentsGetCommentThreadRequestSortOrder", + "CommentsListCommentRepliesRequestSortBy", + "CommentsListCommentRepliesRequestSortOrder", + "CommentsListCommentThreadsRequestSortBy", + "CommentsListCommentThreadsRequestSortOrder", + "WellKnownFileContentType", + "activity_logs", + "comments", + "plans", + "redirects", + "robots_txt", + "scripts", + "well_known", +] diff --git a/src/webflow/resources/sites/resources/activity_logs/client.py b/src/webflow/resources/sites/resources/activity_logs/client.py index cf4e1b3..1a1eb8e 100644 --- a/src/webflow/resources/sites/resources/activity_logs/client.py +++ b/src/webflow/resources/sites/resources/activity_logs/client.py @@ -29,7 +29,11 @@ def list( request_options: typing.Optional[RequestOptions] = None, ) -> SiteActivityLogResponse: """ - Retrieve Activity Logs for a specific Site. Requires Site to be on an Enterprise plan.

Required scope | `site_activity:read` + Retrieve Activity Logs for a specific Site. + + This endpoint requires an Enterprise workspace. + + Required scope: `site_activity:read` Parameters ---------- @@ -63,6 +67,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/activity_logs", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, @@ -138,7 +143,11 @@ async def list( request_options: typing.Optional[RequestOptions] = None, ) -> SiteActivityLogResponse: """ - Retrieve Activity Logs for a specific Site. Requires Site to be on an Enterprise plan.

Required scope | `site_activity:read` + Retrieve Activity Logs for a specific Site. + + This endpoint requires an Enterprise workspace. + + Required scope: `site_activity:read` Parameters ---------- @@ -180,6 +189,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/activity_logs", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, diff --git a/src/webflow/resources/sites/resources/comments/__init__.py b/src/webflow/resources/sites/resources/comments/__init__.py new file mode 100644 index 0000000..1bf96a0 --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/__init__.py @@ -0,0 +1,19 @@ +# This file was auto-generated by Fern from our API Definition. + +from .types import ( + CommentsGetCommentThreadRequestSortBy, + CommentsGetCommentThreadRequestSortOrder, + CommentsListCommentRepliesRequestSortBy, + CommentsListCommentRepliesRequestSortOrder, + CommentsListCommentThreadsRequestSortBy, + CommentsListCommentThreadsRequestSortOrder, +) + +__all__ = [ + "CommentsGetCommentThreadRequestSortBy", + "CommentsGetCommentThreadRequestSortOrder", + "CommentsListCommentRepliesRequestSortBy", + "CommentsListCommentRepliesRequestSortOrder", + "CommentsListCommentThreadsRequestSortBy", + "CommentsListCommentThreadsRequestSortOrder", +] diff --git a/src/webflow/resources/sites/resources/comments/client.py b/src/webflow/resources/sites/resources/comments/client.py new file mode 100644 index 0000000..564e8da --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/client.py @@ -0,0 +1,901 @@ +# This file was auto-generated by Fern from our API Definition. + +from .....core.client_wrapper import SyncClientWrapper +import typing +from .types.comments_list_comment_threads_request_sort_by import CommentsListCommentThreadsRequestSortBy +from .types.comments_list_comment_threads_request_sort_order import CommentsListCommentThreadsRequestSortOrder +from .....core.request_options import RequestOptions +from .....types.comment_thread_list import CommentThreadList +from .....core.jsonable_encoder import jsonable_encoder +from .....core.pydantic_utilities import parse_obj_as +from .....errors.bad_request_error import BadRequestError +from .....errors.unauthorized_error import UnauthorizedError +from .....types.error import Error +from .....errors.not_found_error import NotFoundError +from .....errors.too_many_requests_error import TooManyRequestsError +from .....errors.internal_server_error import InternalServerError +from json.decoder import JSONDecodeError +from .....core.api_error import ApiError +from .types.comments_get_comment_thread_request_sort_by import CommentsGetCommentThreadRequestSortBy +from .types.comments_get_comment_thread_request_sort_order import CommentsGetCommentThreadRequestSortOrder +from .....types.comment_thread import CommentThread +from .types.comments_list_comment_replies_request_sort_by import CommentsListCommentRepliesRequestSortBy +from .types.comments_list_comment_replies_request_sort_order import CommentsListCommentRepliesRequestSortOrder +from .....types.comment_reply_list import CommentReplyList +from .....core.client_wrapper import AsyncClientWrapper + + +class CommentsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def list_comment_threads( + self, + site_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[CommentsListCommentThreadsRequestSortBy] = None, + sort_order: typing.Optional[CommentsListCommentThreadsRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentThreadList: + """ + List all comment threads for a site. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[CommentsListCommentThreadsRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[CommentsListCommentThreadsRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentThreadList + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.comments.list_comment_threads( + site_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentThreadList, + parse_obj_as( + type_=CommentThreadList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def get_comment_thread( + self, + site_id: str, + comment_thread_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[CommentsGetCommentThreadRequestSortBy] = None, + sort_order: typing.Optional[CommentsGetCommentThreadRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentThread: + """ + Get details of a specific comment thread. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + comment_thread_id : str + Unique identifier for a Comment Thread + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[CommentsGetCommentThreadRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[CommentsGetCommentThreadRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentThread + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.comments.get_comment_thread( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments/{jsonable_encoder(comment_thread_id)}", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentThread, + parse_obj_as( + type_=CommentThread, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def list_comment_replies( + self, + site_id: str, + comment_thread_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[CommentsListCommentRepliesRequestSortBy] = None, + sort_order: typing.Optional[CommentsListCommentRepliesRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentReplyList: + """ + List all replies to a specific comment thread. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + comment_thread_id : str + Unique identifier for a Comment Thread + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[CommentsListCommentRepliesRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[CommentsListCommentRepliesRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentReplyList + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.comments.list_comment_replies( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments/{jsonable_encoder(comment_thread_id)}/replies", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentReplyList, + parse_obj_as( + type_=CommentReplyList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + +class AsyncCommentsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list_comment_threads( + self, + site_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[CommentsListCommentThreadsRequestSortBy] = None, + sort_order: typing.Optional[CommentsListCommentThreadsRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentThreadList: + """ + List all comment threads for a site. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[CommentsListCommentThreadsRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[CommentsListCommentThreadsRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentThreadList + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.comments.list_comment_threads( + site_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentThreadList, + parse_obj_as( + type_=CommentThreadList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def get_comment_thread( + self, + site_id: str, + comment_thread_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[CommentsGetCommentThreadRequestSortBy] = None, + sort_order: typing.Optional[CommentsGetCommentThreadRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentThread: + """ + Get details of a specific comment thread. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + comment_thread_id : str + Unique identifier for a Comment Thread + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[CommentsGetCommentThreadRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[CommentsGetCommentThreadRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentThread + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.comments.get_comment_thread( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments/{jsonable_encoder(comment_thread_id)}", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentThread, + parse_obj_as( + type_=CommentThread, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def list_comment_replies( + self, + site_id: str, + comment_thread_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[CommentsListCommentRepliesRequestSortBy] = None, + sort_order: typing.Optional[CommentsListCommentRepliesRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentReplyList: + """ + List all replies to a specific comment thread. + + + There may be a delay of up to 5 minutes before new comments appear in the system. + + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + comment_thread_id : str + Unique identifier for a Comment Thread + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[CommentsListCommentRepliesRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[CommentsListCommentRepliesRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentReplyList + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.comments.list_comment_replies( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments/{jsonable_encoder(comment_thread_id)}/replies", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentReplyList, + parse_obj_as( + type_=CommentReplyList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/webflow/resources/sites/resources/comments/types/__init__.py b/src/webflow/resources/sites/resources/comments/types/__init__.py new file mode 100644 index 0000000..380d194 --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/__init__.py @@ -0,0 +1,17 @@ +# This file was auto-generated by Fern from our API Definition. + +from .comments_get_comment_thread_request_sort_by import CommentsGetCommentThreadRequestSortBy +from .comments_get_comment_thread_request_sort_order import CommentsGetCommentThreadRequestSortOrder +from .comments_list_comment_replies_request_sort_by import CommentsListCommentRepliesRequestSortBy +from .comments_list_comment_replies_request_sort_order import CommentsListCommentRepliesRequestSortOrder +from .comments_list_comment_threads_request_sort_by import CommentsListCommentThreadsRequestSortBy +from .comments_list_comment_threads_request_sort_order import CommentsListCommentThreadsRequestSortOrder + +__all__ = [ + "CommentsGetCommentThreadRequestSortBy", + "CommentsGetCommentThreadRequestSortOrder", + "CommentsListCommentRepliesRequestSortBy", + "CommentsListCommentRepliesRequestSortOrder", + "CommentsListCommentThreadsRequestSortBy", + "CommentsListCommentThreadsRequestSortOrder", +] diff --git a/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_by.py b/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_by.py new file mode 100644 index 0000000..14daabb --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_by.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentsGetCommentThreadRequestSortBy = typing.Union[typing.Literal["createdOn", "lastUpdated"], typing.Any] diff --git a/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_order.py b/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_order.py new file mode 100644 index 0000000..3da3ffc --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_order.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentsGetCommentThreadRequestSortOrder = typing.Union[typing.Literal["asc", "desc"], typing.Any] diff --git a/src/webflow/resources/sites/resources/comments/types/comments_list_comment_replies_request_sort_by.py b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_replies_request_sort_by.py new file mode 100644 index 0000000..67fcb98 --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_replies_request_sort_by.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentsListCommentRepliesRequestSortBy = typing.Union[typing.Literal["createdOn", "lastUpdated"], typing.Any] diff --git a/src/webflow/resources/sites/resources/comments/types/comments_list_comment_replies_request_sort_order.py b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_replies_request_sort_order.py new file mode 100644 index 0000000..03c42c3 --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_replies_request_sort_order.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentsListCommentRepliesRequestSortOrder = typing.Union[typing.Literal["asc", "desc"], typing.Any] diff --git a/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_by.py b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_by.py new file mode 100644 index 0000000..1d541ce --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_by.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentsListCommentThreadsRequestSortBy = typing.Union[typing.Literal["createdOn", "lastUpdated"], typing.Any] diff --git a/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_order.py b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_order.py new file mode 100644 index 0000000..d2c2606 --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_order.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentsListCommentThreadsRequestSortOrder = typing.Union[typing.Literal["asc", "desc"], typing.Any] diff --git a/src/webflow/resources/sites/resources/plans/client.py b/src/webflow/resources/sites/resources/plans/client.py index 291231a..a3309bb 100644 --- a/src/webflow/resources/sites/resources/plans/client.py +++ b/src/webflow/resources/sites/resources/plans/client.py @@ -25,6 +25,8 @@ def get_site_plan(self, site_id: str, *, request_options: typing.Optional[Reques """ Get site plan details for the specified Site. + This endpoint requires an Enterprise workspace. + Required scope | `sites:read` Parameters @@ -53,6 +55,7 @@ def get_site_plan(self, site_id: str, *, request_options: typing.Optional[Reques """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/plan", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -129,6 +132,8 @@ async def get_site_plan(self, site_id: str, *, request_options: typing.Optional[ """ Get site plan details for the specified Site. + This endpoint requires an Enterprise workspace. + Required scope | `sites:read` Parameters @@ -165,6 +170,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/plan", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) diff --git a/src/webflow/resources/sites/resources/redirects/client.py b/src/webflow/resources/sites/resources/redirects/client.py index 4bc0e7b..1ac17b4 100644 --- a/src/webflow/resources/sites/resources/redirects/client.py +++ b/src/webflow/resources/sites/resources/redirects/client.py @@ -27,10 +27,11 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Redirects: """ - Fetch a list of all URL redirect rules configured for a specific site. + 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. + This endpoint requires an Enterprise workspace. Required scope: `sites:read` @@ -60,6 +61,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -137,10 +139,12 @@ def create( request_options: typing.Optional[RequestOptions] = None, ) -> Redirect: """ - Add a new URL redirection rule to a site. + 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. + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -181,6 +185,7 @@ def create( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "id": id, @@ -258,8 +263,12 @@ def delete( self, site_id: str, redirect_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> Redirects: """ - Remove a URL redirection rule from a site. + 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. + + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -292,6 +301,7 @@ def delete( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects/{jsonable_encoder(redirect_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -370,7 +380,10 @@ def update( request_options: typing.Optional[RequestOptions] = None, ) -> Redirect: """ - Update a URL redirection rule from a site. + Update a 301 redirection rule from a site. + + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -415,6 +428,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects/{jsonable_encoder(redirect_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "id": id, @@ -495,10 +509,11 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): async def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Redirects: """ - Fetch a list of all URL redirect rules configured for a specific site. + 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. + This endpoint requires an Enterprise workspace. Required scope: `sites:read` @@ -536,6 +551,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -613,10 +629,12 @@ async def create( request_options: typing.Optional[RequestOptions] = None, ) -> Redirect: """ - Add a new URL redirection rule to a site. + 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. + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -665,6 +683,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "id": id, @@ -742,8 +761,12 @@ async def delete( self, site_id: str, redirect_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> Redirects: """ - Remove a URL redirection rule from a site. + 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. + + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -784,6 +807,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects/{jsonable_encoder(redirect_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -862,7 +886,10 @@ async def update( request_options: typing.Optional[RequestOptions] = None, ) -> Redirect: """ - Update a URL redirection rule from a site. + Update a 301 redirection rule from a site. + + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -915,6 +942,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects/{jsonable_encoder(redirect_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "id": id, diff --git a/src/webflow/resources/sites/resources/robots_txt/__init__.py b/src/webflow/resources/sites/resources/robots_txt/__init__.py new file mode 100644 index 0000000..f3ea265 --- /dev/null +++ b/src/webflow/resources/sites/resources/robots_txt/__init__.py @@ -0,0 +1,2 @@ +# This file was auto-generated by Fern from our API Definition. + diff --git a/src/webflow/resources/sites/resources/robots_txt/client.py b/src/webflow/resources/sites/resources/robots_txt/client.py new file mode 100644 index 0000000..a0bc59b --- /dev/null +++ b/src/webflow/resources/sites/resources/robots_txt/client.py @@ -0,0 +1,1050 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from .....core.client_wrapper import SyncClientWrapper +from .....core.request_options import RequestOptions +from .....types.robots import Robots +from .....core.jsonable_encoder import jsonable_encoder +from .....core.pydantic_utilities import parse_obj_as +from .....errors.bad_request_error import BadRequestError +from .....errors.unauthorized_error import UnauthorizedError +from .....types.error import Error +from .....errors.not_found_error import NotFoundError +from .....errors.too_many_requests_error import TooManyRequestsError +from .....errors.internal_server_error import InternalServerError +from json.decoder import JSONDecodeError +from .....core.api_error import ApiError +from .....types.robots_rules_item import RobotsRulesItem +from .....core.serialization import convert_and_respect_annotation_metadata +from .....core.client_wrapper import AsyncClientWrapper + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RobotsTxtClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Robots: + """ + Retrieve the robots.txt configuration for various user agents. + + This endpoint requires an Enterprise workspace. + + Required scope: `site_config:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.robots_txt.get( + site_id="580e63e98c9a982ac9b8b741", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def put( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + Replace the `robots.txt` configuration for various user agents. + + This endpoint requires an Enterprise workspace. + + Required scope | `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + from webflow import RobotsRulesItem, Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.robots_txt.put( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=["/public"], + disallows=["/vogon-poetry", "/total-perspective-vortex"], + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="PUT", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def delete( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + 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: `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + from webflow import RobotsRulesItem, Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.robots_txt.delete( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="*", + allows=["/public"], + disallows=["/bubbles"], + ) + ], + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def patch( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + Update the `robots.txt` configuration for various user agents. + + This endpoint requires an Enterprise workspace. + + Required scope | `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + from webflow import RobotsRulesItem, Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + 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", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="PATCH", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + +class AsyncRobotsTxtClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Robots: + """ + Retrieve the robots.txt configuration for various user agents. + + This endpoint requires an Enterprise workspace. + + Required scope: `site_config:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.robots_txt.get( + site_id="580e63e98c9a982ac9b8b741", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def put( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + Replace the `robots.txt` configuration for various user agents. + + This endpoint requires an Enterprise workspace. + + Required scope | `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow, RobotsRulesItem + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.robots_txt.put( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=["/public"], + disallows=["/vogon-poetry", "/total-perspective-vortex"], + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="PUT", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def delete( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + 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: `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow, RobotsRulesItem + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.robots_txt.delete( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="*", + allows=["/public"], + disallows=["/bubbles"], + ) + ], + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def patch( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + Update the `robots.txt` configuration for various user agents. + + This endpoint requires an Enterprise workspace. + + Required scope | `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow, RobotsRulesItem + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await 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", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="PATCH", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/webflow/resources/sites/resources/scripts/client.py b/src/webflow/resources/sites/resources/scripts/client.py index 1954842..8af188b 100644 --- a/src/webflow/resources/sites/resources/scripts/client.py +++ b/src/webflow/resources/sites/resources/scripts/client.py @@ -31,9 +31,11 @@ def get_custom_code( self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> ScriptApplyList: """ - Get all registered scripts that have been applied to a specific Site. + Get all scripts applied to a site by the App. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:read` @@ -63,6 +65,7 @@ def get_custom_code( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -140,13 +143,11 @@ def upsert_custom_code( request_options: typing.Optional[RequestOptions] = None, ) -> ScriptApplyList: """ - Add a registered script to a Site. + Apply registered scripts to a site. - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:write` @@ -198,6 +199,7 @@ def upsert_custom_code( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="PUT", json={ "scripts": convert_and_respect_annotation_metadata( @@ -275,9 +277,7 @@ def upsert_custom_code( def delete_custom_code(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: """ - Delete the custom code block that an app created for a Site - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Remove scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts. Required scope | `custom_code:write` @@ -306,6 +306,7 @@ def delete_custom_code(self, site_id: str, *, request_options: typing.Optional[R """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -376,9 +377,13 @@ def list_custom_code_blocks( request_options: typing.Optional[RequestOptions] = None, ) -> ListCustomCodeBlocks: """ - Get all instances of Custom Code applied to a Site or Pages. + Get a list of scripts that have been applied to a site and/or individual pages. + + + 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. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` @@ -414,6 +419,7 @@ def list_custom_code_blocks( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code/blocks", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -494,9 +500,11 @@ async def get_custom_code( self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> ScriptApplyList: """ - Get all registered scripts that have been applied to a specific Site. + Get all scripts applied to a site by the App. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:read` @@ -534,6 +542,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -611,13 +620,11 @@ async def upsert_custom_code( request_options: typing.Optional[RequestOptions] = None, ) -> ScriptApplyList: """ - Add a registered script to a Site. + Apply registered scripts to a site. - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + 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. + Required scope | `custom_code:write` @@ -677,6 +684,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="PUT", json={ "scripts": convert_and_respect_annotation_metadata( @@ -756,9 +764,7 @@ async def delete_custom_code( self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> None: """ - Delete the custom code block that an app created for a Site - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Remove scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts. Required scope | `custom_code:write` @@ -795,6 +801,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -865,9 +872,13 @@ async def list_custom_code_blocks( request_options: typing.Optional[RequestOptions] = None, ) -> ListCustomCodeBlocks: """ - Get all instances of Custom Code applied to a Site or Pages. + Get a list of scripts that have been applied to a site and/or individual pages. + + + 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. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` @@ -911,6 +922,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code/blocks", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, diff --git a/src/webflow/resources/sites/resources/well_known/__init__.py b/src/webflow/resources/sites/resources/well_known/__init__.py new file mode 100644 index 0000000..323b6bd --- /dev/null +++ b/src/webflow/resources/sites/resources/well_known/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .types import WellKnownFileContentType + +__all__ = ["WellKnownFileContentType"] diff --git a/src/webflow/resources/sites/resources/well_known/client.py b/src/webflow/resources/sites/resources/well_known/client.py new file mode 100644 index 0000000..3d846b2 --- /dev/null +++ b/src/webflow/resources/sites/resources/well_known/client.py @@ -0,0 +1,532 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from .....core.client_wrapper import SyncClientWrapper +from .types.well_known_file_content_type import WellKnownFileContentType +from .....core.request_options import RequestOptions +from .....core.jsonable_encoder import jsonable_encoder +from .....errors.bad_request_error import BadRequestError +from .....core.pydantic_utilities import parse_obj_as +from .....errors.unauthorized_error import UnauthorizedError +from .....types.error import Error +from .....errors.not_found_error import NotFoundError +from .....errors.too_many_requests_error import TooManyRequestsError +from .....errors.internal_server_error import InternalServerError +from json.decoder import JSONDecodeError +from .....core.api_error import ApiError +from .....core.client_wrapper import AsyncClientWrapper + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class WellKnownClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def put( + self, + site_id: str, + *, + file_name: str, + file_data: str, + content_type: typing.Optional[WellKnownFileContentType] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + 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:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + 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. + + Returns + ------- + None + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.well_known.put( + site_id="580e63e98c9a982ac9b8b741", + file_name="fileName", + file_data="fileData", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/well_known", + base_url=self._client_wrapper.get_environment().base, + method="PUT", + json={ + "fileName": file_name, + "fileData": file_data, + "contentType": content_type, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def delete( + self, + site_id: str, + *, + file_names: typing.Optional[typing.Sequence[str]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Delete existing well-known files from a site. + + This endpoint requires an Enterprise workspace. + + Required scope: `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + file_names : typing.Optional[typing.Sequence[str]] + A list of file names to delete + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.well_known.delete( + site_id="580e63e98c9a982ac9b8b741", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/well_known", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + json={ + "fileNames": file_names, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + +class AsyncWellKnownClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def put( + self, + site_id: str, + *, + file_name: str, + file_data: str, + content_type: typing.Optional[WellKnownFileContentType] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + 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:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + 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. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.well_known.put( + site_id="580e63e98c9a982ac9b8b741", + file_name="fileName", + file_data="fileData", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/well_known", + base_url=self._client_wrapper.get_environment().base, + method="PUT", + json={ + "fileName": file_name, + "fileData": file_data, + "contentType": content_type, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def delete( + self, + site_id: str, + *, + file_names: typing.Optional[typing.Sequence[str]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Delete existing well-known files from a site. + + This endpoint requires an Enterprise workspace. + + Required scope: `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + file_names : typing.Optional[typing.Sequence[str]] + A list of file names to delete + + 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.well_known.delete( + site_id="580e63e98c9a982ac9b8b741", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/well_known", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + json={ + "fileNames": file_names, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/webflow/resources/sites/resources/well_known/types/__init__.py b/src/webflow/resources/sites/resources/well_known/types/__init__.py new file mode 100644 index 0000000..4fc9c09 --- /dev/null +++ b/src/webflow/resources/sites/resources/well_known/types/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .well_known_file_content_type import WellKnownFileContentType + +__all__ = ["WellKnownFileContentType"] diff --git a/src/webflow/resources/sites/resources/well_known/types/well_known_file_content_type.py b/src/webflow/resources/sites/resources/well_known/types/well_known_file_content_type.py new file mode 100644 index 0000000..be135b4 --- /dev/null +++ b/src/webflow/resources/sites/resources/well_known/types/well_known_file_content_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WellKnownFileContentType = typing.Union[typing.Literal["application/json", "text/plain"], typing.Any] diff --git a/src/webflow/resources/token/client.py b/src/webflow/resources/token/client.py index 628ce3a..d8cfd16 100644 --- a/src/webflow/resources/token/client.py +++ b/src/webflow/resources/token/client.py @@ -45,6 +45,7 @@ def authorized_by(self, *, request_options: typing.Optional[RequestOptions] = No """ _response = self._client_wrapper.httpx_client.request( "token/authorized_by", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -109,6 +110,7 @@ def introspect(self, *, request_options: typing.Optional[RequestOptions] = None) """ _response = self._client_wrapper.httpx_client.request( "token/introspect", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -176,6 +178,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( "token/authorized_by", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -248,6 +251,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( "token/introspect", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) diff --git a/src/webflow/resources/users/__init__.py b/src/webflow/resources/users/__init__.py index 88e72a2..75665c6 100644 --- a/src/webflow/resources/users/__init__.py +++ b/src/webflow/resources/users/__init__.py @@ -1,5 +1,5 @@ # This file was auto-generated by Fern from our API Definition. -from .types import UsersListRequestSort, UsersUpdateRequestData +from .types import UsersListRequestSort -__all__ = ["UsersListRequestSort", "UsersUpdateRequestData"] +__all__ = ["UsersListRequestSort"] diff --git a/src/webflow/resources/users/client.py b/src/webflow/resources/users/client.py index d690c0f..66cb994 100644 --- a/src/webflow/resources/users/client.py +++ b/src/webflow/resources/users/client.py @@ -17,7 +17,10 @@ from json.decoder import JSONDecodeError from ...core.api_error import ApiError from ...types.user import User -from .types.users_update_request_data import UsersUpdateRequestData +import datetime as dt +from ...types.user_status import UserStatus +from ...types.user_access_groups_item import UserAccessGroupsItem +from ...types.user_data import UserData from ...core.serialization import convert_and_respect_annotation_metadata from ...errors.conflict_error import ConflictError from ...core.client_wrapper import AsyncClientWrapper @@ -83,6 +86,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -201,6 +205,7 @@ def get(self, site_id: str, user_id: str, *, request_options: typing.Optional[Re """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -313,6 +318,7 @@ def delete(self, site_id: str, user_id: str, *, request_options: typing.Optional """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -389,8 +395,15 @@ def update( site_id: str, user_id: str, *, - data: typing.Optional[UsersUpdateRequestData] = OMIT, - access_groups: typing.Optional[typing.Sequence[str]] = OMIT, + id: typing.Optional[str] = OMIT, + is_email_verified: typing.Optional[bool] = OMIT, + last_updated: typing.Optional[dt.datetime] = OMIT, + invited_on: typing.Optional[dt.datetime] = OMIT, + created_on: typing.Optional[dt.datetime] = OMIT, + last_login: typing.Optional[dt.datetime] = OMIT, + status: typing.Optional[UserStatus] = OMIT, + access_groups: typing.Optional[typing.Sequence[UserAccessGroupsItem]] = OMIT, + data: typing.Optional[UserData] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> User: """ @@ -409,11 +422,31 @@ def update( user_id : str Unique identifier for a User - data : typing.Optional[UsersUpdateRequestData] + id : typing.Optional[str] + Unique identifier for the User - access_groups : typing.Optional[typing.Sequence[str]] - An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. + is_email_verified : typing.Optional[bool] + Shows whether the user has verified their email address + + last_updated : typing.Optional[dt.datetime] + The timestamp the user was updated + + invited_on : typing.Optional[dt.datetime] + The timestamp the user was invited + created_on : typing.Optional[dt.datetime] + The timestamp the user was created + + last_login : typing.Optional[dt.datetime] + The timestamp the user was logged in + + status : typing.Optional[UserStatus] + The status of the user + + access_groups : typing.Optional[typing.Sequence[UserAccessGroupsItem]] + Access groups the user belongs to + + data : typing.Optional[UserData] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -425,8 +458,9 @@ def update( Examples -------- - from webflow import Webflow - from webflow.resources.users import UsersUpdateRequestData + import datetime + + from webflow import UserAccessGroupsItem, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -434,25 +468,45 @@ def update( client.users.update( site_id="580e63e98c9a982ac9b8b741", user_id="580e63e98c9a982ac9b8b741", - data=UsersUpdateRequestData( - name="Some One", - accept_privacy=False, - accept_communications=False, + id="6287ec36a841b25637c663df", + is_email_verified=True, + last_updated=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", + ), + invited_on=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", + ), + created_on=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", ), - access_groups=["webflowers", "platinum", "free-tier"], + last_login=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", + ), + status="verified", + access_groups=[ + UserAccessGroupsItem( + slug="webflowers", + type="admin", + ) + ], ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ - "data": convert_and_respect_annotation_metadata( - object_=data, annotation=UsersUpdateRequestData, direction="write" + "id": id, + "isEmailVerified": is_email_verified, + "lastUpdated": last_updated, + "invitedOn": invited_on, + "createdOn": created_on, + "lastLogin": last_login, + "status": status, + "accessGroups": convert_and_respect_annotation_metadata( + object_=access_groups, annotation=typing.Sequence[UserAccessGroupsItem], direction="write" ), - "accessGroups": access_groups, - }, - headers={ - "content-type": "application/json", + "data": convert_and_respect_annotation_metadata(object_=data, annotation=UserData, direction="write"), }, request_options=request_options, omit=OMIT, @@ -557,7 +611,6 @@ def invite( access_groups : typing.Optional[typing.Sequence[str]] An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -576,11 +629,12 @@ def invite( client.users.invite( site_id="580e63e98c9a982ac9b8b741", email="some.one@home.com", - access_groups=["webflowers"], + access_groups=["accessGroups"], ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/invite", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "email": email, @@ -742,6 +796,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -868,6 +923,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -990,6 +1046,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -1066,8 +1123,15 @@ async def update( site_id: str, user_id: str, *, - data: typing.Optional[UsersUpdateRequestData] = OMIT, - access_groups: typing.Optional[typing.Sequence[str]] = OMIT, + id: typing.Optional[str] = OMIT, + is_email_verified: typing.Optional[bool] = OMIT, + last_updated: typing.Optional[dt.datetime] = OMIT, + invited_on: typing.Optional[dt.datetime] = OMIT, + created_on: typing.Optional[dt.datetime] = OMIT, + last_login: typing.Optional[dt.datetime] = OMIT, + status: typing.Optional[UserStatus] = OMIT, + access_groups: typing.Optional[typing.Sequence[UserAccessGroupsItem]] = OMIT, + data: typing.Optional[UserData] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> User: """ @@ -1086,11 +1150,31 @@ async def update( user_id : str Unique identifier for a User - data : typing.Optional[UsersUpdateRequestData] + id : typing.Optional[str] + Unique identifier for the User - access_groups : typing.Optional[typing.Sequence[str]] - An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. + is_email_verified : typing.Optional[bool] + Shows whether the user has verified their email address + + last_updated : typing.Optional[dt.datetime] + The timestamp the user was updated + + invited_on : typing.Optional[dt.datetime] + The timestamp the user was invited + created_on : typing.Optional[dt.datetime] + The timestamp the user was created + + last_login : typing.Optional[dt.datetime] + The timestamp the user was logged in + + status : typing.Optional[UserStatus] + The status of the user + + access_groups : typing.Optional[typing.Sequence[UserAccessGroupsItem]] + Access groups the user belongs to + + data : typing.Optional[UserData] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1103,9 +1187,9 @@ async def update( Examples -------- import asyncio + import datetime - from webflow import AsyncWebflow - from webflow.resources.users import UsersUpdateRequestData + from webflow import AsyncWebflow, UserAccessGroupsItem client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -1116,12 +1200,27 @@ async def main() -> None: await client.users.update( site_id="580e63e98c9a982ac9b8b741", user_id="580e63e98c9a982ac9b8b741", - data=UsersUpdateRequestData( - name="Some One", - accept_privacy=False, - accept_communications=False, + id="6287ec36a841b25637c663df", + is_email_verified=True, + last_updated=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", ), - access_groups=["webflowers", "platinum", "free-tier"], + invited_on=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", + ), + created_on=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", + ), + last_login=datetime.datetime.fromisoformat( + "2022-05-20 13:46:12+00:00", + ), + status="verified", + access_groups=[ + UserAccessGroupsItem( + slug="webflowers", + type="admin", + ) + ], ) @@ -1129,15 +1228,20 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ - "data": convert_and_respect_annotation_metadata( - object_=data, annotation=UsersUpdateRequestData, direction="write" + "id": id, + "isEmailVerified": is_email_verified, + "lastUpdated": last_updated, + "invitedOn": invited_on, + "createdOn": created_on, + "lastLogin": last_login, + "status": status, + "accessGroups": convert_and_respect_annotation_metadata( + object_=access_groups, annotation=typing.Sequence[UserAccessGroupsItem], direction="write" ), - "accessGroups": access_groups, - }, - headers={ - "content-type": "application/json", + "data": convert_and_respect_annotation_metadata(object_=data, annotation=UserData, direction="write"), }, request_options=request_options, omit=OMIT, @@ -1242,7 +1346,6 @@ async def invite( access_groups : typing.Optional[typing.Sequence[str]] An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1266,7 +1369,7 @@ async def main() -> None: await client.users.invite( site_id="580e63e98c9a982ac9b8b741", email="some.one@home.com", - access_groups=["webflowers"], + access_groups=["accessGroups"], ) @@ -1274,6 +1377,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/invite", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "email": email, diff --git a/src/webflow/resources/users/types/__init__.py b/src/webflow/resources/users/types/__init__.py index cadf367..3717bf5 100644 --- a/src/webflow/resources/users/types/__init__.py +++ b/src/webflow/resources/users/types/__init__.py @@ -1,6 +1,5 @@ # This file was auto-generated by Fern from our API Definition. from .users_list_request_sort import UsersListRequestSort -from .users_update_request_data import UsersUpdateRequestData -__all__ = ["UsersListRequestSort", "UsersUpdateRequestData"] +__all__ = ["UsersListRequestSort"] diff --git a/src/webflow/resources/users/types/users_update_request_data.py b/src/webflow/resources/users/types/users_update_request_data.py deleted file mode 100644 index 919406c..0000000 --- a/src/webflow/resources/users/types/users_update_request_data.py +++ /dev/null @@ -1,38 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.pydantic_utilities import UniversalBaseModel -import typing -import pydantic -import typing_extensions -from ....core.serialization import FieldMetadata -from ....core.pydantic_utilities import IS_PYDANTIC_V2 - - -class UsersUpdateRequestData(UniversalBaseModel): - name: typing.Optional[str] = pydantic.Field(default=None) - """ - The name of the user - """ - - accept_privacy: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="accept-privacy")] = ( - pydantic.Field(default=None) - ) - """ - Boolean indicating if the user has accepted the privacy policy - """ - - accept_communications: typing_extensions.Annotated[ - typing.Optional[bool], FieldMetadata(alias="accept-communications") - ] = pydantic.Field(default=None) - """ - Boolean indicating if the user has accepted to receive communications - """ - - 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/webhooks/client.py b/src/webflow/resources/webhooks/client.py index ded9a2f..c6821a9 100644 --- a/src/webflow/resources/webhooks/client.py +++ b/src/webflow/resources/webhooks/client.py @@ -61,6 +61,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/webhooks", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -212,6 +213,7 @@ def create( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id_)}/webhooks", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "id": id, @@ -324,6 +326,7 @@ def get(self, webhook_id: str, *, request_options: typing.Optional[RequestOption """ _response = self._client_wrapper.httpx_client.request( f"webhooks/{jsonable_encoder(webhook_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -422,6 +425,7 @@ def delete(self, webhook_id: str, *, request_options: typing.Optional[RequestOpt """ _response = self._client_wrapper.httpx_client.request( f"webhooks/{jsonable_encoder(webhook_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -528,6 +532,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/webhooks", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -686,6 +691,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id_)}/webhooks", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "id": id, @@ -806,6 +812,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"webhooks/{jsonable_encoder(webhook_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -912,6 +919,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"webhooks/{jsonable_encoder(webhook_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) diff --git a/src/webflow/resources/workspaces/__init__.py b/src/webflow/resources/workspaces/__init__.py new file mode 100644 index 0000000..d6cc054 --- /dev/null +++ b/src/webflow/resources/workspaces/__init__.py @@ -0,0 +1,13 @@ +# This file was auto-generated by Fern from our API Definition. + +from .resources import ( + AuditLogsGetWorkspaceAuditLogsRequestEventType, + AuditLogsGetWorkspaceAuditLogsRequestSortOrder, + audit_logs, +) + +__all__ = [ + "AuditLogsGetWorkspaceAuditLogsRequestEventType", + "AuditLogsGetWorkspaceAuditLogsRequestSortOrder", + "audit_logs", +] diff --git a/src/webflow/resources/workspaces/client.py b/src/webflow/resources/workspaces/client.py new file mode 100644 index 0000000..de70ca5 --- /dev/null +++ b/src/webflow/resources/workspaces/client.py @@ -0,0 +1,18 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.client_wrapper import SyncClientWrapper +from .resources.audit_logs.client import AuditLogsClient +from ...core.client_wrapper import AsyncClientWrapper +from .resources.audit_logs.client import AsyncAuditLogsClient + + +class WorkspacesClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + self.audit_logs = AuditLogsClient(client_wrapper=self._client_wrapper) + + +class AsyncWorkspacesClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + self.audit_logs = AsyncAuditLogsClient(client_wrapper=self._client_wrapper) diff --git a/src/webflow/resources/workspaces/resources/__init__.py b/src/webflow/resources/workspaces/resources/__init__.py new file mode 100644 index 0000000..0e96a0e --- /dev/null +++ b/src/webflow/resources/workspaces/resources/__init__.py @@ -0,0 +1,10 @@ +# This file was auto-generated by Fern from our API Definition. + +from . import audit_logs +from .audit_logs import AuditLogsGetWorkspaceAuditLogsRequestEventType, AuditLogsGetWorkspaceAuditLogsRequestSortOrder + +__all__ = [ + "AuditLogsGetWorkspaceAuditLogsRequestEventType", + "AuditLogsGetWorkspaceAuditLogsRequestSortOrder", + "audit_logs", +] diff --git a/src/webflow/resources/workspaces/resources/audit_logs/__init__.py b/src/webflow/resources/workspaces/resources/audit_logs/__init__.py new file mode 100644 index 0000000..dab3df1 --- /dev/null +++ b/src/webflow/resources/workspaces/resources/audit_logs/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .types import AuditLogsGetWorkspaceAuditLogsRequestEventType, AuditLogsGetWorkspaceAuditLogsRequestSortOrder + +__all__ = ["AuditLogsGetWorkspaceAuditLogsRequestEventType", "AuditLogsGetWorkspaceAuditLogsRequestSortOrder"] diff --git a/src/webflow/resources/workspaces/resources/audit_logs/client.py b/src/webflow/resources/workspaces/resources/audit_logs/client.py new file mode 100644 index 0000000..ea6ebd8 --- /dev/null +++ b/src/webflow/resources/workspaces/resources/audit_logs/client.py @@ -0,0 +1,332 @@ +# This file was auto-generated by Fern from our API Definition. + +from .....core.client_wrapper import SyncClientWrapper +import typing +from .types.audit_logs_get_workspace_audit_logs_request_sort_order import AuditLogsGetWorkspaceAuditLogsRequestSortOrder +from .types.audit_logs_get_workspace_audit_logs_request_event_type import AuditLogsGetWorkspaceAuditLogsRequestEventType +import datetime as dt +from .....core.request_options import RequestOptions +from .....types.workspace_audit_log_response import WorkspaceAuditLogResponse +from .....core.jsonable_encoder import jsonable_encoder +from .....core.datetime_utils import serialize_datetime +from .....core.pydantic_utilities import parse_obj_as +from .....errors.unauthorized_error import UnauthorizedError +from .....types.error import Error +from .....errors.forbidden_error import ForbiddenError +from .....errors.not_found_error import NotFoundError +from .....errors.too_many_requests_error import TooManyRequestsError +from .....errors.internal_server_error import InternalServerError +from json.decoder import JSONDecodeError +from .....core.api_error import ApiError +from .....core.client_wrapper import AsyncClientWrapper + + +class AuditLogsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get_workspace_audit_logs( + self, + workspace_id_or_slug: str, + *, + limit: typing.Optional[float] = None, + offset: typing.Optional[float] = None, + sort_order: typing.Optional[AuditLogsGetWorkspaceAuditLogsRequestSortOrder] = None, + event_type: typing.Optional[AuditLogsGetWorkspaceAuditLogsRequestEventType] = None, + from_: typing.Optional[dt.datetime] = None, + to: typing.Optional[dt.datetime] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> WorkspaceAuditLogResponse: + """ + Get audit logs for a workspace. + + This endpoint requires an Enterprise workspace and a workspace token with the `workspace_activity:read` scope. Create a workspace token from your workspace dashboard integrations page to use this endpoint. + + Required scope | `workspace_activity:read` + + Parameters + ---------- + workspace_id_or_slug : str + Unique identifier or slug for a Workspace + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + sort_order : typing.Optional[AuditLogsGetWorkspaceAuditLogsRequestSortOrder] + Sorts the results by asc or desc + + event_type : typing.Optional[AuditLogsGetWorkspaceAuditLogsRequestEventType] + The event type to filter by + + from_ : typing.Optional[dt.datetime] + The start date to filter by + + to : typing.Optional[dt.datetime] + The end date to filter by + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + WorkspaceAuditLogResponse + A list of workspace audit logs + + Examples + -------- + import datetime + + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.workspaces.audit_logs.get_workspace_audit_logs( + workspace_id_or_slug="hitchhikers-workspace", + from_=datetime.datetime.fromisoformat( + "2024-04-22 16:00:31+00:00", + ), + to=datetime.datetime.fromisoformat( + "2024-04-22 16:00:31+00:00", + ), + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"workspaces/{jsonable_encoder(workspace_id_or_slug)}/audit_logs", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "limit": limit, + "offset": offset, + "sortOrder": sort_order, + "eventType": event_type, + "from": serialize_datetime(from_) if from_ is not None else None, + "to": serialize_datetime(to) if to is not None else None, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + WorkspaceAuditLogResponse, + parse_obj_as( + type_=WorkspaceAuditLogResponse, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + +class AsyncAuditLogsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get_workspace_audit_logs( + self, + workspace_id_or_slug: str, + *, + limit: typing.Optional[float] = None, + offset: typing.Optional[float] = None, + sort_order: typing.Optional[AuditLogsGetWorkspaceAuditLogsRequestSortOrder] = None, + event_type: typing.Optional[AuditLogsGetWorkspaceAuditLogsRequestEventType] = None, + from_: typing.Optional[dt.datetime] = None, + to: typing.Optional[dt.datetime] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> WorkspaceAuditLogResponse: + """ + Get audit logs for a workspace. + + This endpoint requires an Enterprise workspace and a workspace token with the `workspace_activity:read` scope. Create a workspace token from your workspace dashboard integrations page to use this endpoint. + + Required scope | `workspace_activity:read` + + Parameters + ---------- + workspace_id_or_slug : str + Unique identifier or slug for a Workspace + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + sort_order : typing.Optional[AuditLogsGetWorkspaceAuditLogsRequestSortOrder] + Sorts the results by asc or desc + + event_type : typing.Optional[AuditLogsGetWorkspaceAuditLogsRequestEventType] + The event type to filter by + + from_ : typing.Optional[dt.datetime] + The start date to filter by + + to : typing.Optional[dt.datetime] + The end date to filter by + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + WorkspaceAuditLogResponse + A list of workspace audit logs + + Examples + -------- + import asyncio + import datetime + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.workspaces.audit_logs.get_workspace_audit_logs( + workspace_id_or_slug="hitchhikers-workspace", + from_=datetime.datetime.fromisoformat( + "2024-04-22 16:00:31+00:00", + ), + to=datetime.datetime.fromisoformat( + "2024-04-22 16:00:31+00:00", + ), + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"workspaces/{jsonable_encoder(workspace_id_or_slug)}/audit_logs", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "limit": limit, + "offset": offset, + "sortOrder": sort_order, + "eventType": event_type, + "from": serialize_datetime(from_) if from_ is not None else None, + "to": serialize_datetime(to) if to is not None else None, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + WorkspaceAuditLogResponse, + parse_obj_as( + type_=WorkspaceAuditLogResponse, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + 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, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/webflow/resources/workspaces/resources/audit_logs/types/__init__.py b/src/webflow/resources/workspaces/resources/audit_logs/types/__init__.py new file mode 100644 index 0000000..3decf29 --- /dev/null +++ b/src/webflow/resources/workspaces/resources/audit_logs/types/__init__.py @@ -0,0 +1,6 @@ +# This file was auto-generated by Fern from our API Definition. + +from .audit_logs_get_workspace_audit_logs_request_event_type import AuditLogsGetWorkspaceAuditLogsRequestEventType +from .audit_logs_get_workspace_audit_logs_request_sort_order import AuditLogsGetWorkspaceAuditLogsRequestSortOrder + +__all__ = ["AuditLogsGetWorkspaceAuditLogsRequestEventType", "AuditLogsGetWorkspaceAuditLogsRequestSortOrder"] diff --git a/src/webflow/resources/workspaces/resources/audit_logs/types/audit_logs_get_workspace_audit_logs_request_event_type.py b/src/webflow/resources/workspaces/resources/audit_logs/types/audit_logs_get_workspace_audit_logs_request_event_type.py new file mode 100644 index 0000000..950e45b --- /dev/null +++ b/src/webflow/resources/workspaces/resources/audit_logs/types/audit_logs_get_workspace_audit_logs_request_event_type.py @@ -0,0 +1,8 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +AuditLogsGetWorkspaceAuditLogsRequestEventType = typing.Union[ + typing.Literal["user_access", "custom_role", "workspace_membership", "site_membership", "workspace_invitation"], + typing.Any, +] diff --git a/src/webflow/resources/workspaces/resources/audit_logs/types/audit_logs_get_workspace_audit_logs_request_sort_order.py b/src/webflow/resources/workspaces/resources/audit_logs/types/audit_logs_get_workspace_audit_logs_request_sort_order.py new file mode 100644 index 0000000..dd90d5f --- /dev/null +++ b/src/webflow/resources/workspaces/resources/audit_logs/types/audit_logs_get_workspace_audit_logs_request_sort_order.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +AuditLogsGetWorkspaceAuditLogsRequestSortOrder = typing.Union[typing.Literal["asc", "desc"], typing.Any] diff --git a/src/webflow/types/__init__.py b/src/webflow/types/__init__.py index 5b2d8c6..c31dd1a 100644 --- a/src/webflow/types/__init__.py +++ b/src/webflow/types/__init__.py @@ -31,9 +31,19 @@ from .collection_item_with_id_input_field_data import CollectionItemWithIdInputFieldData from .collection_list import CollectionList from .collection_list_array_item import CollectionListArrayItem +from .comment_reply import CommentReply +from .comment_reply_author import CommentReplyAuthor +from .comment_reply_list import CommentReplyList +from .comment_reply_list_pagination import CommentReplyListPagination +from .comment_reply_mentioned_users_item import CommentReplyMentionedUsersItem +from .comment_thread import CommentThread +from .comment_thread_author import CommentThreadAuthor +from .comment_thread_list import CommentThreadList +from .comment_thread_list_pagination import CommentThreadListPagination +from .comment_thread_mentioned_users_item import CommentThreadMentionedUsersItem from .component import Component from .component_dom import ComponentDom -from .component_instance_node_property_overrides_write import ComponentInstanceNodePropertyOverridesWrite +from .component_instance import ComponentInstance from .component_instance_node_property_overrides_write_property_overrides_item import ( ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem, ) @@ -42,11 +52,15 @@ from .component_properties import ComponentProperties from .component_property import ComponentProperty from .component_property_type import ComponentPropertyType +from .conflict import Conflict from .conflict_error_body import ConflictErrorBody 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_role import CustomRole +from .custom_role_audit_log_item import CustomRoleAuditLogItem +from .custom_role_audit_log_item_event_sub_type import CustomRoleAuditLogItemEventSubType from .dom import Dom from .domain import Domain from .domains import Domains @@ -55,7 +69,13 @@ from .error import Error from .error_code import ErrorCode from .field import Field +from .field_create import FieldCreate 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 @@ -74,14 +94,29 @@ from .list_custom_code_blocks import ListCustomCodeBlocks from .locale import Locale from .locales import Locales +from .metadata import Metadata +from .metadata_options_item import MetadataOptionsItem from .no_domains import NoDomains -from .node import Node, Node_ComponentInstance, Node_Image, Node_Text +from .node import ( + Node, + Node_ComponentInstance, + Node_Image, + Node_SearchButton, + Node_Select, + Node_SubmitButton, + Node_Text, + Node_TextInput, +) from .not_enterprise_plan_site import NotEnterprisePlanSite from .not_enterprise_plan_workspace import NotEnterprisePlanWorkspace +from .option_field import OptionField from .order import Order from .order_address import OrderAddress from .order_address_japan_type import OrderAddressJapanType from .order_address_type import OrderAddressType +from .order_billing_address import OrderBillingAddress +from .order_billing_address_japan_type import OrderBillingAddressJapanType +from .order_billing_address_type import OrderBillingAddressType from .order_customer_info import OrderCustomerInfo from .order_dispute_last_status import OrderDisputeLastStatus from .order_download_files_item import OrderDownloadFilesItem @@ -92,6 +127,9 @@ from .order_purchased_item_variant_image import OrderPurchasedItemVariantImage from .order_purchased_item_variant_image_file import OrderPurchasedItemVariantImageFile from .order_purchased_item_variant_image_file_variants_item import OrderPurchasedItemVariantImageFileVariantsItem +from .order_shipping_address import OrderShippingAddress +from .order_shipping_address_japan_type import OrderShippingAddressJapanType +from .order_shipping_address_type import OrderShippingAddressType from .order_status import OrderStatus from .order_totals import OrderTotals from .order_totals_extras_item import OrderTotalsExtrasItem @@ -111,11 +149,22 @@ from .publish_status import PublishStatus from .redirect import Redirect from .redirects import Redirects +from .reference_field import ReferenceField +from .reference_field_metadata import ReferenceFieldMetadata +from .reference_field_type import ReferenceFieldType from .registered_script_list import RegisteredScriptList +from .robots import Robots +from .robots_rules_item import RobotsRulesItem from .script_apply import ScriptApply from .script_apply_list import ScriptApplyList from .script_apply_location import ScriptApplyLocation from .scripts import Scripts +from .search_button import SearchButton +from .search_button_node import SearchButtonNode +from .select import Select +from .select_node import SelectNode +from .select_node_choices_item import SelectNodeChoicesItem +from .select_node_write_choices_item import SelectNodeWriteChoicesItem from .site import Site from .site_activity_log_item import SiteActivityLogItem from .site_activity_log_item_event import SiteActivityLogItemEvent @@ -123,6 +172,9 @@ from .site_activity_log_item_user import SiteActivityLogItemUser from .site_activity_log_response import SiteActivityLogResponse from .site_data_collection_type import SiteDataCollectionType +from .site_membership import SiteMembership +from .site_membership_audit_log_item import SiteMembershipAuditLogItem +from .site_membership_audit_log_item_event_sub_type import SiteMembershipAuditLogItemEventSubType from .site_plan import SitePlan from .site_plan_id import SitePlanId from .site_plan_name import SitePlanName @@ -139,16 +191,24 @@ from .sku_property_list import SkuPropertyList from .sku_property_list_enum_item import SkuPropertyListEnumItem from .sku_value_list import SkuValueList +from .static_field import StaticField +from .static_field_type import StaticFieldType from .stripe_card import StripeCard from .stripe_card_brand import StripeCardBrand from .stripe_card_expires import StripeCardExpires from .stripe_details import StripeDetails +from .submit_button import SubmitButton +from .submit_button_node import SubmitButtonNode from .text import Text +from .text_input import TextInput +from .text_input_node import TextInputNode from .text_node import TextNode from .text_node_text import TextNodeText -from .text_node_write import TextNodeWrite from .trigger_type import TriggerType from .user import User +from .user_access import UserAccess +from .user_access_audit_log_item import UserAccessAuditLogItem +from .user_access_audit_log_item_event_sub_type import UserAccessAuditLogItemEventSubType from .user_access_groups_item import UserAccessGroupsItem from .user_access_groups_item_type import UserAccessGroupsItemType from .user_data import UserData @@ -160,6 +220,50 @@ from .webhook import Webhook from .webhook_filter import WebhookFilter from .webhook_list import WebhookList +from .workspace_audit_log_item import ( + WorkspaceAuditLogItem, + WorkspaceAuditLogItem_CustomRole, + WorkspaceAuditLogItem_SiteMembership, + WorkspaceAuditLogItem_UserAccess, + WorkspaceAuditLogItem_WorkspaceInvitation, + WorkspaceAuditLogItem_WorkspaceMembership, +) +from .workspace_audit_log_item_actor import WorkspaceAuditLogItemActor +from .workspace_audit_log_item_payload_site_membership_method import WorkspaceAuditLogItemPayloadSiteMembershipMethod +from .workspace_audit_log_item_payload_site_membership_site import WorkspaceAuditLogItemPayloadSiteMembershipSite +from .workspace_audit_log_item_payload_site_membership_target_user import ( + WorkspaceAuditLogItemPayloadSiteMembershipTargetUser, +) +from .workspace_audit_log_item_payload_site_membership_user_type import ( + WorkspaceAuditLogItemPayloadSiteMembershipUserType, +) +from .workspace_audit_log_item_payload_user_access_method import WorkspaceAuditLogItemPayloadUserAccessMethod +from .workspace_audit_log_item_payload_workspace_invitation_method import ( + WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod, +) +from .workspace_audit_log_item_payload_workspace_invitation_target_user import ( + WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser, +) +from .workspace_audit_log_item_payload_workspace_invitation_user_type import ( + WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType, +) +from .workspace_audit_log_item_payload_workspace_membership_method import ( + WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod, +) +from .workspace_audit_log_item_payload_workspace_membership_target_user import ( + WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser, +) +from .workspace_audit_log_item_payload_workspace_membership_user_type import ( + WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType, +) +from .workspace_audit_log_item_workspace import WorkspaceAuditLogItemWorkspace +from .workspace_audit_log_response import WorkspaceAuditLogResponse +from .workspace_invitation import WorkspaceInvitation +from .workspace_invitation_audit_log_item import WorkspaceInvitationAuditLogItem +from .workspace_invitation_audit_log_item_event_sub_type import WorkspaceInvitationAuditLogItemEventSubType +from .workspace_membership import WorkspaceMembership +from .workspace_membership_audit_log_item import WorkspaceMembershipAuditLogItem +from .workspace_membership_audit_log_item_event_sub_type import WorkspaceMembershipAuditLogItemEventSubType __all__ = [ "AccessGroup", @@ -193,20 +297,34 @@ "CollectionItemWithIdInputFieldData", "CollectionList", "CollectionListArrayItem", + "CommentReply", + "CommentReplyAuthor", + "CommentReplyList", + "CommentReplyListPagination", + "CommentReplyMentionedUsersItem", + "CommentThread", + "CommentThreadAuthor", + "CommentThreadList", + "CommentThreadListPagination", + "CommentThreadMentionedUsersItem", "Component", "ComponentDom", - "ComponentInstanceNodePropertyOverridesWrite", + "ComponentInstance", "ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem", "ComponentList", "ComponentNode", "ComponentProperties", "ComponentProperty", "ComponentPropertyType", + "Conflict", "ConflictErrorBody", "CustomCodeBlock", "CustomCodeBlockType", "CustomCodeHostedResponse", "CustomCodeInlineResponse", + "CustomRole", + "CustomRoleAuditLogItem", + "CustomRoleAuditLogItemEventSubType", "Dom", "Domain", "Domains", @@ -215,7 +333,11 @@ "Error", "ErrorCode", "Field", + "FieldCreate", "FieldType", + "FieldValidations", + "FieldValidationsAdditionalProperties", + "FieldValidationsAdditionalPropertiesAdditionalProperties", "ForbiddenErrorBody", "Form", "FormField", @@ -234,17 +356,27 @@ "ListCustomCodeBlocks", "Locale", "Locales", + "Metadata", + "MetadataOptionsItem", "NoDomains", "Node", "Node_ComponentInstance", "Node_Image", + "Node_SearchButton", + "Node_Select", + "Node_SubmitButton", "Node_Text", + "Node_TextInput", "NotEnterprisePlanSite", "NotEnterprisePlanWorkspace", + "OptionField", "Order", "OrderAddress", "OrderAddressJapanType", "OrderAddressType", + "OrderBillingAddress", + "OrderBillingAddressJapanType", + "OrderBillingAddressType", "OrderCustomerInfo", "OrderDisputeLastStatus", "OrderDownloadFilesItem", @@ -255,6 +387,9 @@ "OrderPurchasedItemVariantImage", "OrderPurchasedItemVariantImageFile", "OrderPurchasedItemVariantImageFileVariantsItem", + "OrderShippingAddress", + "OrderShippingAddressJapanType", + "OrderShippingAddressType", "OrderStatus", "OrderTotals", "OrderTotalsExtrasItem", @@ -274,11 +409,22 @@ "PublishStatus", "Redirect", "Redirects", + "ReferenceField", + "ReferenceFieldMetadata", + "ReferenceFieldType", "RegisteredScriptList", + "Robots", + "RobotsRulesItem", "ScriptApply", "ScriptApplyList", "ScriptApplyLocation", "Scripts", + "SearchButton", + "SearchButtonNode", + "Select", + "SelectNode", + "SelectNodeChoicesItem", + "SelectNodeWriteChoicesItem", "Site", "SiteActivityLogItem", "SiteActivityLogItemEvent", @@ -286,6 +432,9 @@ "SiteActivityLogItemUser", "SiteActivityLogResponse", "SiteDataCollectionType", + "SiteMembership", + "SiteMembershipAuditLogItem", + "SiteMembershipAuditLogItemEventSubType", "SitePlan", "SitePlanId", "SitePlanName", @@ -302,16 +451,24 @@ "SkuPropertyList", "SkuPropertyListEnumItem", "SkuValueList", + "StaticField", + "StaticFieldType", "StripeCard", "StripeCardBrand", "StripeCardExpires", "StripeDetails", + "SubmitButton", + "SubmitButtonNode", "Text", + "TextInput", + "TextInputNode", "TextNode", "TextNodeText", - "TextNodeWrite", "TriggerType", "User", + "UserAccess", + "UserAccessAuditLogItem", + "UserAccessAuditLogItemEventSubType", "UserAccessGroupsItem", "UserAccessGroupsItemType", "UserData", @@ -323,4 +480,30 @@ "Webhook", "WebhookFilter", "WebhookList", + "WorkspaceAuditLogItem", + "WorkspaceAuditLogItemActor", + "WorkspaceAuditLogItemPayloadSiteMembershipMethod", + "WorkspaceAuditLogItemPayloadSiteMembershipSite", + "WorkspaceAuditLogItemPayloadSiteMembershipTargetUser", + "WorkspaceAuditLogItemPayloadSiteMembershipUserType", + "WorkspaceAuditLogItemPayloadUserAccessMethod", + "WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod", + "WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser", + "WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType", + "WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod", + "WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser", + "WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType", + "WorkspaceAuditLogItemWorkspace", + "WorkspaceAuditLogItem_CustomRole", + "WorkspaceAuditLogItem_SiteMembership", + "WorkspaceAuditLogItem_UserAccess", + "WorkspaceAuditLogItem_WorkspaceInvitation", + "WorkspaceAuditLogItem_WorkspaceMembership", + "WorkspaceAuditLogResponse", + "WorkspaceInvitation", + "WorkspaceInvitationAuditLogItem", + "WorkspaceInvitationAuditLogItemEventSubType", + "WorkspaceMembership", + "WorkspaceMembershipAuditLogItem", + "WorkspaceMembershipAuditLogItemEventSubType", ] diff --git a/src/webflow/types/application.py b/src/webflow/types/application.py index ac819f0..b11f910 100644 --- a/src/webflow/types/application.py +++ b/src/webflow/types/application.py @@ -1,5 +1,41 @@ # This file was auto-generated by Fern from our API Definition. +from ..core.pydantic_utilities import UniversalBaseModel import typing +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 -Application = typing.Optional[typing.Any] + +class Application(UniversalBaseModel): + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Unique identifier for the Application + """ + + description: typing.Optional[str] = pydantic.Field(default=None) + """ + Application description provided by the developer + """ + + homepage: typing.Optional[str] = pydantic.Field(default=None) + """ + Application homepage URL provided by the developer + """ + + display_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="displayName")] = ( + pydantic.Field(default=None) + ) + """ + Application name provided by the developer + """ + + 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 b67cefa..8ebad3b 100644 --- a/src/webflow/types/asset.py +++ b/src/webflow/types/asset.py @@ -11,6 +11,10 @@ class Asset(UniversalBaseModel): + """ + Asset details + """ + id: typing.Optional[str] = pydantic.Field(default=None) """ Unique identifier for this asset @@ -49,9 +53,7 @@ class Asset(UniversalBaseModel): Original file name at the time of upload """ - display_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="displayName")] = ( - pydantic.Field(default=None) - ) + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() """ Display name of the asset """ @@ -70,7 +72,11 @@ class Asset(UniversalBaseModel): Date the asset metadata was created """ - variants: typing.Optional[typing.List[AssetVariant]] = None + variants: typing.List[AssetVariant] = pydantic.Field() + """ + A list of [asset variants](https://help.webflow.com/hc/en-us/articles/33961378697107-Responsive-images) created by Webflow to serve your site responsively. + """ + alt_text: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="altText")] = pydantic.Field( default=None ) diff --git a/src/webflow/types/asset_variant.py b/src/webflow/types/asset_variant.py index 5278667..0ad16f1 100644 --- a/src/webflow/types/asset_variant.py +++ b/src/webflow/types/asset_variant.py @@ -2,40 +2,38 @@ from ..core.pydantic_utilities import UniversalBaseModel import typing_extensions -import typing from ..core.serialization import FieldMetadata import pydantic +import typing from ..core.pydantic_utilities import IS_PYDANTIC_V2 class AssetVariant(UniversalBaseModel): - hosted_url: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="hostedUrl")] = pydantic.Field( - default=None - ) + """ + Asset variant details + """ + + hosted_url: typing_extensions.Annotated[str, FieldMetadata(alias="hostedUrl")] = pydantic.Field() """ URL of where the asset variant is hosted """ - original_file_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="originalFileName")] = ( - pydantic.Field(default=None) - ) + original_file_name: typing_extensions.Annotated[str, FieldMetadata(alias="originalFileName")] = pydantic.Field() """ Original file name of the variant """ - display_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="displayName")] = ( - pydantic.Field(default=None) - ) + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() """ Display name of the variant """ - format: typing.Optional[str] = pydantic.Field(default=None) + format: str = pydantic.Field() """ format of the variant """ - width: typing.Optional[int] = pydantic.Field(default=None) + width: int = pydantic.Field() """ Width in pixels """ @@ -45,7 +43,7 @@ class AssetVariant(UniversalBaseModel): Height in pixels """ - quality: typing.Optional[int] = pydantic.Field(default=None) + quality: int = pydantic.Field() """ Value between 0 and 100 representing the image quality """ diff --git a/src/webflow/types/assets.py b/src/webflow/types/assets.py index 380b0de..bd5f8ea 100644 --- a/src/webflow/types/assets.py +++ b/src/webflow/types/assets.py @@ -3,6 +3,7 @@ from ..core.pydantic_utilities import UniversalBaseModel import typing from .asset import Asset +from .pagination import Pagination from ..core.pydantic_utilities import IS_PYDANTIC_V2 import pydantic @@ -13,6 +14,7 @@ class Assets(UniversalBaseModel): """ assets: typing.Optional[typing.List[Asset]] = None + pagination: typing.Optional[Pagination] = 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/bulk_collection_item.py b/src/webflow/types/bulk_collection_item.py index 4d17d13..de8e770 100644 --- a/src/webflow/types/bulk_collection_item.py +++ b/src/webflow/types/bulk_collection_item.py @@ -1,9 +1,9 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel +import typing import pydantic import typing_extensions -import typing from ..core.serialization import FieldMetadata from .bulk_collection_item_field_data import BulkCollectionItemFieldData from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -14,7 +14,7 @@ class BulkCollectionItem(UniversalBaseModel): The fields that define the schema for a given Item are based on the Collection that Item belongs to. Beyond the user defined fields, there are a handful of additional fields that are automatically created for all items """ - id: str = pydantic.Field() + id: typing.Optional[str] = pydantic.Field(default=None) """ Unique identifier for the Item """ diff --git a/src/webflow/types/collection.py b/src/webflow/types/collection.py index 81e0f90..5e1dd67 100644 --- a/src/webflow/types/collection.py +++ b/src/webflow/types/collection.py @@ -1,9 +1,9 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel +import typing import pydantic import typing_extensions -import typing from ..core.serialization import FieldMetadata import datetime as dt from .field import Field @@ -15,21 +15,17 @@ class Collection(UniversalBaseModel): A collection object """ - id: str = pydantic.Field() + id: typing.Optional[str] = pydantic.Field(default=None) """ Unique identifier for a Collection """ - display_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="displayName")] = ( - pydantic.Field(default=None) - ) + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() """ Name given to the Collection """ - singular_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="singularName")] = ( - pydantic.Field(default=None) - ) + singular_name: typing_extensions.Annotated[str, FieldMetadata(alias="singularName")] = pydantic.Field() """ The name of one Item in Collection (e.g. ”Blog Post” if the Collection is called “Blog Posts”) """ diff --git a/src/webflow/types/collection_list_array_item.py b/src/webflow/types/collection_list_array_item.py index 77e518a..d3abf5a 100644 --- a/src/webflow/types/collection_list_array_item.py +++ b/src/webflow/types/collection_list_array_item.py @@ -1,9 +1,9 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel +import typing import pydantic import typing_extensions -import typing from ..core.serialization import FieldMetadata import datetime as dt from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -14,7 +14,7 @@ class CollectionListArrayItem(UniversalBaseModel): A collection object """ - id: str = pydantic.Field() + id: typing.Optional[str] = pydantic.Field(default=None) """ Unique identifier for a Collection """ diff --git a/src/webflow/types/comment_reply.py b/src/webflow/types/comment_reply.py new file mode 100644 index 0000000..f1626aa --- /dev/null +++ b/src/webflow/types/comment_reply.py @@ -0,0 +1,95 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from .comment_reply_author import CommentReplyAuthor +from .comment_reply_mentioned_users_item import CommentReplyMentionedUsersItem +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class CommentReply(UniversalBaseModel): + """ + A comment thread represents a conversation between users on a specific page. Each comment thread has a unique identifier and can contain multiple comments. + """ + + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Unique identifier for the comment thread + """ + + comment_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="commentId")] = pydantic.Field( + default=None + ) + """ + The comment reply unique identifier + """ + + site_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="siteId")] = pydantic.Field( + default=None + ) + """ + The site unique identifier + """ + + page_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="pageId")] = pydantic.Field( + default=None + ) + """ + The page unique identifier + """ + + locale_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="localeId")] = pydantic.Field( + default=None + ) + """ + The locale unique identifier + """ + + breakpoint: typing.Optional[str] = pydantic.Field(default=None) + """ + The breakpoint the comment was left on + """ + + content: str = pydantic.Field() + """ + The content of the comment reply + """ + + is_resolved: typing_extensions.Annotated[bool, FieldMetadata(alias="isResolved")] = pydantic.Field() + """ + Boolean determining if the comment thread is resolved + """ + + author: CommentReplyAuthor + mentioned_users: typing_extensions.Annotated[ + typing.Optional[typing.List[CommentReplyMentionedUsersItem]], FieldMetadata(alias="mentionedUsers") + ] = pydantic.Field(default=None) + """ + List of mentioned users is an empty array until email notifications are sent. + """ + + last_updated: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="lastUpdated")] = ( + pydantic.Field(default=None) + ) + """ + The date the item was last updated + """ + + created_on: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="createdOn")] = pydantic.Field( + default=None + ) + """ + The date the item was created + """ + + 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/comment_reply_author.py b/src/webflow/types/comment_reply_author.py new file mode 100644 index 0000000..7509b7e --- /dev/null +++ b/src/webflow/types/comment_reply_author.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentReplyAuthor(UniversalBaseModel): + id: str = pydantic.Field() + """ + The unique identifier of the author + """ + + email: str = pydantic.Field() + """ + Email of the author + """ + + name: str = pydantic.Field() + """ + Name of the author + """ + + 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/comment_reply_list.py b/src/webflow/types/comment_reply_list.py new file mode 100644 index 0000000..c382932 --- /dev/null +++ b/src/webflow/types/comment_reply_list.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .comment_reply import CommentReply +from .comment_reply_list_pagination import CommentReplyListPagination +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class CommentReplyList(UniversalBaseModel): + """ + A list of comment replies. + """ + + comments: typing.List[CommentReply] + pagination: CommentReplyListPagination + + 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/comment_reply_list_pagination.py b/src/webflow/types/comment_reply_list_pagination.py new file mode 100644 index 0000000..7fa5c8e --- /dev/null +++ b/src/webflow/types/comment_reply_list_pagination.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentReplyListPagination(UniversalBaseModel): + limit: float = pydantic.Field() + """ + The limit specified in the request (default 100) + """ + + offset: float = pydantic.Field() + """ + The offset specified for pagination + """ + + total: float = pydantic.Field() + """ + Total number of comment replies + """ + + 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/comment_reply_mentioned_users_item.py b/src/webflow/types/comment_reply_mentioned_users_item.py new file mode 100644 index 0000000..12324d9 --- /dev/null +++ b/src/webflow/types/comment_reply_mentioned_users_item.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentReplyMentionedUsersItem(UniversalBaseModel): + id: str = pydantic.Field() + """ + The unique identifier of the mentioned user + """ + + email: str = pydantic.Field() + """ + Email of the user + """ + + name: str = pydantic.Field() + """ + Name of the User + """ + + 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/comment_thread.py b/src/webflow/types/comment_thread.py new file mode 100644 index 0000000..5bca3da --- /dev/null +++ b/src/webflow/types/comment_thread.py @@ -0,0 +1,100 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from .comment_thread_author import CommentThreadAuthor +from .comment_thread_mentioned_users_item import CommentThreadMentionedUsersItem +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class CommentThread(UniversalBaseModel): + """ + A comment thread represents a conversation between users on a specific page. Each comment thread has a unique identifier and can contain multiple comments. Retrieve comment replies using the replies API endpoint. + """ + + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Unique identifier for the comment thread + """ + + site_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="siteId")] = pydantic.Field( + default=None + ) + """ + The site unique identifier + """ + + page_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="pageId")] = pydantic.Field( + default=None + ) + """ + The page unique identifier + """ + + locale_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="localeId")] = pydantic.Field( + default=None + ) + """ + The locale unique identifier + """ + + item_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="itemId")] = pydantic.Field( + default=None + ) + """ + The item unique identifier + """ + + breakpoint: typing.Optional[str] = pydantic.Field(default=None) + """ + The breakpoint the comment was left on + """ + + url: typing.Optional[str] = pydantic.Field(default=None) + """ + The URL of the page the comment was left on + """ + + content: str = pydantic.Field() + """ + The content of the comment reply + """ + + is_resolved: typing_extensions.Annotated[bool, FieldMetadata(alias="isResolved")] = pydantic.Field() + """ + Boolean determining if the comment thread is resolved + """ + + author: CommentThreadAuthor + mentioned_users: typing_extensions.Annotated[ + typing.List[CommentThreadMentionedUsersItem], FieldMetadata(alias="mentionedUsers") + ] = pydantic.Field() + """ + List of mentioned users. This is an empty array until email notifications are sent, which can take up to 5 minutes after the comment is created. + """ + + created_on: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="createdOn")] = pydantic.Field( + default=None + ) + """ + The date the item was created + """ + + last_updated: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="lastUpdated")] = ( + pydantic.Field(default=None) + ) + """ + The date the item was last updated + """ + + 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/comment_thread_author.py b/src/webflow/types/comment_thread_author.py new file mode 100644 index 0000000..c2f1b1e --- /dev/null +++ b/src/webflow/types/comment_thread_author.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentThreadAuthor(UniversalBaseModel): + user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] = pydantic.Field() + """ + The unique identifier of the author + """ + + email: str = pydantic.Field() + """ + Email of the author + """ + + name: str = pydantic.Field() + """ + Name of the author + """ + + 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/comment_thread_list.py b/src/webflow/types/comment_thread_list.py new file mode 100644 index 0000000..f46e6bd --- /dev/null +++ b/src/webflow/types/comment_thread_list.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .comment_thread import CommentThread +from .comment_thread_list_pagination import CommentThreadListPagination +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class CommentThreadList(UniversalBaseModel): + """ + A list of comment threads on the site. Contains the content of the first reply. + """ + + comments: typing.List[CommentThread] + pagination: CommentThreadListPagination + + 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/comment_thread_list_pagination.py b/src/webflow/types/comment_thread_list_pagination.py new file mode 100644 index 0000000..e5d55bb --- /dev/null +++ b/src/webflow/types/comment_thread_list_pagination.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentThreadListPagination(UniversalBaseModel): + limit: float = pydantic.Field() + """ + The limit specified in the request (default 100) + """ + + offset: float = pydantic.Field() + """ + The offset specified for pagination + """ + + total: float = pydantic.Field() + """ + Total number of comment threads + """ + + 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/comment_thread_mentioned_users_item.py b/src/webflow/types/comment_thread_mentioned_users_item.py new file mode 100644 index 0000000..f9a20df --- /dev/null +++ b/src/webflow/types/comment_thread_mentioned_users_item.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentThreadMentionedUsersItem(UniversalBaseModel): + user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] = pydantic.Field() + """ + The unique identifier of the mentioned user + """ + + email: str = pydantic.Field() + """ + Email of the user + """ + + name: str = pydantic.Field() + """ + Name of the User + """ + + 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.py b/src/webflow/types/component.py index ae6fea2..3619bcf 100644 --- a/src/webflow/types/component.py +++ b/src/webflow/types/component.py @@ -1,8 +1,8 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel -import pydantic import typing +import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -11,7 +11,7 @@ class Component(UniversalBaseModel): The Component object """ - id: str = pydantic.Field() + id: typing.Optional[str] = pydantic.Field(default=None) """ Unique identifier for the Component """ diff --git a/src/webflow/types/component_dom.py b/src/webflow/types/component_dom.py index 3f76c81..2f70fc4 100644 --- a/src/webflow/types/component_dom.py +++ b/src/webflow/types/component_dom.py @@ -12,7 +12,7 @@ class ComponentDom(UniversalBaseModel): """ - The Component DOM schema represents the content structure of a component. Similar to Page DOM, it captures various content nodes and their associated attributes, but specifically for a component's structure. Each node has a unique identifier and can contain text, images, or nested component instances. + The Component DOM schema represents the content structure of a component. Similar to Page DOM, it captures various content nodes and their associated attributes, but specifically for a component's structure. Each node has a unique identifier and can contain text, images, select or text inputs, submit buttons, or nested component instances. """ component_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="componentId")] = ( diff --git a/src/webflow/types/component_instance_node_property_overrides_write.py b/src/webflow/types/component_instance.py similarity index 94% rename from src/webflow/types/component_instance_node_property_overrides_write.py rename to src/webflow/types/component_instance.py index 6c7d69c..301324f 100644 --- a/src/webflow/types/component_instance_node_property_overrides_write.py +++ b/src/webflow/types/component_instance.py @@ -11,7 +11,7 @@ from ..core.pydantic_utilities import IS_PYDANTIC_V2 -class ComponentInstanceNodePropertyOverridesWrite(UniversalBaseModel): +class ComponentInstance(UniversalBaseModel): """ Update text property overrides of a component instance """ diff --git a/src/webflow/types/component_node.py b/src/webflow/types/component_node.py index fa5f69d..6f371d6 100644 --- a/src/webflow/types/component_node.py +++ b/src/webflow/types/component_node.py @@ -16,19 +16,17 @@ class ComponentNode(UniversalBaseModel): id: typing.Optional[str] = pydantic.Field(default=None) """ - Node UUID + The unique identifier of the component instance node """ - component_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="componentId")] = ( - pydantic.Field(default=None) - ) + component_id: typing_extensions.Annotated[str, FieldMetadata(alias="componentId")] = pydantic.Field() """ - Component ID + The unique identifier of the component """ property_overrides: typing_extensions.Annotated[ - typing.Optional[typing.List[ComponentProperty]], FieldMetadata(alias="propertyOverrides") - ] = pydantic.Field(default=None) + typing.List[ComponentProperty], FieldMetadata(alias="propertyOverrides") + ] = pydantic.Field() """ List of component properties with overrides for a component instance. """ diff --git a/src/webflow/types/conflict.py b/src/webflow/types/conflict.py new file mode 100644 index 0000000..30b9809 --- /dev/null +++ b/src/webflow/types/conflict.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +Conflict = typing.Optional[typing.Any] diff --git a/src/webflow/types/custom_role.py b/src/webflow/types/custom_role.py new file mode 100644 index 0000000..f8c9440 --- /dev/null +++ b/src/webflow/types/custom_role.py @@ -0,0 +1,33 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from ..core.serialization import FieldMetadata +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class CustomRole(UniversalBaseModel): + role_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="roleName")] = pydantic.Field( + default=None + ) + """ + The name of the custom role + """ + + previous_role_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="previousRoleName")] = ( + pydantic.Field(default=None) + ) + """ + The previous name of the custom role + """ + + 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_role_audit_log_item.py b/src/webflow/types/custom_role_audit_log_item.py new file mode 100644 index 0000000..336aa26 --- /dev/null +++ b/src/webflow/types/custom_role_audit_log_item.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from .custom_role_audit_log_item_event_sub_type import CustomRoleAuditLogItemEventSubType +from ..core.serialization import FieldMetadata +from .custom_role import CustomRole +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class CustomRoleAuditLogItem(UniversalBaseModel): + event_sub_type: typing_extensions.Annotated[ + typing.Optional[CustomRoleAuditLogItemEventSubType], FieldMetadata(alias="eventSubType") + ] = None + payload: typing.Optional[CustomRole] = 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_role_audit_log_item_event_sub_type.py b/src/webflow/types/custom_role_audit_log_item_event_sub_type.py new file mode 100644 index 0000000..38d177b --- /dev/null +++ b/src/webflow/types/custom_role_audit_log_item_event_sub_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CustomRoleAuditLogItemEventSubType = typing.Union[ + typing.Literal["role_created", "role_updated", "role_deleted"], typing.Any +] diff --git a/src/webflow/types/dom.py b/src/webflow/types/dom.py index ce15a6a..693da07 100644 --- a/src/webflow/types/dom.py +++ b/src/webflow/types/dom.py @@ -7,6 +7,7 @@ import pydantic from .node import Node from .pagination import Pagination +import datetime as dt from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -24,6 +25,12 @@ class Dom(UniversalBaseModel): nodes: typing.Optional[typing.List[Node]] = None pagination: typing.Optional[Pagination] = None + last_updated: typing_extensions.Annotated[typing.Optional[dt.datetime], FieldMetadata(alias="lastUpdated")] = ( + pydantic.Field(default=None) + ) + """ + The date the page dom was most recently updated + """ 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/domain.py b/src/webflow/types/domain.py index e678d1d..5721163 100644 --- a/src/webflow/types/domain.py +++ b/src/webflow/types/domain.py @@ -1,8 +1,8 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel -import pydantic import typing +import pydantic import typing_extensions import datetime as dt from ..core.serialization import FieldMetadata @@ -10,7 +10,7 @@ class Domain(UniversalBaseModel): - id: str = pydantic.Field() + id: typing.Optional[str] = pydantic.Field(default=None) """ Unique identifier for the Domain """ diff --git a/src/webflow/types/field.py b/src/webflow/types/field.py index 40233a9..9827e8c 100644 --- a/src/webflow/types/field.py +++ b/src/webflow/types/field.py @@ -1,11 +1,12 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel +import typing import pydantic import typing_extensions from ..core.serialization import FieldMetadata -import typing from .field_type import FieldType +from .field_validations import FieldValidations from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -14,7 +15,7 @@ class Field(UniversalBaseModel): The details of a field in a collection """ - id: str = pydantic.Field() + id: typing.Optional[str] = pydantic.Field(default=None) """ Unique identifier for a Field """ @@ -53,6 +54,11 @@ class Field(UniversalBaseModel): Additional text to help anyone filling out this field """ + validations: typing.Optional[FieldValidations] = pydantic.Field(default=None) + """ + The validations for the field + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/webflow/types/field_create.py b/src/webflow/types/field_create.py new file mode 100644 index 0000000..1c9cf61 --- /dev/null +++ b/src/webflow/types/field_create.py @@ -0,0 +1,8 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from .static_field import StaticField +from .option_field import OptionField +from .reference_field import ReferenceField + +FieldCreate = typing.Union[StaticField, OptionField, ReferenceField] diff --git a/src/webflow/types/field_type.py b/src/webflow/types/field_type.py index 6318a3d..e3495ce 100644 --- a/src/webflow/types/field_type.py +++ b/src/webflow/types/field_type.py @@ -8,15 +8,19 @@ "DateTime", "Email", "ExtFileRef", + "File", "Image", "Link", "MultiImage", + "MultiReference", "Number", + "Option", "Phone", "PlainText", + "Reference", "RichText", "Switch", - "Video", + "VideoLink", ], typing.Any, ] diff --git a/src/webflow/types/field_validations.py b/src/webflow/types/field_validations.py new file mode 100644 index 0000000..ca58a0b --- /dev/null +++ b/src/webflow/types/field_validations.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from .field_validations_additional_properties import FieldValidationsAdditionalProperties +from ..core.serialization import FieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class FieldValidations(UniversalBaseModel): + """ + The validations for the field + """ + + additional_properties: typing_extensions.Annotated[ + typing.Optional[FieldValidationsAdditionalProperties], FieldMetadata(alias="additionalProperties") + ] = 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/field_validations_additional_properties.py b/src/webflow/types/field_validations_additional_properties.py new file mode 100644 index 0000000..ba31807 --- /dev/null +++ b/src/webflow/types/field_validations_additional_properties.py @@ -0,0 +1,10 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from .field_validations_additional_properties_additional_properties import ( + FieldValidationsAdditionalPropertiesAdditionalProperties, +) + +FieldValidationsAdditionalProperties = typing.Union[ + str, float, bool, int, FieldValidationsAdditionalPropertiesAdditionalProperties +] diff --git a/src/webflow/types/field_validations_additional_properties_additional_properties.py b/src/webflow/types/field_validations_additional_properties_additional_properties.py new file mode 100644 index 0000000..da6a9ee --- /dev/null +++ b/src/webflow/types/field_validations_additional_properties_additional_properties.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from ..core.serialization import FieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class FieldValidationsAdditionalPropertiesAdditionalProperties(UniversalBaseModel): + additional_properties: typing_extensions.Annotated[ + typing.Optional[typing.Optional[typing.Any]], FieldMetadata(alias="additionalProperties") + ] = 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/image_node.py b/src/webflow/types/image_node.py index 2351cea..3deaf19 100644 --- a/src/webflow/types/image_node.py +++ b/src/webflow/types/image_node.py @@ -17,7 +17,11 @@ class ImageNode(UniversalBaseModel): Node UUID """ - image: typing.Optional[ImageNodeImage] = None + image: ImageNodeImage = pydantic.Field() + """ + The image details of the node + """ + attributes: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None) """ The custom attributes of the node diff --git a/src/webflow/types/image_node_image.py b/src/webflow/types/image_node_image.py index 2ef819f..f8d9379 100644 --- a/src/webflow/types/image_node_image.py +++ b/src/webflow/types/image_node_image.py @@ -9,6 +9,10 @@ class ImageNodeImage(UniversalBaseModel): + """ + The image details of the node + """ + alt: typing.Optional[str] = None asset_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="assetId")] = None diff --git a/src/webflow/types/metadata.py b/src/webflow/types/metadata.py new file mode 100644 index 0000000..1c9caa7 --- /dev/null +++ b/src/webflow/types/metadata.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .metadata_options_item import MetadataOptionsItem +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class Metadata(UniversalBaseModel): + """ + The metadata for the Option field. + """ + + options: typing.List[MetadataOptionsItem] = pydantic.Field() + """ + The option values for the Option field. + """ + + 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/metadata_options_item.py b/src/webflow/types/metadata_options_item.py new file mode 100644 index 0000000..91eb360 --- /dev/null +++ b/src/webflow/types/metadata_options_item.py @@ -0,0 +1,31 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class MetadataOptionsItem(UniversalBaseModel): + """ + A single option value for the Option field. + """ + + name: str = pydantic.Field() + """ + The name of the option + """ + + id: typing.Optional[str] = pydantic.Field(default=None) + """ + The unique identifier of the option + """ + + 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/node.py b/src/webflow/types/node.py index cd0942f..2feb92d 100644 --- a/src/webflow/types/node.py +++ b/src/webflow/types/node.py @@ -10,6 +10,7 @@ import typing_extensions from ..core.serialization import FieldMetadata from .component_property import ComponentProperty +from .select_node_choices_item import SelectNodeChoicesItem class Node_Text(UniversalBaseModel): @@ -19,7 +20,7 @@ class Node_Text(UniversalBaseModel): type: typing.Literal["text"] = "text" id: typing.Optional[str] = None - text: typing.Optional[TextNodeText] = None + text: TextNodeText attributes: typing.Optional[typing.Dict[str, str]] = None if IS_PYDANTIC_V2: @@ -39,7 +40,7 @@ class Node_Image(UniversalBaseModel): type: typing.Literal["image"] = "image" id: typing.Optional[str] = None - image: typing.Optional[ImageNodeImage] = None + image: ImageNodeImage attributes: typing.Optional[typing.Dict[str, str]] = None if IS_PYDANTIC_V2: @@ -59,10 +60,10 @@ class Node_ComponentInstance(UniversalBaseModel): type: typing.Literal["component-instance"] = "component-instance" id: typing.Optional[str] = None - component_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="componentId")] = None + component_id: typing_extensions.Annotated[str, FieldMetadata(alias="componentId")] property_overrides: typing_extensions.Annotated[ - typing.Optional[typing.List[ComponentProperty]], FieldMetadata(alias="propertyOverrides") - ] = None + typing.List[ComponentProperty], FieldMetadata(alias="propertyOverrides") + ] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -74,4 +75,87 @@ class Config: extra = pydantic.Extra.allow -Node = typing.Union[Node_Text, Node_Image, Node_ComponentInstance] +class Node_TextInput(UniversalBaseModel): + """ + A generic representation of a content element within the Document Object Model (DOM). Each node has a unique identifier and a specific type that determines its content structure and attributes. + """ + + type: typing.Literal["text-input"] = "text-input" + id: typing.Optional[str] = None + placeholder: str + attributes: typing.Optional[typing.Dict[str, str]] = 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 + + +class Node_Select(UniversalBaseModel): + """ + A generic representation of a content element within the Document Object Model (DOM). Each node has a unique identifier and a specific type that determines its content structure and attributes. + """ + + type: typing.Literal["select"] = "select" + id: typing.Optional[str] = None + choices: typing.List[SelectNodeChoicesItem] + attributes: typing.Optional[typing.Dict[str, str]] = 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 + + +class Node_SubmitButton(UniversalBaseModel): + """ + A generic representation of a content element within the Document Object Model (DOM). Each node has a unique identifier and a specific type that determines its content structure and attributes. + """ + + type: typing.Literal["submit-button"] = "submit-button" + id: typing.Optional[str] = None + value: str + waiting_text: typing_extensions.Annotated[str, FieldMetadata(alias="waitingText")] + attributes: typing.Optional[typing.Dict[str, str]] = 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 + + +class Node_SearchButton(UniversalBaseModel): + """ + A generic representation of a content element within the Document Object Model (DOM). Each node has a unique identifier and a specific type that determines its content structure and attributes. + """ + + type: typing.Literal["search-button"] = "search-button" + id: typing.Optional[str] = None + value: str + attributes: typing.Optional[typing.Dict[str, str]] = 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 + + +Node = typing.Union[ + Node_Text, Node_Image, Node_ComponentInstance, Node_TextInput, Node_Select, Node_SubmitButton, Node_SearchButton +] diff --git a/src/webflow/types/option_field.py b/src/webflow/types/option_field.py new file mode 100644 index 0000000..7f7c6d5 --- /dev/null +++ b/src/webflow/types/option_field.py @@ -0,0 +1,58 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from .metadata import Metadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class OptionField(UniversalBaseModel): + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Unique identifier for a Field + """ + + is_editable: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isEditable")] = pydantic.Field( + default=None + ) + """ + Define whether the field is editable + """ + + is_required: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isRequired")] = pydantic.Field( + default=None + ) + """ + define whether a field is required in a collection + """ + + type: typing.Literal["Option"] = pydantic.Field(default="Option") + """ + The [Option field type](/data/reference/field-types-item-values#option) + """ + + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() + """ + The name of a field + """ + + help_text: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="helpText")] = pydantic.Field( + default=None + ) + """ + Additional text to help anyone filling out this field + """ + + metadata: Metadata + + 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/order.py b/src/webflow/types/order.py index d45b1de..2b2844c 100644 --- a/src/webflow/types/order.py +++ b/src/webflow/types/order.py @@ -10,6 +10,8 @@ from .order_dispute_last_status import OrderDisputeLastStatus from .order_price import OrderPrice from .order_address import OrderAddress +from .order_shipping_address import OrderShippingAddress +from .order_billing_address import OrderBillingAddress from .order_customer_info import OrderCustomerInfo from .order_purchased_item import OrderPurchasedItem from .stripe_details import StripeDetails @@ -119,14 +121,14 @@ class Order(UniversalBaseModel): """ shipping_address: typing_extensions.Annotated[ - typing.Optional[OrderAddress], FieldMetadata(alias="shippingAddress") + typing.Optional[OrderShippingAddress], FieldMetadata(alias="shippingAddress") ] = pydantic.Field(default=None) """ The shipping address """ billing_address: typing_extensions.Annotated[ - typing.Optional[OrderAddress], FieldMetadata(alias="billingAddress") + typing.Optional[OrderBillingAddress], FieldMetadata(alias="billingAddress") ] = pydantic.Field(default=None) """ The billing address diff --git a/src/webflow/types/order_billing_address.py b/src/webflow/types/order_billing_address.py new file mode 100644 index 0000000..75e87c6 --- /dev/null +++ b/src/webflow/types/order_billing_address.py @@ -0,0 +1,78 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .order_billing_address_type import OrderBillingAddressType +import pydantic +import typing_extensions +from .order_billing_address_japan_type import OrderBillingAddressJapanType +from ..core.serialization import FieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class OrderBillingAddress(UniversalBaseModel): + """ + The billing address + """ + + type: typing.Optional[OrderBillingAddressType] = pydantic.Field(default=None) + """ + The type of the order address (billing or shipping) + """ + + japan_type: typing_extensions.Annotated[ + typing.Optional[OrderBillingAddressJapanType], FieldMetadata(alias="japanType") + ] = pydantic.Field(default=None) + """ + Represents a Japan-only address format. This field will only appear on orders placed from Japan. + """ + + addressee: typing.Optional[str] = pydantic.Field(default=None) + """ + Display name on the address + """ + + line_1: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="line1")] = pydantic.Field( + default=None + ) + """ + The first line of the address + """ + + line_2: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="line2")] = pydantic.Field( + default=None + ) + """ + The second line of the address + """ + + city: typing.Optional[str] = pydantic.Field(default=None) + """ + The city of the address. + """ + + state: typing.Optional[str] = pydantic.Field(default=None) + """ + The state or province of the address + """ + + country: typing.Optional[str] = pydantic.Field(default=None) + """ + The country of the address + """ + + postal_code: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="postalCode")] = pydantic.Field( + default=None + ) + """ + The postal code of the address + """ + + 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/order_billing_address_japan_type.py b/src/webflow/types/order_billing_address_japan_type.py new file mode 100644 index 0000000..8c983bb --- /dev/null +++ b/src/webflow/types/order_billing_address_japan_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +OrderBillingAddressJapanType = typing.Union[typing.Literal["kana", "kanji"], typing.Any] diff --git a/src/webflow/types/order_billing_address_type.py b/src/webflow/types/order_billing_address_type.py new file mode 100644 index 0000000..6b03d6e --- /dev/null +++ b/src/webflow/types/order_billing_address_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +OrderBillingAddressType = typing.Union[typing.Literal["shipping", "billing"], typing.Any] diff --git a/src/webflow/types/order_shipping_address.py b/src/webflow/types/order_shipping_address.py new file mode 100644 index 0000000..5c62f00 --- /dev/null +++ b/src/webflow/types/order_shipping_address.py @@ -0,0 +1,78 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .order_shipping_address_type import OrderShippingAddressType +import pydantic +import typing_extensions +from .order_shipping_address_japan_type import OrderShippingAddressJapanType +from ..core.serialization import FieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class OrderShippingAddress(UniversalBaseModel): + """ + The shipping address + """ + + type: typing.Optional[OrderShippingAddressType] = pydantic.Field(default=None) + """ + The type of the order address (billing or shipping) + """ + + japan_type: typing_extensions.Annotated[ + typing.Optional[OrderShippingAddressJapanType], FieldMetadata(alias="japanType") + ] = pydantic.Field(default=None) + """ + Represents a Japan-only address format. This field will only appear on orders placed from Japan. + """ + + addressee: typing.Optional[str] = pydantic.Field(default=None) + """ + Display name on the address + """ + + line_1: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="line1")] = pydantic.Field( + default=None + ) + """ + The first line of the address + """ + + line_2: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="line2")] = pydantic.Field( + default=None + ) + """ + The second line of the address + """ + + city: typing.Optional[str] = pydantic.Field(default=None) + """ + The city of the address. + """ + + state: typing.Optional[str] = pydantic.Field(default=None) + """ + The state or province of the address + """ + + country: typing.Optional[str] = pydantic.Field(default=None) + """ + The country of the address + """ + + postal_code: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="postalCode")] = pydantic.Field( + default=None + ) + """ + The postal code of the address + """ + + 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/order_shipping_address_japan_type.py b/src/webflow/types/order_shipping_address_japan_type.py new file mode 100644 index 0000000..b5b548e --- /dev/null +++ b/src/webflow/types/order_shipping_address_japan_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +OrderShippingAddressJapanType = typing.Union[typing.Literal["kana", "kanji"], typing.Any] diff --git a/src/webflow/types/order_shipping_address_type.py b/src/webflow/types/order_shipping_address_type.py new file mode 100644 index 0000000..467ccbd --- /dev/null +++ b/src/webflow/types/order_shipping_address_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +OrderShippingAddressType = typing.Union[typing.Literal["shipping", "billing"], typing.Any] diff --git a/src/webflow/types/page.py b/src/webflow/types/page.py index 56b32d3..af2fa6b 100644 --- a/src/webflow/types/page.py +++ b/src/webflow/types/page.py @@ -1,9 +1,9 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel +import typing import pydantic import typing_extensions -import typing from ..core.serialization import FieldMetadata import datetime as dt from .page_seo import PageSeo @@ -16,7 +16,7 @@ class Page(UniversalBaseModel): The Page object """ - id: str = pydantic.Field() + id: typing.Optional[str] = pydantic.Field(default=None) """ Unique identifier for the Page """ @@ -90,13 +90,6 @@ class Page(UniversalBaseModel): Indicates whether the Page is a Branch of another Page [Page Branching](https://university.webflow.com/lesson/page-branching) """ - is_members_only: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isMembersOnly")] = ( - pydantic.Field(default=None) - ) - """ - Indicates whether the Page is restricted by [Memberships Controls](https://university.webflow.com/lesson/webflow-memberships-overview#how-to-manage-page-restrictions) - """ - seo: typing.Optional[PageSeo] = pydantic.Field(default=None) """ SEO-related fields for the Page diff --git a/src/webflow/types/pagination.py b/src/webflow/types/pagination.py index aa38c46..6b8d4ee 100644 --- a/src/webflow/types/pagination.py +++ b/src/webflow/types/pagination.py @@ -1,9 +1,9 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel -import typing import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing class Pagination(UniversalBaseModel): @@ -11,17 +11,17 @@ class Pagination(UniversalBaseModel): Pagination object """ - limit: typing.Optional[float] = pydantic.Field(default=None) + limit: float = pydantic.Field() """ The limit used for pagination """ - offset: typing.Optional[float] = pydantic.Field(default=None) + offset: float = pydantic.Field() """ The offset used for pagination """ - total: typing.Optional[float] = pydantic.Field(default=None) + total: float = pydantic.Field() """ The total number of records """ diff --git a/src/webflow/types/product_field_data.py b/src/webflow/types/product_field_data.py index e58b83d..e907159 100644 --- a/src/webflow/types/product_field_data.py +++ b/src/webflow/types/product_field_data.py @@ -43,9 +43,9 @@ class ProductFieldData(UniversalBaseModel): Variant types to include in SKUs """ - categories: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + category: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ - The categories your product belongs to. + The category your product belongs to. """ tax_category: typing_extensions.Annotated[ diff --git a/src/webflow/types/reference_field.py b/src/webflow/types/reference_field.py new file mode 100644 index 0000000..3c75552 --- /dev/null +++ b/src/webflow/types/reference_field.py @@ -0,0 +1,62 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from .reference_field_type import ReferenceFieldType +from .reference_field_metadata import ReferenceFieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class ReferenceField(UniversalBaseModel): + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Unique identifier for a Field + """ + + is_editable: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isEditable")] = pydantic.Field( + default=None + ) + """ + Define whether the field is editable + """ + + is_required: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isRequired")] = pydantic.Field( + default=None + ) + """ + define whether a field is required in a collection + """ + + type: ReferenceFieldType = pydantic.Field() + """ + Choose these appropriate field type for your collection data + """ + + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() + """ + The name of a field + """ + + help_text: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="helpText")] = pydantic.Field( + default=None + ) + """ + Additional text to help anyone filling out this field + """ + + metadata: ReferenceFieldMetadata = pydantic.Field() + """ + The collectionId for the referenced collection. Only applicable for Reference and MultiReference fields. + """ + + 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/reference_field_metadata.py b/src/webflow/types/reference_field_metadata.py new file mode 100644 index 0000000..164c4a6 --- /dev/null +++ b/src/webflow/types/reference_field_metadata.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class ReferenceFieldMetadata(UniversalBaseModel): + """ + The collectionId for the referenced collection. Only applicable for Reference and MultiReference fields. + """ + + collection_id: typing_extensions.Annotated[str, FieldMetadata(alias="collectionId")] = pydantic.Field() + """ + The unique identifier of the collection + """ + + 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/reference_field_type.py b/src/webflow/types/reference_field_type.py new file mode 100644 index 0000000..b80f3e1 --- /dev/null +++ b/src/webflow/types/reference_field_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ReferenceFieldType = typing.Union[typing.Literal["MultiReference", "Reference"], typing.Any] diff --git a/src/webflow/types/registered_script_list.py b/src/webflow/types/registered_script_list.py index ddfff8d..e9d8a01 100644 --- a/src/webflow/types/registered_script_list.py +++ b/src/webflow/types/registered_script_list.py @@ -5,6 +5,7 @@ import typing from .custom_code_hosted_response import CustomCodeHostedResponse from ..core.serialization import FieldMetadata +from .pagination import Pagination from ..core.pydantic_utilities import IS_PYDANTIC_V2 import pydantic @@ -17,6 +18,7 @@ class RegisteredScriptList(UniversalBaseModel): registered_scripts: typing_extensions.Annotated[ typing.Optional[typing.List[CustomCodeHostedResponse]], FieldMetadata(alias="registeredScripts") ] = None + pagination: typing.Optional[Pagination] = 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/robots.py b/src/webflow/types/robots.py new file mode 100644 index 0000000..7489660 --- /dev/null +++ b/src/webflow/types/robots.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .robots_rules_item import RobotsRulesItem +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class Robots(UniversalBaseModel): + """ + The robots.txt file for a given site + """ + + rules: typing.Optional[typing.List[RobotsRulesItem]] = pydantic.Field(default=None) + """ + List of rules for user agents. + """ + + sitemap: typing.Optional[str] = pydantic.Field(default=None) + """ + URL to the sitemap. + """ + + 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/robots_rules_item.py b/src/webflow/types/robots_rules_item.py new file mode 100644 index 0000000..048f239 --- /dev/null +++ b/src/webflow/types/robots_rules_item.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class RobotsRulesItem(UniversalBaseModel): + user_agent: typing_extensions.Annotated[str, FieldMetadata(alias="userAgent")] = pydantic.Field() + """ + The user agent the rules apply to. + """ + + allows: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of paths allowed for this user agent. + """ + + disallows: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of paths disallowed for this user agent. + """ + + 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/text_node_write.py b/src/webflow/types/search_button.py similarity index 75% rename from src/webflow/types/text_node_write.py rename to src/webflow/types/search_button.py index a16c800..10e83ce 100644 --- a/src/webflow/types/text_node_write.py +++ b/src/webflow/types/search_button.py @@ -8,9 +8,9 @@ import typing -class TextNodeWrite(UniversalBaseModel): +class SearchButton(UniversalBaseModel): """ - Update a text node + Update a search button node """ node_id: typing_extensions.Annotated[str, FieldMetadata(alias="nodeId")] = pydantic.Field() @@ -18,9 +18,9 @@ class TextNodeWrite(UniversalBaseModel): Node UUID """ - text: str = pydantic.Field() + value: str = pydantic.Field() """ - HTML content of the node, including the HTML tag. The HTML tags must be the same as what's returned from the Get Content endpoint. + The text content of the search button. """ if IS_PYDANTIC_V2: diff --git a/src/webflow/types/search_button_node.py b/src/webflow/types/search_button_node.py new file mode 100644 index 0000000..fe71178 --- /dev/null +++ b/src/webflow/types/search_button_node.py @@ -0,0 +1,36 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class SearchButtonNode(UniversalBaseModel): + """ + Represents search button elements within the DOM. It contains the text of the button. Additional attributes can be associated with the text for styling or other purposes. + """ + + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Node UUID + """ + + value: str = pydantic.Field() + """ + The text content of the search button. + """ + + attributes: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None) + """ + The custom attributes of the node + """ + + 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/select.py b/src/webflow/types/select.py new file mode 100644 index 0000000..7208091 --- /dev/null +++ b/src/webflow/types/select.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +import typing +from .select_node_write_choices_item import SelectNodeWriteChoicesItem +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class Select(UniversalBaseModel): + """ + Update choices on a select node + """ + + node_id: typing_extensions.Annotated[str, FieldMetadata(alias="nodeId")] = pydantic.Field() + """ + Node UUID + """ + + choices: typing.List[SelectNodeWriteChoicesItem] = pydantic.Field() + """ + The list of choices to set on the select node. + """ + + 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/select_node.py b/src/webflow/types/select_node.py new file mode 100644 index 0000000..29214d8 --- /dev/null +++ b/src/webflow/types/select_node.py @@ -0,0 +1,37 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +from .select_node_choices_item import SelectNodeChoicesItem +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class SelectNode(UniversalBaseModel): + """ + Represents select elements within the DOM. It contains the list of choices in the select. Additional attributes can be associated with the text for styling or other purposes. + """ + + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Node UUID + """ + + choices: typing.List[SelectNodeChoicesItem] = pydantic.Field() + """ + The list of choices in this select node. + """ + + attributes: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None) + """ + The custom attributes of the node + """ + + 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/select_node_choices_item.py b/src/webflow/types/select_node_choices_item.py new file mode 100644 index 0000000..cd210b1 --- /dev/null +++ b/src/webflow/types/select_node_choices_item.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class SelectNodeChoicesItem(UniversalBaseModel): + value: str = pydantic.Field() + """ + The value of the choice when selected. + """ + + text: str = pydantic.Field() + """ + The text to display for the choice. + """ + + 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/select_node_write_choices_item.py b/src/webflow/types/select_node_write_choices_item.py new file mode 100644 index 0000000..4346fef --- /dev/null +++ b/src/webflow/types/select_node_write_choices_item.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class SelectNodeWriteChoicesItem(UniversalBaseModel): + value: str = pydantic.Field() + """ + The value of the choice when selected. + """ + + text: str = pydantic.Field() + """ + The text to display for the choice. + """ + + 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/site_membership.py b/src/webflow/types/site_membership.py new file mode 100644 index 0000000..5ad913f --- /dev/null +++ b/src/webflow/types/site_membership.py @@ -0,0 +1,49 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .workspace_audit_log_item_payload_site_membership_site import WorkspaceAuditLogItemPayloadSiteMembershipSite +import typing_extensions +from .workspace_audit_log_item_payload_site_membership_target_user import ( + WorkspaceAuditLogItemPayloadSiteMembershipTargetUser, +) +from ..core.serialization import FieldMetadata +from .workspace_audit_log_item_payload_site_membership_method import WorkspaceAuditLogItemPayloadSiteMembershipMethod +from .workspace_audit_log_item_payload_site_membership_user_type import ( + WorkspaceAuditLogItemPayloadSiteMembershipUserType, +) +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class SiteMembership(UniversalBaseModel): + site: typing.Optional[WorkspaceAuditLogItemPayloadSiteMembershipSite] = None + target_user: typing_extensions.Annotated[ + typing.Optional[WorkspaceAuditLogItemPayloadSiteMembershipTargetUser], FieldMetadata(alias="targetUser") + ] = None + method: typing.Optional[WorkspaceAuditLogItemPayloadSiteMembershipMethod] = None + user_type: typing_extensions.Annotated[ + typing.Optional[WorkspaceAuditLogItemPayloadSiteMembershipUserType], FieldMetadata(alias="userType") + ] = None + role_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="roleName")] = pydantic.Field( + default=None + ) + """ + The name of the role that was assigned to the user + """ + + previous_role_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="previousRoleName")] = ( + pydantic.Field(default=None) + ) + """ + The previous role that the user had + """ + + 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/site_membership_audit_log_item.py b/src/webflow/types/site_membership_audit_log_item.py new file mode 100644 index 0000000..d24ee9f --- /dev/null +++ b/src/webflow/types/site_membership_audit_log_item.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from .site_membership_audit_log_item_event_sub_type import SiteMembershipAuditLogItemEventSubType +from ..core.serialization import FieldMetadata +from .site_membership import SiteMembership +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class SiteMembershipAuditLogItem(UniversalBaseModel): + event_sub_type: typing_extensions.Annotated[ + typing.Optional[SiteMembershipAuditLogItemEventSubType], FieldMetadata(alias="eventSubType") + ] = None + payload: typing.Optional[SiteMembership] = 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/site_membership_audit_log_item_event_sub_type.py b/src/webflow/types/site_membership_audit_log_item_event_sub_type.py new file mode 100644 index 0000000..b604b85 --- /dev/null +++ b/src/webflow/types/site_membership_audit_log_item_event_sub_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +SiteMembershipAuditLogItemEventSubType = typing.Union[ + typing.Literal["user_added", "user_removed", "user_role_updated"], typing.Any +] diff --git a/src/webflow/types/sku_field_data.py b/src/webflow/types/sku_field_data.py index e20efdb..13e32ac 100644 --- a/src/webflow/types/sku_field_data.py +++ b/src/webflow/types/sku_field_data.py @@ -10,6 +10,7 @@ from .sku_field_data_compare_at_price import SkuFieldDataCompareAtPrice from .sku_field_data_ec_sku_billing_method import SkuFieldDataEcSkuBillingMethod from .sku_field_data_ec_sku_subscription_plan import SkuFieldDataEcSkuSubscriptionPlan +from .sku_property_list import SkuPropertyList from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -43,10 +44,18 @@ class SkuFieldData(UniversalBaseModel): ec_sku_billing_method: typing_extensions.Annotated[ typing.Optional[SkuFieldDataEcSkuBillingMethod], FieldMetadata(alias="ec-sku-billing-method") - ] = None + ] = pydantic.Field(default=None) + """ + [Billing method](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#billing-methods)for the SKU + """ + ec_sku_subscription_plan: typing_extensions.Annotated[ typing.Optional[SkuFieldDataEcSkuSubscriptionPlan], FieldMetadata(alias="ec-sku-subscription-plan") - ] = None + ] = pydantic.Field(default=None) + """ + [Subscription plan](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#subscription) for the SKU + """ + track_inventory: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="track-inventory")] = ( pydantic.Field(default=None) ) @@ -59,6 +68,25 @@ class SkuFieldData(UniversalBaseModel): Quantity of SKU that will be tracked as items are ordered. """ + main_image: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="main-image")] = pydantic.Field( + default=None + ) + """ + The URL for the main image of the SKU + """ + + sku: typing.Optional[str] = pydantic.Field(default=None) + """ + A unique identifier for the SKU + """ + + sku_properties: typing_extensions.Annotated[ + typing.Optional[typing.List[SkuPropertyList]], FieldMetadata(alias="sku-properties") + ] = pydantic.Field(default=None) + """ + The properties of the SKU + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/webflow/types/sku_field_data_ec_sku_subscription_plan.py b/src/webflow/types/sku_field_data_ec_sku_subscription_plan.py index 24c85a7..ed2e484 100644 --- a/src/webflow/types/sku_field_data_ec_sku_subscription_plan.py +++ b/src/webflow/types/sku_field_data_ec_sku_subscription_plan.py @@ -9,6 +9,10 @@ class SkuFieldDataEcSkuSubscriptionPlan(UniversalBaseModel): + """ + [Subscription plan](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#subscription) for the SKU + """ + interval: typing.Optional[SkuFieldDataEcSkuSubscriptionPlanInterval] = pydantic.Field(default=None) """ Interval of subscription renewal diff --git a/src/webflow/types/sku_field_data_price.py b/src/webflow/types/sku_field_data_price.py index 45ff611..cb31f4a 100644 --- a/src/webflow/types/sku_field_data_price.py +++ b/src/webflow/types/sku_field_data_price.py @@ -21,6 +21,11 @@ class SkuFieldDataPrice(UniversalBaseModel): Currency of Item """ + currency: typing.Optional[str] = pydantic.Field(default=None) + """ + Currency of Item (alternative representation) + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/webflow/types/static_field.py b/src/webflow/types/static_field.py new file mode 100644 index 0000000..c6e6162 --- /dev/null +++ b/src/webflow/types/static_field.py @@ -0,0 +1,56 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from .static_field_type import StaticFieldType +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class StaticField(UniversalBaseModel): + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Unique identifier for a Field + """ + + is_editable: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isEditable")] = pydantic.Field( + default=None + ) + """ + Define whether the field is editable + """ + + is_required: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isRequired")] = pydantic.Field( + default=None + ) + """ + define whether a field is required in a collection + """ + + type: StaticFieldType = pydantic.Field() + """ + Choose these appropriate field type for your collection data + """ + + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() + """ + The name of a field + """ + + help_text: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="helpText")] = pydantic.Field( + default=None + ) + """ + Additional text to help anyone filling out this field + """ + + 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/collections/resources/fields/types/field_create_type.py b/src/webflow/types/static_field_type.py similarity index 82% rename from src/webflow/resources/collections/resources/fields/types/field_create_type.py rename to src/webflow/types/static_field_type.py index c8ec44b..e7cadf0 100644 --- a/src/webflow/resources/collections/resources/fields/types/field_create_type.py +++ b/src/webflow/types/static_field_type.py @@ -2,12 +2,11 @@ import typing -FieldCreateType = typing.Union[ +StaticFieldType = typing.Union[ typing.Literal[ "Color", "DateTime", "Email", - "ExtFileRef", "File", "Image", "Link", @@ -17,7 +16,7 @@ "PlainText", "RichText", "Switch", - "Video", + "VideoLink", ], typing.Any, ] diff --git a/src/webflow/types/submit_button.py b/src/webflow/types/submit_button.py new file mode 100644 index 0000000..158759b --- /dev/null +++ b/src/webflow/types/submit_button.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class SubmitButton(UniversalBaseModel): + """ + Update a submit button node + """ + + node_id: typing_extensions.Annotated[str, FieldMetadata(alias="nodeId")] = pydantic.Field() + """ + Node UUID + """ + + value: typing.Optional[str] = pydantic.Field(default=None) + """ + The text content of the submit button. + """ + + waiting_text: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="waitingText")] = ( + pydantic.Field(default=None) + ) + """ + The text to show while the form is submitting. + """ + + 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/submit_button_node.py b/src/webflow/types/submit_button_node.py new file mode 100644 index 0000000..8fe90a4 --- /dev/null +++ b/src/webflow/types/submit_button_node.py @@ -0,0 +1,43 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class SubmitButtonNode(UniversalBaseModel): + """ + Represents submit button elements within the DOM. It contains the text and waiting text of the button. Additional attributes can be associated with the text for styling or other purposes. + """ + + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Node UUID + """ + + value: str = pydantic.Field() + """ + The text content of the submit button. + """ + + waiting_text: typing_extensions.Annotated[str, FieldMetadata(alias="waitingText")] = pydantic.Field() + """ + The text to show while the form is submitting. + """ + + attributes: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None) + """ + The custom attributes of the node + """ + + 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/text.py b/src/webflow/types/text.py index 18f8501..913d5d1 100644 --- a/src/webflow/types/text.py +++ b/src/webflow/types/text.py @@ -7,6 +7,10 @@ class Text(UniversalBaseModel): + """ + The text content of the node + """ + html: typing.Optional[str] = pydantic.Field(default=None) """ The HTML content of the text node. diff --git a/src/webflow/types/text_input.py b/src/webflow/types/text_input.py new file mode 100644 index 0000000..80e4037 --- /dev/null +++ b/src/webflow/types/text_input.py @@ -0,0 +1,33 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class TextInput(UniversalBaseModel): + """ + Update placeholder text on a text input node + """ + + node_id: typing_extensions.Annotated[str, FieldMetadata(alias="nodeId")] = pydantic.Field() + """ + Node UUID + """ + + placeholder: str = pydantic.Field() + """ + The placeholder text of the input node + """ + + 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/text_input_node.py b/src/webflow/types/text_input_node.py new file mode 100644 index 0000000..bfd71a1 --- /dev/null +++ b/src/webflow/types/text_input_node.py @@ -0,0 +1,36 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class TextInputNode(UniversalBaseModel): + """ + Represents text input and textarea elements within the DOM. It contains the placeholder text in the input. Additional attributes can be associated with the text for styling or other purposes. + """ + + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Node UUID + """ + + placeholder: str = pydantic.Field() + """ + The placeholder text of the input node + """ + + attributes: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None) + """ + The custom attributes of the node + """ + + 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/text_node.py b/src/webflow/types/text_node.py index 1e16717..64774c9 100644 --- a/src/webflow/types/text_node.py +++ b/src/webflow/types/text_node.py @@ -1,26 +1,26 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel -import typing +import typing_extensions +from ..core.serialization import FieldMetadata import pydantic -from .text_node_text import TextNodeText from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing class TextNode(UniversalBaseModel): """ - Represents text content within the DOM. It contains both the raw text and its HTML representation. Additional attributes can be associated with the text for styling or other purposes. + Update a text node """ - id: typing.Optional[str] = pydantic.Field(default=None) + node_id: typing_extensions.Annotated[str, FieldMetadata(alias="nodeId")] = pydantic.Field() """ Node UUID """ - text: typing.Optional[TextNodeText] = None - attributes: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None) + text: str = pydantic.Field() """ - The custom attributes of the node + HTML content of the node, including the HTML tag. The HTML tags must be the same as what's returned from the Get Content endpoint. """ if IS_PYDANTIC_V2: diff --git a/src/webflow/types/text_node_text.py b/src/webflow/types/text_node_text.py index 895dc0b..5add2f0 100644 --- a/src/webflow/types/text_node_text.py +++ b/src/webflow/types/text_node_text.py @@ -7,6 +7,10 @@ class TextNodeText(UniversalBaseModel): + """ + The text content of the node + """ + html: typing.Optional[str] = pydantic.Field(default=None) """ The HTML content of the text node. diff --git a/src/webflow/types/trigger_type.py b/src/webflow/types/trigger_type.py index e12b650..26ca017 100644 --- a/src/webflow/types/trigger_type.py +++ b/src/webflow/types/trigger_type.py @@ -19,6 +19,7 @@ "collection_item_changed", "collection_item_deleted", "collection_item_unpublished", + "comment_created", ], typing.Any, ] diff --git a/src/webflow/types/user_access.py b/src/webflow/types/user_access.py new file mode 100644 index 0000000..7c869dd --- /dev/null +++ b/src/webflow/types/user_access.py @@ -0,0 +1,33 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .workspace_audit_log_item_payload_user_access_method import WorkspaceAuditLogItemPayloadUserAccessMethod +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class UserAccess(UniversalBaseModel): + method: typing.Optional[WorkspaceAuditLogItemPayloadUserAccessMethod] = None + location: typing.Optional[str] = pydantic.Field(default=None) + """ + The geolocation based on the logged IP address + """ + + ip_address: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="ipAddress")] = pydantic.Field( + default=None + ) + """ + The captured IP address of the user + """ + + 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/user_access_audit_log_item.py b/src/webflow/types/user_access_audit_log_item.py new file mode 100644 index 0000000..b94e6a7 --- /dev/null +++ b/src/webflow/types/user_access_audit_log_item.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from .user_access_audit_log_item_event_sub_type import UserAccessAuditLogItemEventSubType +from ..core.serialization import FieldMetadata +from .user_access import UserAccess +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class UserAccessAuditLogItem(UniversalBaseModel): + event_sub_type: typing_extensions.Annotated[ + typing.Optional[UserAccessAuditLogItemEventSubType], FieldMetadata(alias="eventSubType") + ] = None + payload: typing.Optional[UserAccess] = 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/user_access_audit_log_item_event_sub_type.py b/src/webflow/types/user_access_audit_log_item_event_sub_type.py new file mode 100644 index 0000000..382f247 --- /dev/null +++ b/src/webflow/types/user_access_audit_log_item_event_sub_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +UserAccessAuditLogItemEventSubType = typing.Union[typing.Literal["login", "logout"], typing.Any] diff --git a/src/webflow/types/webhook_list.py b/src/webflow/types/webhook_list.py index ea705c4..1740272 100644 --- a/src/webflow/types/webhook_list.py +++ b/src/webflow/types/webhook_list.py @@ -2,15 +2,15 @@ from ..core.pydantic_utilities import UniversalBaseModel import typing -from .pagination import Pagination from .webhook import Webhook +from .pagination import Pagination from ..core.pydantic_utilities import IS_PYDANTIC_V2 import pydantic class WebhookList(UniversalBaseModel): - pagination: typing.Optional[Pagination] = None webhooks: typing.Optional[typing.List[Webhook]] = None + pagination: typing.Optional[Pagination] = 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/workspace_audit_log_item.py b/src/webflow/types/workspace_audit_log_item.py new file mode 100644 index 0000000..4f95a56 --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item.py @@ -0,0 +1,141 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import datetime as dt +from .workspace_audit_log_item_actor import WorkspaceAuditLogItemActor +from .workspace_audit_log_item_workspace import WorkspaceAuditLogItemWorkspace +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from .user_access_audit_log_item_event_sub_type import UserAccessAuditLogItemEventSubType +from .user_access import UserAccess +from .custom_role_audit_log_item_event_sub_type import CustomRoleAuditLogItemEventSubType +from .custom_role import CustomRole +from .workspace_membership_audit_log_item_event_sub_type import WorkspaceMembershipAuditLogItemEventSubType +from .workspace_membership import WorkspaceMembership +from .site_membership_audit_log_item_event_sub_type import SiteMembershipAuditLogItemEventSubType +from .site_membership import SiteMembership +from .workspace_invitation_audit_log_item_event_sub_type import WorkspaceInvitationAuditLogItemEventSubType +from .workspace_invitation import WorkspaceInvitation + + +class Base(UniversalBaseModel): + timestamp: typing.Optional[dt.datetime] = None + actor: typing.Optional[WorkspaceAuditLogItemActor] = None + workspace: typing.Optional[WorkspaceAuditLogItemWorkspace] = 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 + + +class WorkspaceAuditLogItem_UserAccess(Base): + event_type: typing_extensions.Annotated[typing.Literal["user_access"], FieldMetadata(alias="eventType")] = ( + "user_access" + ) + event_sub_type: typing_extensions.Annotated[ + typing.Optional[UserAccessAuditLogItemEventSubType], FieldMetadata(alias="eventSubType") + ] = None + payload: typing.Optional[UserAccess] = 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 + + +class WorkspaceAuditLogItem_CustomRole(Base): + event_type: typing_extensions.Annotated[typing.Literal["custom_role"], FieldMetadata(alias="eventType")] = ( + "custom_role" + ) + event_sub_type: typing_extensions.Annotated[ + typing.Optional[CustomRoleAuditLogItemEventSubType], FieldMetadata(alias="eventSubType") + ] = None + payload: typing.Optional[CustomRole] = 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 + + +class WorkspaceAuditLogItem_WorkspaceMembership(Base): + event_type: typing_extensions.Annotated[ + typing.Literal["workspace_membership"], FieldMetadata(alias="eventType") + ] = "workspace_membership" + event_sub_type: typing_extensions.Annotated[ + typing.Optional[WorkspaceMembershipAuditLogItemEventSubType], FieldMetadata(alias="eventSubType") + ] = None + payload: typing.Optional[WorkspaceMembership] = 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 + + +class WorkspaceAuditLogItem_SiteMembership(Base): + event_type: typing_extensions.Annotated[typing.Literal["site_membership"], FieldMetadata(alias="eventType")] = ( + "site_membership" + ) + event_sub_type: typing_extensions.Annotated[ + typing.Optional[SiteMembershipAuditLogItemEventSubType], FieldMetadata(alias="eventSubType") + ] = None + payload: typing.Optional[SiteMembership] = 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 + + +class WorkspaceAuditLogItem_WorkspaceInvitation(Base): + event_type: typing_extensions.Annotated[ + typing.Literal["workspace_invitation"], FieldMetadata(alias="eventType") + ] = "workspace_invitation" + event_sub_type: typing_extensions.Annotated[ + typing.Optional[WorkspaceInvitationAuditLogItemEventSubType], FieldMetadata(alias="eventSubType") + ] = None + payload: typing.Optional[WorkspaceInvitation] = 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 + + +WorkspaceAuditLogItem = typing.Union[ + WorkspaceAuditLogItem_UserAccess, + WorkspaceAuditLogItem_CustomRole, + WorkspaceAuditLogItem_WorkspaceMembership, + WorkspaceAuditLogItem_SiteMembership, + WorkspaceAuditLogItem_WorkspaceInvitation, +] diff --git a/src/webflow/types/workspace_audit_log_item_actor.py b/src/webflow/types/workspace_audit_log_item_actor.py new file mode 100644 index 0000000..7da609c --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_actor.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class WorkspaceAuditLogItemActor(UniversalBaseModel): + id: typing.Optional[str] = None + email: typing.Optional[str] = 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/workspace_audit_log_item_payload_site_membership_method.py b/src/webflow/types/workspace_audit_log_item_payload_site_membership_method.py new file mode 100644 index 0000000..8dbb6ad --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_site_membership_method.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WorkspaceAuditLogItemPayloadSiteMembershipMethod = typing.Union[ + typing.Literal["sso", "invite", "scim", "dashboard", "admin"], typing.Any +] diff --git a/src/webflow/types/workspace_audit_log_item_payload_site_membership_site.py b/src/webflow/types/workspace_audit_log_item_payload_site_membership_site.py new file mode 100644 index 0000000..6d392bd --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_site_membership_site.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class WorkspaceAuditLogItemPayloadSiteMembershipSite(UniversalBaseModel): + id: typing.Optional[str] = None + slug: typing.Optional[str] = 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/workspace_audit_log_item_payload_site_membership_target_user.py b/src/webflow/types/workspace_audit_log_item_payload_site_membership_target_user.py new file mode 100644 index 0000000..bcfc37b --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_site_membership_target_user.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class WorkspaceAuditLogItemPayloadSiteMembershipTargetUser(UniversalBaseModel): + id: typing.Optional[str] = None + email: typing.Optional[str] = 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/workspace_audit_log_item_payload_site_membership_user_type.py b/src/webflow/types/workspace_audit_log_item_payload_site_membership_user_type.py new file mode 100644 index 0000000..47b5168 --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_site_membership_user_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WorkspaceAuditLogItemPayloadSiteMembershipUserType = typing.Union[ + typing.Literal["member", "guest", "reviewer", "client"], typing.Any +] diff --git a/src/webflow/types/workspace_audit_log_item_payload_user_access_method.py b/src/webflow/types/workspace_audit_log_item_payload_user_access_method.py new file mode 100644 index 0000000..5417cff --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_user_access_method.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WorkspaceAuditLogItemPayloadUserAccessMethod = typing.Union[ + typing.Literal["dashboard", "sso", "api", "google"], typing.Any +] diff --git a/src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_method.py b/src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_method.py new file mode 100644 index 0000000..79a3042 --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_method.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod = typing.Union[ + typing.Literal["sso", "dashboard", "admin"], typing.Any +] diff --git a/src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_target_user.py b/src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_target_user.py new file mode 100644 index 0000000..1360978 --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_target_user.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser(UniversalBaseModel): + id: typing.Optional[str] = None + email: typing.Optional[str] = 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/workspace_audit_log_item_payload_workspace_invitation_user_type.py b/src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_user_type.py new file mode 100644 index 0000000..980d3a9 --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_user_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType = typing.Union[ + typing.Literal["member", "guest", "reviewer", "client"], typing.Any +] diff --git a/src/webflow/types/workspace_audit_log_item_payload_workspace_membership_method.py b/src/webflow/types/workspace_audit_log_item_payload_workspace_membership_method.py new file mode 100644 index 0000000..a86a23c --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_workspace_membership_method.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod = typing.Union[ + typing.Literal["sso", "dashboard", "admin"], typing.Any +] diff --git a/src/webflow/types/workspace_audit_log_item_payload_workspace_membership_target_user.py b/src/webflow/types/workspace_audit_log_item_payload_workspace_membership_target_user.py new file mode 100644 index 0000000..6ce0f6a --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_workspace_membership_target_user.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser(UniversalBaseModel): + id: typing.Optional[str] = None + email: typing.Optional[str] = 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/workspace_audit_log_item_payload_workspace_membership_user_type.py b/src/webflow/types/workspace_audit_log_item_payload_workspace_membership_user_type.py new file mode 100644 index 0000000..dad636f --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_payload_workspace_membership_user_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType = typing.Union[ + typing.Literal["member", "guest", "reviewer", "client"], typing.Any +] diff --git a/src/webflow/types/workspace_audit_log_item_workspace.py b/src/webflow/types/workspace_audit_log_item_workspace.py new file mode 100644 index 0000000..6c13bf5 --- /dev/null +++ b/src/webflow/types/workspace_audit_log_item_workspace.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class WorkspaceAuditLogItemWorkspace(UniversalBaseModel): + id: typing.Optional[str] = None + slug: typing.Optional[str] = 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/workspace_audit_log_response.py b/src/webflow/types/workspace_audit_log_response.py new file mode 100644 index 0000000..f6d0d13 --- /dev/null +++ b/src/webflow/types/workspace_audit_log_response.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .workspace_audit_log_item import WorkspaceAuditLogItem +from .pagination import Pagination +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class WorkspaceAuditLogResponse(UniversalBaseModel): + items: typing.Optional[typing.List[WorkspaceAuditLogItem]] = None + pagination: typing.Optional[Pagination] = 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/workspace_invitation.py b/src/webflow/types/workspace_invitation.py new file mode 100644 index 0000000..0bfa99e --- /dev/null +++ b/src/webflow/types/workspace_invitation.py @@ -0,0 +1,49 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from .workspace_audit_log_item_payload_workspace_invitation_target_user import ( + WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser, +) +from ..core.serialization import FieldMetadata +from .workspace_audit_log_item_payload_workspace_invitation_method import ( + WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod, +) +from .workspace_audit_log_item_payload_workspace_invitation_user_type import ( + WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType, +) +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class WorkspaceInvitation(UniversalBaseModel): + target_user: typing_extensions.Annotated[ + typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser], FieldMetadata(alias="targetUser") + ] = None + method: typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod] = None + user_type: typing_extensions.Annotated[ + typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType], FieldMetadata(alias="userType") + ] = None + role_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="roleName")] = pydantic.Field( + default=None + ) + """ + The name of the role that was assigned to the user + """ + + previous_role_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="previousRoleName")] = ( + pydantic.Field(default=None) + ) + """ + The previous role that the user had + """ + + 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/workspace_invitation_audit_log_item.py b/src/webflow/types/workspace_invitation_audit_log_item.py new file mode 100644 index 0000000..e41f504 --- /dev/null +++ b/src/webflow/types/workspace_invitation_audit_log_item.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from .workspace_invitation_audit_log_item_event_sub_type import WorkspaceInvitationAuditLogItemEventSubType +from ..core.serialization import FieldMetadata +from .workspace_invitation import WorkspaceInvitation +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class WorkspaceInvitationAuditLogItem(UniversalBaseModel): + event_sub_type: typing_extensions.Annotated[ + typing.Optional[WorkspaceInvitationAuditLogItemEventSubType], FieldMetadata(alias="eventSubType") + ] = None + payload: typing.Optional[WorkspaceInvitation] = 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/workspace_invitation_audit_log_item_event_sub_type.py b/src/webflow/types/workspace_invitation_audit_log_item_event_sub_type.py new file mode 100644 index 0000000..821fd81 --- /dev/null +++ b/src/webflow/types/workspace_invitation_audit_log_item_event_sub_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WorkspaceInvitationAuditLogItemEventSubType = typing.Union[ + typing.Literal["invite_sent", "invite_accepted", "invite_updated", "invite_canceled", "invite_declined"], typing.Any +] diff --git a/src/webflow/types/workspace_membership.py b/src/webflow/types/workspace_membership.py new file mode 100644 index 0000000..1c369a2 --- /dev/null +++ b/src/webflow/types/workspace_membership.py @@ -0,0 +1,49 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from .workspace_audit_log_item_payload_workspace_membership_target_user import ( + WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser, +) +from ..core.serialization import FieldMetadata +from .workspace_audit_log_item_payload_workspace_membership_method import ( + WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod, +) +from .workspace_audit_log_item_payload_workspace_membership_user_type import ( + WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType, +) +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class WorkspaceMembership(UniversalBaseModel): + target_user: typing_extensions.Annotated[ + typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser], FieldMetadata(alias="targetUser") + ] = None + method: typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod] = None + user_type: typing_extensions.Annotated[ + typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType], FieldMetadata(alias="userType") + ] = None + role_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="roleName")] = pydantic.Field( + default=None + ) + """ + The name of the role that was assigned to the user + """ + + previous_role_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="previousRoleName")] = ( + pydantic.Field(default=None) + ) + """ + The previous role that the user had + """ + + 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/workspace_membership_audit_log_item.py b/src/webflow/types/workspace_membership_audit_log_item.py new file mode 100644 index 0000000..4ac92d7 --- /dev/null +++ b/src/webflow/types/workspace_membership_audit_log_item.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from .workspace_membership_audit_log_item_event_sub_type import WorkspaceMembershipAuditLogItemEventSubType +from ..core.serialization import FieldMetadata +from .workspace_membership import WorkspaceMembership +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class WorkspaceMembershipAuditLogItem(UniversalBaseModel): + event_sub_type: typing_extensions.Annotated[ + typing.Optional[WorkspaceMembershipAuditLogItemEventSubType], FieldMetadata(alias="eventSubType") + ] = None + payload: typing.Optional[WorkspaceMembership] = 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/workspace_membership_audit_log_item_event_sub_type.py b/src/webflow/types/workspace_membership_audit_log_item_event_sub_type.py new file mode 100644 index 0000000..4d90d7a --- /dev/null +++ b/src/webflow/types/workspace_membership_audit_log_item_event_sub_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WorkspaceMembershipAuditLogItemEventSubType = typing.Union[ + typing.Literal["user_added", "user_removed", "user_role_updated"], typing.Any +] diff --git a/tests/collections/test_fields.py b/tests/collections/test_fields.py index f64c447..dc18ff3 100644 --- a/tests/collections/test_fields.py +++ b/tests/collections/test_fields.py @@ -3,43 +3,50 @@ from webflow import Webflow from webflow import AsyncWebflow import typing +from webflow import StaticField from ..utilities import validate_response async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "75821f618da60c18383330bcc0ca488b", - "isRequired": False, + "id": "562ac0395358780a1f5e6fbc", "isEditable": True, + "isRequired": False, "type": "RichText", - "slug": "post-body", "displayName": "Post Body", "helpText": "Add the body of your post here", } expected_types: typing.Any = { "id": None, - "isRequired": None, "isEditable": None, + "isRequired": None, "type": None, - "slug": None, "displayName": None, "helpText": None, } response = client.collections.fields.create( collection_id="580e63fc8c9a982ac9b8b745", - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + 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", + ), ) validate_response(response, expected_response, expected_types) async_response = await async_client.collections.fields.create( collection_id="580e63fc8c9a982ac9b8b745", - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + 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", + ), ) validate_response(async_response, expected_response, expected_types) @@ -68,6 +75,7 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: "slug": "post-body", "displayName": "Post Body", "helpText": "Add the body of your post here", + "validations": {"additionalProperties": "additionalProperties"}, } expected_types: typing.Any = { "id": None, @@ -77,6 +85,7 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: "slug": None, "displayName": None, "helpText": None, + "validations": {"additionalProperties": None}, } response = client.collections.fields.update( collection_id="580e63fc8c9a982ac9b8b745", diff --git a/tests/collections/test_items.py b/tests/collections/test_items.py index fc926a7..ded27e7 100644 --- a/tests/collections/test_items.py +++ b/tests/collections/test_items.py @@ -6,12 +6,15 @@ from ..utilities import validate_response from webflow import CollectionItemPostSingle from webflow import CollectionItemPostSingleFieldData +from webflow.resources.collections.resources.items import ItemsDeleteItemsRequestItemsItem from webflow import CollectionItemWithIdInput from webflow import CollectionItemWithIdInputFieldData from webflow import CollectionItem from webflow import CollectionItemFieldData +from webflow.resources.collections.resources.items import ItemsDeleteItemsLiveRequestItemsItem from webflow.resources.collections.resources.items import SingleCmsItem from webflow import CollectionItemPatchSingleFieldData +from webflow.resources.collections.resources.items import ItemIDs async def test_list_items(client: Webflow, async_client: AsyncWebflow) -> None: @@ -140,42 +143,123 @@ async def test_create_item(client: Webflow, async_client: AsyncWebflow) -> None: async def test_delete_items(client: Webflow, async_client: AsyncWebflow) -> None: # Type ignore to avoid mypy complaining about the function not being meant to return a value assert ( - client.collections.items.delete_items(collection_id="580e63fc8c9a982ac9b8b745") # type: ignore[func-returns-value] + client.collections.items.delete_items( + collection_id="580e63fc8c9a982ac9b8b745", + items=[ItemsDeleteItemsRequestItemsItem(id="580e64008c9a982ac9b8b754")], + ) # type: ignore[func-returns-value] is None ) assert ( - await async_client.collections.items.delete_items(collection_id="580e63fc8c9a982ac9b8b745") # type: ignore[func-returns-value] + await async_client.collections.items.delete_items( + collection_id="580e63fc8c9a982ac9b8b745", + items=[ItemsDeleteItemsRequestItemsItem(id="580e64008c9a982ac9b8b754")], + ) # type: ignore[func-returns-value] is None ) async def test_update_items(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "id", - "cmsLocaleId": "653ad57de882f528b32e810e", - "lastPublished": "2023-03-17T18:47:35.560Z", - "lastUpdated": "2023-03-17T18:47:35.560Z", - "createdOn": "2023-03-17T18:47:35.560Z", - "isArchived": True, - "isDraft": True, - "fieldData": { - "name": "My new item", - "slug": "my-new-item", - "date": "2022-11-18T00:00:00.000Z", - "featured": False, - "color": "#db4b68", - }, + "items": [ + { + "id": "66f6ed9576ddacf3149d5ea6", + "cmsLocaleId": "66f6e966c9e1dc700a857ca5", + "lastPublished": "2024-09-27T17:38:29.066Z", + "lastUpdated": "2024-09-27T17:38:29.066Z", + "createdOn": "2024-09-27T17:38:29.066Z", + "isArchived": False, + "isDraft": False, + "fieldData": {"name": "Ne Paniquez Pas", "slug": "ne-paniquez-pas", "featured": False}, + }, + { + "id": "66f6ed9576ddacf3149d5ea6", + "cmsLocaleId": "66f6e966c9e1dc700a857ca4", + "lastPublished": "2024-09-27T17:38:29.066Z", + "lastUpdated": "2024-09-27T17:38:29.066Z", + "createdOn": "2024-09-27T17:38:29.066Z", + "isArchived": False, + "isDraft": False, + "fieldData": {"name": "No Entrar en Pánico", "slug": "no-entrar-en-panico", "featured": False}, + }, + { + "id": "66f6ed9576ddacf3149d5eaa", + "cmsLocaleId": "66f6e966c9e1dc700a857ca5", + "lastPublished": "2024-09-27T17:38:29.066Z", + "lastUpdated": "2024-09-27T17:38:29.066Z", + "createdOn": "2024-09-27T17:38:29.066Z", + "isArchived": False, + "isDraft": False, + "fieldData": { + "name": "Au Revoir et Merci pour Tous les Poissons", + "slug": "au-revoir-et-merci", + "featured": False, + }, + }, + { + "id": "66f6ed9576ddacf3149d5eaa", + "cmsLocaleId": "66f6e966c9e1dc700a857ca4", + "lastPublished": "2024-09-27T17:38:29.066Z", + "lastUpdated": "2024-09-27T17:38:29.066Z", + "createdOn": "2024-09-27T17:38:29.066Z", + "isArchived": False, + "isDraft": False, + "fieldData": { + "name": "Hasta Luego y Gracias por Todo el Pescado", + "slug": "hasta-luego-y-gracias", + "featured": False, + }, + }, + ], + "pagination": {"limit": 25, "offset": 0, "total": 4}, } expected_types: typing.Any = { - "id": None, - "cmsLocaleId": None, - "lastPublished": None, - "lastUpdated": None, - "createdOn": None, - "isArchived": None, - "isDraft": None, - "fieldData": {"name": None, "slug": None}, + "items": ( + "list", + { + 0: { + "id": None, + "cmsLocaleId": None, + "lastPublished": None, + "lastUpdated": None, + "createdOn": None, + "isArchived": None, + "isDraft": None, + "fieldData": {"name": None, "slug": None}, + }, + 1: { + "id": None, + "cmsLocaleId": None, + "lastPublished": None, + "lastUpdated": None, + "createdOn": None, + "isArchived": None, + "isDraft": None, + "fieldData": {"name": None, "slug": None}, + }, + 2: { + "id": None, + "cmsLocaleId": None, + "lastPublished": None, + "lastUpdated": None, + "createdOn": None, + "isArchived": None, + "isDraft": None, + "fieldData": {"name": None, "slug": None}, + }, + 3: { + "id": None, + "cmsLocaleId": None, + "lastPublished": None, + "lastUpdated": None, + "createdOn": None, + "isArchived": None, + "isDraft": None, + "fieldData": {"name": None, "slug": None}, + }, + }, + ), + "pagination": {"limit": None, "offset": None, "total": None}, } response = client.collections.items.update_items( collection_id="580e63fc8c9a982ac9b8b745", @@ -366,12 +450,18 @@ async def test_create_item_live(client: Webflow, async_client: AsyncWebflow) -> async def test_delete_items_live(client: Webflow, async_client: AsyncWebflow) -> None: # Type ignore to avoid mypy complaining about the function not being meant to return a value assert ( - client.collections.items.delete_items_live(collection_id="580e63fc8c9a982ac9b8b745") # type: ignore[func-returns-value] + client.collections.items.delete_items_live( + collection_id="580e63fc8c9a982ac9b8b745", + items=[ItemsDeleteItemsLiveRequestItemsItem(id="580e64008c9a982ac9b8b754")], + ) # type: ignore[func-returns-value] is None ) assert ( - await async_client.collections.items.delete_items_live(collection_id="580e63fc8c9a982ac9b8b745") # type: ignore[func-returns-value] + await async_client.collections.items.delete_items_live( + collection_id="580e63fc8c9a982ac9b8b745", + items=[ItemsDeleteItemsLiveRequestItemsItem(id="580e64008c9a982ac9b8b754")], + ) # type: ignore[func-returns-value] is None ) @@ -382,31 +472,31 @@ async def test_update_items_live(client: Webflow, async_client: AsyncWebflow) -> { "id": "66f6ed9576ddacf3149d5ea6", "cmsLocaleId": "66f6e966c9e1dc700a857ca5", - "lastPublished": "2023-03-17T18:47:35.560Z", + "lastPublished": "2024-09-27T17:38:29.066Z", "lastUpdated": "2024-09-27T17:38:29.066Z", "createdOn": "2024-09-27T17:38:29.066Z", - "isArchived": True, - "isDraft": True, + "isArchived": False, + "isDraft": False, "fieldData": {"name": "Ne Paniquez Pas", "slug": "ne-paniquez-pas", "featured": False}, }, { "id": "66f6ed9576ddacf3149d5ea6", "cmsLocaleId": "66f6e966c9e1dc700a857ca4", - "lastPublished": "2023-03-17T18:47:35.560Z", + "lastPublished": "2024-09-27T17:38:29.066Z", "lastUpdated": "2024-09-27T17:38:29.066Z", "createdOn": "2024-09-27T17:38:29.066Z", - "isArchived": True, - "isDraft": True, + "isArchived": False, + "isDraft": False, "fieldData": {"name": "No Entrar en Pánico", "slug": "no-entrar-en-panico", "featured": False}, }, { "id": "66f6ed9576ddacf3149d5eaa", "cmsLocaleId": "66f6e966c9e1dc700a857ca5", - "lastPublished": "2023-03-17T18:47:35.560Z", + "lastPublished": "2024-09-27T17:38:29.066Z", "lastUpdated": "2024-09-27T17:38:29.066Z", "createdOn": "2024-09-27T17:38:29.066Z", - "isArchived": True, - "isDraft": True, + "isArchived": False, + "isDraft": False, "fieldData": { "name": "Au Revoir et Merci pour Tous les Poissons", "slug": "au-revoir-et-merci", @@ -416,11 +506,11 @@ async def test_update_items_live(client: Webflow, async_client: AsyncWebflow) -> { "id": "66f6ed9576ddacf3149d5eaa", "cmsLocaleId": "66f6e966c9e1dc700a857ca4", - "lastPublished": "2023-03-17T18:47:35.560Z", + "lastPublished": "2024-09-27T17:38:29.066Z", "lastUpdated": "2024-09-27T17:38:29.066Z", "createdOn": "2024-09-27T17:38:29.066Z", - "isArchived": True, - "isDraft": True, + "isArchived": False, + "isDraft": False, "fieldData": { "name": "Hasta Luego y Gracias por Todo el Pescado", "slug": "hasta-luego-y-gracias", @@ -801,10 +891,14 @@ async def test_publish_item(client: Webflow, async_client: AsyncWebflow) -> None "errors": ["Staging item ID 643fd856d66b6528195ee2cf not found."], } expected_types: typing.Any = {"publishedItemIds": ("list", {0: None, 1: None}), "errors": ("list", {0: None})} - response = client.collections.items.publish_item(collection_id="580e63fc8c9a982ac9b8b745", item_ids=["itemIds"]) + response = client.collections.items.publish_item( + collection_id="580e63fc8c9a982ac9b8b745", + request=ItemIDs(item_ids=["643fd856d66b6528195ee2ca", "643fd856d66b6528195ee2cb", "643fd856d66b6528195ee2cc"]), + ) validate_response(response, expected_response, expected_types) async_response = await async_client.collections.items.publish_item( - collection_id="580e63fc8c9a982ac9b8b745", item_ids=["itemIds"] + collection_id="580e63fc8c9a982ac9b8b745", + request=ItemIDs(item_ids=["643fd856d66b6528195ee2ca", "643fd856d66b6528195ee2cb", "643fd856d66b6528195ee2cc"]), ) validate_response(async_response, expected_response, expected_types) diff --git a/tests/conftest.py b/tests/conftest.py index 019aab8..8d87434 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ from webflow import Webflow import os +from webflow.environment import WebflowEnvironment import pytest from webflow import AsyncWebflow @@ -9,12 +10,26 @@ @pytest.fixture def client() -> Webflow: return Webflow( - access_token=os.getenv("ENV_ACCESS_TOKEN", "access_token"), base_url=os.getenv("TESTS_BASE_URL", "base_url") + access_token=os.getenv("ENV_ACCESS_TOKEN", "access_token"), + environment=WebflowEnvironment( + base=os.getenv("TESTS_BASE_URL", "base_url"), + data_api=os.getenv("TESTS_BASE_URL", "base_url"), + content_delivery_api=os.getenv("TESTS_BASE_URL", "base_url"), + production=os.getenv("TESTS_BASE_URL", "base_url"), + cdn=os.getenv("TESTS_BASE_URL", "base_url"), + ), ) @pytest.fixture def async_client() -> AsyncWebflow: return AsyncWebflow( - access_token=os.getenv("ENV_ACCESS_TOKEN", "access_token"), base_url=os.getenv("TESTS_BASE_URL", "base_url") + access_token=os.getenv("ENV_ACCESS_TOKEN", "access_token"), + environment=WebflowEnvironment( + base=os.getenv("TESTS_BASE_URL", "base_url"), + data_api=os.getenv("TESTS_BASE_URL", "base_url"), + content_delivery_api=os.getenv("TESTS_BASE_URL", "base_url"), + production=os.getenv("TESTS_BASE_URL", "base_url"), + cdn=os.getenv("TESTS_BASE_URL", "base_url"), + ), ) diff --git a/tests/sites/test_activity_logs.py b/tests/sites/test_activity_logs.py index f289464..722a4f2 100644 --- a/tests/sites/test_activity_logs.py +++ b/tests/sites/test_activity_logs.py @@ -18,9 +18,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "user": {"id": "6509cd56e90eec668b009712", "displayName": "John Doe"}, "resourceId": "654c16c7b229e56bcf26870c", "resourceName": "foo-bar", - "newValue": "newValue", - "previousValue": "previousValue", - "payload": {"key": "value"}, } ], "pagination": {"limit": 25, "offset": 0, "total": 1}, @@ -38,9 +35,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "user": {"id": None, "displayName": None}, "resourceId": None, "resourceName": None, - "newValue": None, - "previousValue": None, - "payload": ("dict", {0: (None, None)}), } }, ), diff --git a/tests/sites/test_comments.py b/tests/sites/test_comments.py new file mode 100644 index 0000000..2be436d --- /dev/null +++ b/tests/sites/test_comments.py @@ -0,0 +1,212 @@ +# This file was auto-generated by Fern from our API Definition. + +from webflow import Webflow +from webflow import AsyncWebflow +import typing +from ..utilities import validate_response + + +async def test_list_comment_threads(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "comments": [ + { + "id": "679d2ddb5196117ad04d1ffa", + "siteId": "679826b3b20b045e176bc4b5", + "pageId": "679826b3b20b045e176bc4bc", + "localeId": "67993753d910db250db64b3e", + "breakpoint": "main", + "url": "https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc", + "content": "Let's go to the pub! [[6287ec36a841b25637c663df]] ", + "isResolved": False, + "author": { + "userId": "6287ec36a841b25637c663df", + "email": "ford.prefect@heartofgold.spaceship", + "name": "Ford Prefect", + }, + "mentionedUsers": [ + { + "userId": "6287ec36a841b25637c663df", + "email": "arthur.dent@heartofgold.spaceship", + "name": "Arthur Dent", + } + ], + "createdOn": "2025-01-31T20:08:59.759Z", + "lastUpdated": "2025-01-31T20:08:59.759Z", + }, + { + "id": "679d2ddb5196117ad04d1ffc", + "siteId": "679826b3b20b045e176bc4b5", + "pageId": "679826b3b20b045e176bc4bc", + "localeId": "67993753d910db250db64b3e", + "breakpoint": "main", + "url": "https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc", + "content": "You have five minutes left to drink it [[6287ec36a841b25637c663df]] ", + "isResolved": False, + "author": { + "userId": "6287ec36a841b25637c663df", + "email": "ford.prefect@heartofgold.spaceship", + "name": "Ford Prefect", + }, + "mentionedUsers": [ + { + "userId": "6287ec36a841b25637c663df", + "email": "arthur.dent@heartofgold.spaceship", + "name": "Arthur Dent", + } + ], + "createdOn": "2025-01-31T20:08:59.759Z", + "lastUpdated": "2025-01-31T20:08:59.759Z", + }, + ], + "pagination": {"limit": 2, "offset": 0, "total": 2}, + } + expected_types: typing.Any = { + "comments": ( + "list", + { + 0: { + "id": None, + "siteId": None, + "pageId": None, + "localeId": None, + "breakpoint": None, + "url": None, + "content": None, + "isResolved": None, + "author": {"userId": None, "email": None, "name": None}, + "mentionedUsers": ("list", {0: {"userId": None, "email": None, "name": None}}), + "createdOn": None, + "lastUpdated": None, + }, + 1: { + "id": None, + "siteId": None, + "pageId": None, + "localeId": None, + "breakpoint": None, + "url": None, + "content": None, + "isResolved": None, + "author": {"userId": None, "email": None, "name": None}, + "mentionedUsers": ("list", {0: {"userId": None, "email": None, "name": None}}), + "createdOn": None, + "lastUpdated": None, + }, + }, + ), + "pagination": {"limit": None, "offset": None, "total": None}, + } + response = client.sites.comments.list_comment_threads( + site_id="580e63e98c9a982ac9b8b741", locale_id="65427cf400e02b306eaa04a0" + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.comments.list_comment_threads( + site_id="580e63e98c9a982ac9b8b741", locale_id="65427cf400e02b306eaa04a0" + ) + validate_response(async_response, expected_response, expected_types) + + +async def test_get_comment_thread(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "id": "580e64008c9a982ac9b8b754", + "siteId": "580e64008c9a982ac9b8b754", + "pageId": "580e64008c9a982ac9b8b754", + "localeId": "580e64008c9a982ac9b8b754", + "itemId": "580e64008c9a982ac9b8b754", + "breakpoint": "main", + "url": "https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc", + "content": "This is a comment reply", + "isResolved": True, + "author": {"userId": "userId", "email": "email", "name": "name"}, + "mentionedUsers": [ + {"userId": "6287ec36a841b25637c663df", "email": "arthur.dent@heartofgold.spaceship", "name": "Arthur Dent"} + ], + "createdOn": "2023-03-17T18:47:35.560Z", + "lastUpdated": "2023-03-17T18:47:35.560Z", + } + expected_types: typing.Any = { + "id": None, + "siteId": None, + "pageId": None, + "localeId": None, + "itemId": None, + "breakpoint": None, + "url": None, + "content": None, + "isResolved": None, + "author": {"userId": None, "email": None, "name": None}, + "mentionedUsers": ("list", {0: {"userId": None, "email": None, "name": None}}), + "createdOn": None, + "lastUpdated": None, + } + response = client.sites.comments.get_comment_thread( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.comments.get_comment_thread( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + validate_response(async_response, expected_response, expected_types) + + +async def test_list_comment_replies(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "comments": [ + { + "id": "679d2ddb5196117ad04d1ffa", + "commentId": "679d2ddb5196117ad04d1ff8", + "siteId": "679826b3b20b045e176bc4b5", + "pageId": "679826b3b20b045e176bc4bc", + "localeId": "67993753d910db250db64b3e", + "breakpoint": "main", + "content": "This comment mentions another user [[6287ec36a841b25637c663df]] ", + "isResolved": False, + "author": {"id": "id", "email": "email", "name": "name"}, + "mentionedUsers": [{"id": "id", "email": "arthur.dent@example.com", "name": "Arthur Dent"}], + "lastUpdated": "2025-01-31T20:08:59.759Z", + "createdOn": "2025-01-31T20:08:59.759Z", + } + ], + "pagination": {"limit": 2, "offset": 0, "total": 1}, + } + expected_types: typing.Any = { + "comments": ( + "list", + { + 0: { + "id": None, + "commentId": None, + "siteId": None, + "pageId": None, + "localeId": None, + "breakpoint": None, + "content": None, + "isResolved": None, + "author": {"id": None, "email": None, "name": None}, + "mentionedUsers": ("list", {0: {"id": None, "email": None, "name": None}}), + "lastUpdated": None, + "createdOn": None, + } + }, + ), + "pagination": {"limit": None, "offset": None, "total": None}, + } + response = client.sites.comments.list_comment_replies( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.comments.list_comment_replies( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + validate_response(async_response, expected_response, expected_types) diff --git a/tests/sites/test_robots_txt.py b/tests/sites/test_robots_txt.py new file mode 100644 index 0000000..cb38204 --- /dev/null +++ b/tests/sites/test_robots_txt.py @@ -0,0 +1,145 @@ +# This file was auto-generated by Fern from our API Definition. + +from webflow import Webflow +from webflow import AsyncWebflow +import typing +from ..utilities import validate_response +from webflow import RobotsRulesItem + + +async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "rules": [ + { + "userAgent": "googlebot", + "allows": ["/public"], + "disallows": ["/vogon-poetry", "/total-perspective-vortex"], + } + ], + "sitemap": "https://heartofgold.ship/sitemap.xml", + } + expected_types: typing.Any = { + "rules": ( + "list", + {0: {"userAgent": None, "allows": ("list", {0: None}), "disallows": ("list", {0: None, 1: None})}}, + ), + "sitemap": None, + } + response = client.sites.robots_txt.get(site_id="580e63e98c9a982ac9b8b741") + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.robots_txt.get(site_id="580e63e98c9a982ac9b8b741") + validate_response(async_response, expected_response, expected_types) + + +async def test_put(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "rules": [ + { + "userAgent": "googlebot", + "allows": ["/public"], + "disallows": ["/vogon-poetry", "/total-perspective-vortex"], + } + ], + "sitemap": "https://heartofgold.ship/sitemap.xml", + } + expected_types: typing.Any = { + "rules": ( + "list", + {0: {"userAgent": None, "allows": ("list", {0: None}), "disallows": ("list", {0: None, 1: None})}}, + ), + "sitemap": None, + } + response = client.sites.robots_txt.put( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", allows=["/public"], disallows=["/vogon-poetry", "/total-perspective-vortex"] + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.robots_txt.put( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", allows=["/public"], disallows=["/vogon-poetry", "/total-perspective-vortex"] + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + validate_response(async_response, expected_response, expected_types) + + +async def test_delete(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "rules": [ + { + "userAgent": "googlebot", + "allows": ["/public"], + "disallows": ["/vogon-poetry", "/total-perspective-vortex"], + } + ], + "sitemap": "https://heartofgold.ship/sitemap.xml", + } + expected_types: typing.Any = { + "rules": ( + "list", + {0: {"userAgent": None, "allows": ("list", {0: None}), "disallows": ("list", {0: None, 1: None})}}, + ), + "sitemap": None, + } + response = client.sites.robots_txt.delete( + site_id="580e63e98c9a982ac9b8b741", + rules=[RobotsRulesItem(user_agent="*", allows=["/public"], disallows=["/bubbles"])], + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.robots_txt.delete( + site_id="580e63e98c9a982ac9b8b741", + rules=[RobotsRulesItem(user_agent="*", allows=["/public"], disallows=["/bubbles"])], + ) + validate_response(async_response, expected_response, expected_types) + + +async def test_patch(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "rules": [ + { + "userAgent": "googlebot", + "allows": ["/public"], + "disallows": ["/vogon-poetry", "/total-perspective-vortex"], + } + ], + "sitemap": "https://heartofgold.ship/sitemap.xml", + } + expected_types: typing.Any = { + "rules": ( + "list", + {0: {"userAgent": None, "allows": ("list", {0: None}), "disallows": ("list", {0: None, 1: None})}}, + ), + "sitemap": None, + } + response = 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", + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_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", + ) + validate_response(async_response, expected_response, expected_types) diff --git a/tests/sites/test_scripts.py b/tests/sites/test_scripts.py index cc5d71c..beb0949 100644 --- a/tests/sites/test_scripts.py +++ b/tests/sites/test_scripts.py @@ -101,7 +101,6 @@ async def test_list_custom_code_blocks(client: Webflow, async_client: AsyncWebfl "blocks": [ { "siteId": "6258612d1ee792848f805dcf", - "pageId": "pageId", "type": "site", "scripts": [ {"id": "chartjs", "location": "header", "version": "4.4.2", "attributes": {"key": "value"}} @@ -126,7 +125,6 @@ async def test_list_custom_code_blocks(client: Webflow, async_client: AsyncWebfl { 0: { "siteId": None, - "pageId": None, "type": None, "scripts": ( "list", diff --git a/tests/sites/test_well_known.py b/tests/sites/test_well_known.py new file mode 100644 index 0000000..feb3609 --- /dev/null +++ b/tests/sites/test_well_known.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from webflow import Webflow +from webflow import AsyncWebflow + + +async def test_put(client: Webflow, async_client: AsyncWebflow) -> None: + # Type ignore to avoid mypy complaining about the function not being meant to return a value + assert ( + client.sites.well_known.put(site_id="580e63e98c9a982ac9b8b741", file_name="fileName", file_data="fileData") # type: ignore[func-returns-value] + is None + ) + + assert ( + await async_client.sites.well_known.put( + site_id="580e63e98c9a982ac9b8b741", file_name="fileName", file_data="fileData" + ) # type: ignore[func-returns-value] + is None + ) + + +async def test_delete(client: Webflow, async_client: AsyncWebflow) -> None: + # Type ignore to avoid mypy complaining about the function not being meant to return a value + assert ( + client.sites.well_known.delete(site_id="580e63e98c9a982ac9b8b741") # type: ignore[func-returns-value] + is None + ) + + assert ( + await async_client.sites.well_known.delete(site_id="580e63e98c9a982ac9b8b741") # type: ignore[func-returns-value] + is None + ) diff --git a/tests/test_assets.py b/tests/test_assets.py index af158ef..8c9afaa 100644 --- a/tests/test_assets.py +++ b/tests/test_assets.py @@ -30,9 +30,33 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "quality": 100, } ], - "altText": "A red chair", - } - ] + "altText": "A single candy wrapper", + }, + { + "id": "63e5889e7fe4eafa7384cea5", + "contentType": "image/png", + "size": 2212772, + "siteId": "63938b302ea6b0aa6f3d8745", + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg", + "originalFileName": "Gum-Wrapper.svg", + "displayName": "63e5889e7fe4eafa7384cea5_Gum-Wrapper.png", + "lastUpdated": "2023-03-01T23:42:57Z", + "createdOn": "2023-02-09T23:58:22Z", + "variants": [ + { + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "originalFileName": "Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "displayName": "660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "format": "png", + "width": 500, + "height": 900, + "quality": 100, + } + ], + "altText": "A single gum wrapper", + }, + ], + "pagination": {"limit": 2, "offset": 0, "total": 2}, } expected_types: typing.Any = { "assets": ( @@ -63,9 +87,36 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: }, ), "altText": None, - } + }, + 1: { + "id": None, + "contentType": None, + "size": "integer", + "siteId": None, + "hostedUrl": None, + "originalFileName": None, + "displayName": None, + "lastUpdated": "datetime", + "createdOn": "datetime", + "variants": ( + "list", + { + 0: { + "hostedUrl": None, + "originalFileName": None, + "displayName": None, + "format": None, + "width": "integer", + "height": "integer", + "quality": "integer", + } + }, + ), + "altText": None, + }, }, - ) + ), + "pagination": {"limit": None, "offset": None, "total": None}, } response = client.assets.list(site_id="580e63e98c9a982ac9b8b741") validate_response(response, expected_response, expected_types) @@ -94,7 +145,7 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "parentFolder": "6436b1ce5281cace05b65aea", "uploadUrl": "https://s3.amazonaws.com/webflow-dev-assets/643021114e290e0d3a0602b2/64358b9544249dc43d37d2b7_Screenshot%202023-04-11%20at%209.50.42%20AM.png", "assetUrl": "https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d907ab9e91e3e9f56385e_paranoidAndroid-2024.png", - "hostedUrl": "https://d1otoma47x30pg.cloudfront.net/643021114e290e0d3a0602b2/64358b9544249dc43d37d2b7_Screenshot%202023-04-11%20at%209.50.42%20AM.png", + "hostedUrl": "https://dev-assets.website-files.com/643021114e290e0d3a0602b2/64358b9544249dc43d37d2b7_Screenshot%202023-04-11%20at%209.50.42%20AM.png", "originalFileName": "file.png", "createdOn": "2023-04-11T16:32:21Z", "lastUpdated": "2023-04-12T20:31:03Z", @@ -136,28 +187,27 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "55131cd036c09f7d07883dfc", + "id": "63e5889e7fe4eafa7384cea4", "contentType": "image/png", - "size": 1500, - "siteId": "62749158efef318abc8d5a0f", - "hostedUrl": "example.com/hostedimage.png", - "originalFileName": "image.png", - "displayName": "example-image-123.png", - "lastUpdated": "2016-09-06T21:12:22Z", - "createdOn": "2016-09-02T23:26:22Z", + "size": 2212772, + "siteId": "63938b302ea6b0aa6f3d8745", + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg", + "originalFileName": "Candy-Wrapper.svg", + "displayName": "63e5889e7fe4eafa7384cea4_Candy-Wrapper.png", + "lastUpdated": "2023-03-01T23:42:57Z", + "createdOn": "2023-02-09T23:58:22Z", "variants": [ { - "hostedUrl": "example.com/hostedimage.png", - "originalFileName": "image.png", - "displayName": "A brown dog", - "format": "format", - "width": 1500, + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "originalFileName": "Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "displayName": "660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "format": "png", + "width": 500, "height": 900, - "quality": 1, - "error": "error", + "quality": 100, } ], - "altText": "A red chair", + "altText": "A single candy wrapper", } expected_types: typing.Any = { "id": None, @@ -180,7 +230,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "width": "integer", "height": "integer", "quality": "integer", - "error": None, } }, ), @@ -208,28 +257,27 @@ async def test_delete(client: Webflow, async_client: AsyncWebflow) -> None: async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "55131cd036c09f7d07883dfc", + "id": "63e5889e7fe4eafa7384cea4", "contentType": "image/png", - "size": 1500, - "siteId": "62749158efef318abc8d5a0f", - "hostedUrl": "example.com/hostedimage.png", - "originalFileName": "image.png", - "displayName": "example-image-123.png", - "lastUpdated": "2016-09-06T21:12:22Z", - "createdOn": "2016-09-02T23:26:22Z", + "size": 2212772, + "siteId": "63938b302ea6b0aa6f3d8745", + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg", + "originalFileName": "Candy-Wrapper.svg", + "displayName": "63e5889e7fe4eafa7384cea4_Candy-Wrapper.png", + "lastUpdated": "2023-03-01T23:42:57Z", + "createdOn": "2023-02-09T23:58:22Z", "variants": [ { - "hostedUrl": "example.com/hostedimage.png", - "originalFileName": "image.png", - "displayName": "A brown dog", - "format": "format", - "width": 1500, + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "originalFileName": "Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "displayName": "660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "format": "png", + "width": 500, "height": 900, - "quality": 1, - "error": "error", + "quality": 100, } ], - "altText": "A red chair", + "altText": "A single candy wrapper", } expected_types: typing.Any = { "id": None, @@ -252,7 +300,6 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: "width": "integer", "height": "integer", "quality": "integer", - "error": None, } }, ), @@ -271,7 +318,6 @@ async def test_list_folders(client: Webflow, async_client: AsyncWebflow) -> None { "id": "6390c49774a71f0e3c1a08ee", "displayName": "emoji icons", - "parentFolder": "6390c49774a71f99f21a08eb", "assets": ["63e5889e7fe4eafa7384cea4", "659595234426a9fcbad57043"], "siteId": "6390c49674a71f84b51a08d8", "createdOn": "2018-10-14T21:55:49Z", @@ -287,7 +333,6 @@ async def test_list_folders(client: Webflow, async_client: AsyncWebflow) -> None 0: { "id": None, "displayName": None, - "parentFolder": None, "assets": ("list", {0: None, 1: None}), "siteId": None, "createdOn": "datetime", diff --git a/tests/test_collections.py b/tests/test_collections.py index 1e76945..1395cbd 100644 --- a/tests/test_collections.py +++ b/tests/test_collections.py @@ -4,6 +4,9 @@ from webflow import AsyncWebflow import typing from .utilities import validate_response +from webflow import StaticField +from webflow import ReferenceField +from webflow import ReferenceFieldMetadata async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: @@ -75,22 +78,40 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "580e63fc8c9a982ac9b8b745", + "id": "562ac0395358780a1f5e6fbd", "displayName": "Blog Posts", "singularName": "Blog Post", - "slug": "post", + "slug": "posts", "createdOn": "2016-10-24T19:41:48Z", "lastUpdated": "2016-10-24T19:42:38Z", "fields": [ { - "id": "23cc2d952d4e4631ffd4345d2743db4e", + "id": "id", "isRequired": True, "isEditable": True, "type": "PlainText", - "slug": "name", - "displayName": "Name", - "helpText": "helpText", - } + "slug": "title", + "displayName": "Title", + "helpText": "The title of the blog post", + }, + { + "id": "id", + "isRequired": True, + "isEditable": True, + "type": "RichText", + "slug": "content", + "displayName": "Content", + "helpText": "The content of the blog post", + }, + { + "id": "id", + "isRequired": True, + "isEditable": True, + "type": "Reference", + "slug": "author", + "displayName": "Author", + "helpText": "The author of the blog post", + }, ], } expected_types: typing.Any = { @@ -111,39 +132,234 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "slug": None, "displayName": None, "helpText": None, - } + }, + 1: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 2: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, }, ), } response = client.collections.create( - site_id="580e63e98c9a982ac9b8b741", display_name="Blog Posts", singular_name="Blog Post", slug="posts" + site_id="580e63e98c9a982ac9b8b741", + display_name="Blog Posts", + singular_name="Blog Post", + slug="posts", + fields=[ + StaticField( + is_required=True, type="PlainText", display_name="Title", help_text="The title of the blog post" + ), + StaticField( + is_required=True, type="RichText", display_name="Content", help_text="The content of the blog post" + ), + ReferenceField( + is_required=True, + type="Reference", + display_name="Author", + help_text="The author of the blog post", + metadata=ReferenceFieldMetadata(collection_id="23cc2d952d4e4631ffd4345d2743db4e"), + ), + ], ) validate_response(response, expected_response, expected_types) async_response = await async_client.collections.create( - site_id="580e63e98c9a982ac9b8b741", display_name="Blog Posts", singular_name="Blog Post", slug="posts" + site_id="580e63e98c9a982ac9b8b741", + display_name="Blog Posts", + singular_name="Blog Post", + slug="posts", + fields=[ + StaticField( + is_required=True, type="PlainText", display_name="Title", help_text="The title of the blog post" + ), + StaticField( + is_required=True, type="RichText", display_name="Content", help_text="The content of the blog post" + ), + ReferenceField( + is_required=True, + type="Reference", + display_name="Author", + help_text="The author of the blog post", + metadata=ReferenceFieldMetadata(collection_id="23cc2d952d4e4631ffd4345d2743db4e"), + ), + ], ) validate_response(async_response, expected_response, expected_types) async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "580e63fc8c9a982ac9b8b745", - "displayName": "Blog Posts", - "singularName": "Blog Post", - "slug": "post", - "createdOn": "2016-10-24T19:41:48Z", - "lastUpdated": "2016-10-24T19:42:38Z", + "id": "7f15043107e2fc95644e93807ee25dd6", + "displayName": "Guide Entries", + "singularName": "Guide Entry", + "slug": "guide-entry", + "createdOn": "2024-04-12T12:42:00Z", + "lastUpdated": "2024-04-12T12:42:00Z", "fields": [ { - "id": "23cc2d952d4e4631ffd4345d2743db4e", + "id": "5e2a1b3c4d5e6f7890a1b2c3", "isRequired": True, "isEditable": True, "type": "PlainText", "slug": "name", - "displayName": "Name", - "helpText": "helpText", - } + "displayName": "Entry Title", + "helpText": "Name of the entry.", + }, + { + "id": "5e2a1b3c4d5e6f7890a1b2c4", + "isRequired": True, + "isEditable": True, + "type": "PlainText", + "slug": "slug", + "displayName": "Slug", + "helpText": "Slug of the entry.", + }, + { + "id": "6f7e8d9c0b1a2e3d4c5b6a7f", + "isRequired": False, + "isEditable": True, + "type": "PlainText", + "slug": "summary", + "displayName": "Summary", + "helpText": "A short summary of the entry.", + }, + { + "id": "1a2b3c4d5e6f7a8b9c0d1e2f", + "isRequired": False, + "isEditable": True, + "type": "RichText", + "slug": "entry-html", + "displayName": "Entry HTML", + "helpText": "The HTML content of the entry.", + }, + { + "id": "7e8d9c0b1a2e3d4c5b6a7f8e", + "isRequired": False, + "isEditable": True, + "type": "Image", + "slug": "illustration-image", + "displayName": "Illustration Image", + "helpText": "An image of the entry.", + }, + { + "id": "2f3e4d5c6b7a8e9d0c1b2a3f", + "isRequired": False, + "isEditable": True, + "type": "VideoLink", + "slug": "demonstration-video", + "displayName": "Demonstration Video", + "helpText": "A video of the entry.", + }, + { + "id": "8e9d0c1b2a3f4e5d6c7b8a9e", + "isRequired": False, + "isEditable": True, + "type": "Link", + "slug": "more-info-link", + "displayName": "More Info Link", + "helpText": "A link to more information about the entry.", + }, + { + "id": "3f4e5d6c7b8a9e0d1c2b3a4f", + "isRequired": False, + "isEditable": True, + "type": "Number", + "slug": "importance-level", + "displayName": "Importance Level", + "helpText": "The importance level of the entry.", + }, + { + "id": "9e0d1c2b3a4f5e6d7c8b9a0e", + "isRequired": False, + "isEditable": True, + "type": "Switch", + "slug": "is-essential", + "displayName": "Is Essential", + "helpText": "Is this entry essential?", + }, + { + "id": "4f5e6d7c8b9a0e1d2c3b4a5f", + "isRequired": False, + "isEditable": True, + "type": "Color", + "slug": "first-mentioned", + "displayName": "First Mentioned", + "helpText": "Date of the first mention of the subject.", + }, + { + "id": "0e1d2c3b4a5f6e7d8c9b0a1e", + "isRequired": False, + "isEditable": True, + "type": "Color", + "slug": "towel-color", + "displayName": "Towel Color", + "helpText": "The color of the towel.", + }, + { + "id": "5f6e7d8c9b0a1e2d3c4b5a6f", + "isRequired": False, + "isEditable": True, + "type": "Reference", + "slug": "related-entry", + "displayName": "Related Entry", + "helpText": "A related entry.", + }, + { + "id": "1e2d3c4b5a6f7e8d9c0b1a2f", + "isRequired": False, + "isEditable": True, + "type": "MultiReference", + "slug": "mentioned-in-entries", + "displayName": "Mentioned In Entries", + "helpText": "Entries that mention this subject.", + }, + { + "id": "6f7e8d9c0b1a2e3d4c5b6a8f", + "isRequired": False, + "isEditable": True, + "type": "Option", + "slug": "item-type", + "displayName": "Item Type", + "helpText": "The type of item.", + }, + { + "id": "2e3d4c5b6a7f8e9d0c1b2a4f", + "isRequired": False, + "isEditable": True, + "type": "File", + "slug": "guide-file", + "displayName": "Guide File", + }, + { + "id": "7f8e9d0c1b2a3f4e5d6c8b9e", + "isRequired": False, + "isEditable": True, + "type": "Email", + "slug": "contributor-email", + "displayName": "Contributor Email", + }, + { + "id": "3a4f5e6d7c8b9a0e1d2c4b5f", + "isRequired": False, + "isEditable": True, + "type": "Phone", + "slug": "emergency-contact", + "displayName": "Emergency Contact", + }, ], } expected_types: typing.Any = { @@ -164,7 +380,148 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "slug": None, "displayName": None, "helpText": None, - } + }, + 1: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 2: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 3: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 4: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 5: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 6: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 7: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 8: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 9: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 10: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 11: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 12: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 13: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 14: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + }, + 15: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + }, + 16: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + }, }, ), } diff --git a/tests/test_components.py b/tests/test_components.py index 2f5a42d..4d0598b 100644 --- a/tests/test_components.py +++ b/tests/test_components.py @@ -4,8 +4,12 @@ from webflow import AsyncWebflow import typing from .utilities import validate_response -from webflow import TextNodeWrite -from webflow import ComponentInstanceNodePropertyOverridesWrite +from webflow import TextNode +from webflow import Select +from webflow import SelectNodeWriteChoicesItem +from webflow import TextInput +from webflow import SubmitButton +from webflow import ComponentInstance from webflow import ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem from webflow.resources.components import ComponentPropertiesWritePropertiesItem @@ -27,20 +31,8 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "description": "A secondary button component that can be used across the site", "readonly": True, }, - { - "id": "6258612d1ee792848f805dcf", - "name": "Card", - "group": "Buttons", - "description": "A button component that can be used across the site", - "readonly": True, - }, - { - "id": "68a2b1d1ee792848f805dcf", - "name": "Nav", - "group": "Buttons", - "description": "A button component that can be used across the site", - "readonly": True, - }, + {"id": "6258612d1ee792848f805dcf", "name": "Card", "readonly": True}, + {"id": "68a2b1d1ee792848f805dcf", "name": "Nav", "readonly": True}, ], "pagination": {"limit": 20, "offset": 0, "total": 4}, } @@ -50,8 +42,8 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: { 0: {"id": None, "name": None, "group": None, "description": None, "readonly": None}, 1: {"id": None, "name": None, "group": None, "description": None, "readonly": None}, - 2: {"id": None, "name": None, "group": None, "description": None, "readonly": None}, - 3: {"id": None, "name": None, "group": None, "description": None, "readonly": None}, + 2: {"id": None, "name": None, "readonly": None}, + 3: {"id": None, "name": None, "readonly": None}, }, ), "pagination": {"limit": None, "offset": None, "total": None}, @@ -67,47 +59,46 @@ async def test_get_content(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { "componentId": "69118560-d0bc-15fc-bbf8-b8fe5f6535b5", "nodes": [ + {"id": "id", "text": {}, "attributes": {"key": "value"}, "type": "text"}, + {"id": "id", "text": {}, "attributes": {"key": "value"}, "type": "text"}, + {"id": "id", "image": {}, "attributes": {"key": "value"}, "type": "image"}, + {"id": "id", "placeholder": "placeholder", "attributes": {"key": "value"}, "type": "text-input"}, { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad623", - "componentId": "nodes", - "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], + "id": "id", + "choices": [{"value": "value", "text": "text"}], + "attributes": {"key": "value"}, + "type": "select", }, { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad627", - "componentId": "nodes", - "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], + "id": "id", + "value": "value", + "waitingText": "waitingText", + "attributes": {"key": "value"}, + "type": "submit-button", }, { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad629", - "componentId": "nodes", + "id": "id", + "componentId": "componentId", "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], - }, - { "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad631", - "componentId": "6258612d1ee792848f805dcf", - "propertyOverrides": [ - { - "propertyId": "a245c12d-995b-55ee-5ec7-aa36a6cad633", - "type": "Plain Text", - "text": {"text": "Don't Panic!"}, - }, - { - "propertyId": "a245c12d-995b-55ee-5ec7-aa36a6cad635", - "type": "Rich Text", - "text": {"html": "

Always know where your towel is.

"}, - }, - ], }, ], - "pagination": {"limit": 4, "offset": 0, "total": 4}, + "pagination": {"limit": 7, "offset": 0, "total": 7}, } expected_types: typing.Any = { "componentId": None, - "nodes": ("list", {0: "no_validate", 1: "no_validate", 2: "no_validate", 3: "no_validate"}), + "nodes": ( + "list", + { + 0: "no_validate", + 1: "no_validate", + 2: "no_validate", + 3: "no_validate", + 4: "no_validate", + 5: "no_validate", + 6: "no_validate", + }, + ), "pagination": {"limit": None, "offset": None, "total": None}, } response = client.components.get_content( @@ -133,14 +124,23 @@ async def test_update_content(client: Webflow, async_client: AsyncWebflow) -> No component_id="8505ba55-ef72-629e-f85c-33e4b703d48b", locale_id="65427cf400e02b306eaa04a0", nodes=[ - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623", text="

The Hitchhiker's Guide to the Galaxy

" ), - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627", text="

Don't Panic!

Always know where your towel is.

", ), - ComponentInstanceNodePropertyOverridesWrite( + Select( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635", + choices=[ + SelectNodeWriteChoicesItem(value="choice-1", text="First choice"), + SelectNodeWriteChoicesItem(value="choice-2", text="Second choice"), + ], + ), + TextInput(node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642", placeholder="Enter something here..."), + SubmitButton(node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671", value="Submit", waiting_text="Submitting..."), + ComponentInstance( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629", property_overrides=[ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem( @@ -161,14 +161,23 @@ async def test_update_content(client: Webflow, async_client: AsyncWebflow) -> No component_id="8505ba55-ef72-629e-f85c-33e4b703d48b", locale_id="65427cf400e02b306eaa04a0", nodes=[ - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623", text="

The Hitchhiker's Guide to the Galaxy

" ), - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627", text="

Don't Panic!

Always know where your towel is.

", ), - ComponentInstanceNodePropertyOverridesWrite( + Select( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635", + choices=[ + SelectNodeWriteChoicesItem(value="choice-1", text="First choice"), + SelectNodeWriteChoicesItem(value="choice-2", text="Second choice"), + ], + ), + TextInput(node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642", placeholder="Enter something here..."), + SubmitButton(node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671", value="Submit", waiting_text="Submitting..."), + ComponentInstance( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629", property_overrides=[ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem( diff --git a/tests/test_forms.py b/tests/test_forms.py index ee88977..f653d93 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -106,12 +106,7 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "createdOn": "2016-10-24T19:41:29Z", "lastUpdated": "2016-10-24T19:43:17Z", "fields": { - "660d5bcc9c0772150459dfb1": { - "displayName": "Name", - "type": "Plain", - "placeholder": "Enter your email", - "userVisible": True, - }, + "660d5bcc9c0772150459dfb1": {"displayName": "Name", "type": "Plain", "userVisible": True}, "589a331aa51e760df7ccb89d": { "displayName": "Email", "type": "Email", @@ -122,7 +117,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "responseSettings": { "redirectUrl": "https://example.com", "redirectMethod": "GET", - "redirectAction": "POST https://example.com", "sendEmailConfirmation": True, }, "id": "589a331aa51e760df7ccb89e", @@ -140,16 +134,11 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "fields": ( "dict", { - 0: (None, {"displayName": None, "type": None, "placeholder": None, "userVisible": None}), + 0: (None, {"displayName": None, "type": None, "userVisible": None}), 1: (None, {"displayName": None, "type": None, "placeholder": None, "userVisible": None}), }, ), - "responseSettings": { - "redirectUrl": None, - "redirectMethod": None, - "redirectAction": None, - "sendEmailConfirmation": None, - }, + "responseSettings": {"redirectUrl": None, "redirectMethod": None, "sendEmailConfirmation": None}, "id": None, "siteId": None, "siteDomainId": None, @@ -242,6 +231,19 @@ async def test_get_submission(client: Webflow, async_client: AsyncWebflow) -> No validate_response(async_response, expected_response, expected_types) +async def test_delete_submission(client: Webflow, async_client: AsyncWebflow) -> None: + # Type ignore to avoid mypy complaining about the function not being meant to return a value + assert ( + client.forms.delete_submission(form_submission_id="580e63e98c9a982ac9b8b741") # type: ignore[func-returns-value] + is None + ) + + assert ( + await async_client.forms.delete_submission(form_submission_id="580e63e98c9a982ac9b8b741") # type: ignore[func-returns-value] + is None + ) + + async def test_update_submission(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { "id": "6321ca84df3949bfc6752327", @@ -264,3 +266,60 @@ async def test_update_submission(client: Webflow, async_client: AsyncWebflow) -> async_response = await async_client.forms.update_submission(form_submission_id="580e63e98c9a982ac9b8b741") validate_response(async_response, expected_response, expected_types) + + +async def test_list_submissions_by_site(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "formSubmissions": [ + { + "id": "6321ca84df3949bfc6752327", + "displayName": "Sample Form", + "siteId": "62749158efef318abc8d5a0f", + "workspaceId": "62749158efef318abc8d5a0f", + "dateSubmitted": "2022-09-14T12:35:16Z", + "formResponse": {"First Name": "Arthur", "Last Name": "Dent"}, + }, + { + "id": "660d64fabf6e0a0d4edab981", + "displayName": "Sample Form", + "siteId": "62749158efef318abc8d5a0f", + "workspaceId": "62749158efef318abc8d5a0f", + "dateSubmitted": "2022-09-14T12:35:16Z", + "formResponse": {"First Name": "Ford", "Last Name": "Prefect"}, + }, + ], + "pagination": {"limit": 25, "offset": 0, "total": 2}, + } + expected_types: typing.Any = { + "formSubmissions": ( + "list", + { + 0: { + "id": None, + "displayName": None, + "siteId": None, + "workspaceId": None, + "dateSubmitted": "datetime", + "formResponse": ("dict", {0: (None, None), 1: (None, None)}), + }, + 1: { + "id": None, + "displayName": None, + "siteId": None, + "workspaceId": None, + "dateSubmitted": "datetime", + "formResponse": ("dict", {0: (None, None), 1: (None, None)}), + }, + }, + ), + "pagination": {"limit": None, "offset": None, "total": None}, + } + response = client.forms.list_submissions_by_site( + site_id="580e63e98c9a982ac9b8b741", element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0" + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.forms.list_submissions_by_site( + site_id="580e63e98c9a982ac9b8b741", element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0" + ) + validate_response(async_response, expected_response, expected_types) diff --git a/tests/test_orders.py b/tests/test_orders.py index a874784..c89ee5f 100644 --- a/tests/test_orders.py +++ b/tests/test_orders.py @@ -15,11 +15,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "comment": "Customer requested gift wrapping and a personalized note saying: Happy Birthday, Ford! 🎉 Please ensure the item is packed with extra bubble wrap for safe transit.", "orderComment": 'Please gift wrap with a personal note saying "Happy Birthday, Ford! 🎉', "acceptedOn": "2024-04-10T13:16:21Z", - "fulfilledOn": "2018-12-03T22:06:15Z", - "refundedOn": "2018-12-03T22:06:15Z", - "disputedOn": "2018-12-03T22:06:15Z", - "disputeUpdatedOn": "2018-12-03T22:06:15Z", - "disputeLastStatus": "warning_needs_response", "customerPaid": {"unit": "USD", "value": "5892", "string": " 211.55 USD"}, "netAmount": {"unit": "USD", "value": "5892", "string": " 200.89 USD"}, "applicationFee": {"unit": "USD", "value": "5892", "string": " 4.23 USD"}, @@ -82,7 +77,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "variantSlug": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantSKU": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 55.61 USD"}, "weight": 11, @@ -101,7 +96,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "variantSlug": "incredible-bronze-towels-sleek-frozen-incredible-metal", "variantSKU": "incredible-bronze-towels-sleek-frozen-incredible-metal", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e26729_image16.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e26729_image16.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 83.09 USD"}, "width": 19, @@ -122,14 +117,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": "Arthur Dent", "expires": {"year": 2025, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -160,11 +147,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "comment": "Example comment to myself", "orderComment": "", "acceptedOn": "2024-03-29T21:29:21Z", - "fulfilledOn": "2018-12-03T22:06:15Z", "refundedOn": "2024-04-08T18:25:04Z", - "disputedOn": "2018-12-03T22:06:15Z", - "disputeUpdatedOn": "2018-12-03T22:06:15Z", - "disputeLastStatus": "warning_needs_response", "customerPaid": {"unit": "USD", "value": "5892", "string": " 118.73 USD"}, "netAmount": {"unit": "USD", "value": "5892", "string": " 112.62 USD"}, "applicationFee": {"unit": "USD", "value": "5892", "string": " 2.37 USD"}, @@ -226,7 +209,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "variantSlug": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantSKU": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 55.61 USD"}, "weight": 11, @@ -245,7 +228,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "variantSlug": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantSKU": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 53.44 USD"}, "weight": 38, @@ -269,14 +252,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -328,11 +303,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "comment": None, "orderComment": None, "acceptedOn": "datetime", - "fulfilledOn": "datetime", - "refundedOn": "datetime", - "disputedOn": "datetime", - "disputeUpdatedOn": "datetime", - "disputeLastStatus": None, "customerPaid": {"unit": None, "value": None, "string": None}, "netAmount": {"unit": None, "value": None, "string": None}, "applicationFee": {"unit": None, "value": None, "string": None}, @@ -437,14 +407,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": None, "expires": {"year": None, "month": None}, }, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -472,11 +434,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "comment": None, "orderComment": None, "acceptedOn": "datetime", - "fulfilledOn": "datetime", "refundedOn": "datetime", - "disputedOn": "datetime", - "disputeUpdatedOn": "datetime", - "disputeLastStatus": None, "customerPaid": {"unit": None, "value": None, "string": None}, "netAmount": {"unit": None, "value": None, "string": None}, "applicationFee": {"unit": None, "value": None, "string": None}, @@ -583,14 +541,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": None, "expires": {"year": None, "month": None}, }, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -714,7 +664,7 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "variantSlug": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantSKU": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 55.61 USD"}, "weight": 11, @@ -733,7 +683,7 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "variantSlug": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantSKU": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 53.44 USD"}, "weight": 38, @@ -744,12 +694,10 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: ], "purchasedItemsCount": 2, "stripeDetails": { - "subscriptionId": "sub_1J6xwG2eZvKYlo2CXu9Zt0Tn", "paymentMethod": "pm_1OzmzBJYFi4lcbXWHKNdXU7j", "paymentIntentId": "pi_3OzmzDJYFi4lcbXW1hTBW6ft", "customerId": "cus_PpRsNHwWdUoRKR", "chargeId": "ch_3OzmzDJYFi4lcbXW1ndkkrH2", - "disputeId": "disputeId", "refundId": "re_3OzmzDJYFi4lcbXW1kFAmlBk", "refundReason": "fraudulent", }, @@ -759,14 +707,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -913,24 +853,14 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: ), "purchasedItemsCount": None, "stripeDetails": { - "subscriptionId": None, "paymentMethod": None, "paymentIntentId": None, "customerId": None, "chargeId": None, - "disputeId": None, "refundId": None, "refundReason": None, }, "stripeCard": {"last4": None, "brand": None, "ownerName": None, "expires": {"year": None, "month": None}}, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -1052,7 +982,7 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: "variantSlug": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantSKU": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 55.61 USD"}, "weight": 11, @@ -1071,7 +1001,7 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: "variantSlug": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantSKU": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 53.44 USD"}, "weight": 38, @@ -1082,12 +1012,10 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: ], "purchasedItemsCount": 2, "stripeDetails": { - "subscriptionId": "sub_1J6xwG2eZvKYlo2CXu9Zt0Tn", "paymentMethod": "pm_1OzmzBJYFi4lcbXWHKNdXU7j", "paymentIntentId": "pi_3OzmzDJYFi4lcbXW1hTBW6ft", "customerId": "cus_PpRsNHwWdUoRKR", "chargeId": "ch_3OzmzDJYFi4lcbXW1ndkkrH2", - "disputeId": "disputeId", "refundId": "re_3OzmzDJYFi4lcbXW1kFAmlBk", "refundReason": "fraudulent", }, @@ -1097,14 +1025,6 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -1251,24 +1171,14 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: ), "purchasedItemsCount": None, "stripeDetails": { - "subscriptionId": None, "paymentMethod": None, "paymentIntentId": None, "customerId": None, "chargeId": None, - "disputeId": None, "refundId": None, "refundReason": None, }, "stripeCard": {"last4": None, "brand": None, "ownerName": None, "expires": {"year": None, "month": None}}, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -1390,7 +1300,7 @@ async def test_update_fulfill(client: Webflow, async_client: AsyncWebflow) -> No "variantSlug": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantSKU": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 55.61 USD"}, "weight": 11, @@ -1409,7 +1319,7 @@ async def test_update_fulfill(client: Webflow, async_client: AsyncWebflow) -> No "variantSlug": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantSKU": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 53.44 USD"}, "weight": 38, @@ -1420,12 +1330,10 @@ async def test_update_fulfill(client: Webflow, async_client: AsyncWebflow) -> No ], "purchasedItemsCount": 2, "stripeDetails": { - "subscriptionId": "sub_1J6xwG2eZvKYlo2CXu9Zt0Tn", "paymentMethod": "pm_1OzmzBJYFi4lcbXWHKNdXU7j", "paymentIntentId": "pi_3OzmzDJYFi4lcbXW1hTBW6ft", "customerId": "cus_PpRsNHwWdUoRKR", "chargeId": "ch_3OzmzDJYFi4lcbXW1ndkkrH2", - "disputeId": "disputeId", "refundId": "re_3OzmzDJYFi4lcbXW1kFAmlBk", "refundReason": "fraudulent", }, @@ -1435,14 +1343,6 @@ async def test_update_fulfill(client: Webflow, async_client: AsyncWebflow) -> No "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -1589,24 +1489,14 @@ async def test_update_fulfill(client: Webflow, async_client: AsyncWebflow) -> No ), "purchasedItemsCount": None, "stripeDetails": { - "subscriptionId": None, "paymentMethod": None, "paymentIntentId": None, "customerId": None, "chargeId": None, - "disputeId": None, "refundId": None, "refundReason": None, }, "stripeCard": {"last4": None, "brand": None, "ownerName": None, "expires": {"year": None, "month": None}}, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -1728,7 +1618,7 @@ async def test_update_unfulfill(client: Webflow, async_client: AsyncWebflow) -> "variantSlug": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantSKU": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 55.61 USD"}, "weight": 11, @@ -1747,7 +1637,7 @@ async def test_update_unfulfill(client: Webflow, async_client: AsyncWebflow) -> "variantSlug": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantSKU": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 53.44 USD"}, "weight": 38, @@ -1758,12 +1648,10 @@ async def test_update_unfulfill(client: Webflow, async_client: AsyncWebflow) -> ], "purchasedItemsCount": 2, "stripeDetails": { - "subscriptionId": "sub_1J6xwG2eZvKYlo2CXu9Zt0Tn", "paymentMethod": "pm_1OzmzBJYFi4lcbXWHKNdXU7j", "paymentIntentId": "pi_3OzmzDJYFi4lcbXW1hTBW6ft", "customerId": "cus_PpRsNHwWdUoRKR", "chargeId": "ch_3OzmzDJYFi4lcbXW1ndkkrH2", - "disputeId": "disputeId", "refundId": "re_3OzmzDJYFi4lcbXW1kFAmlBk", "refundReason": "fraudulent", }, @@ -1773,14 +1661,6 @@ async def test_update_unfulfill(client: Webflow, async_client: AsyncWebflow) -> "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -1927,24 +1807,14 @@ async def test_update_unfulfill(client: Webflow, async_client: AsyncWebflow) -> ), "purchasedItemsCount": None, "stripeDetails": { - "subscriptionId": None, "paymentMethod": None, "paymentIntentId": None, "customerId": None, "chargeId": None, - "disputeId": None, "refundId": None, "refundReason": None, }, "stripeCard": {"last4": None, "brand": None, "ownerName": None, "expires": {"year": None, "month": None}}, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -2066,7 +1936,7 @@ async def test_refund(client: Webflow, async_client: AsyncWebflow) -> None: "variantSlug": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantSKU": "luxurious-fresh-ball-generic-bronze-practical-plastic", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2672c_image14.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 55.61 USD"}, "weight": 11, @@ -2085,7 +1955,7 @@ async def test_refund(client: Webflow, async_client: AsyncWebflow) -> None: "variantSlug": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantSKU": "recycled-steel-gloves-electronic-granite-handcrafted-grey", "variantImage": { - "url": "https://d1otoma47x30pg.cloudfront.net/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" + "url": "https://dev-assets.website-files.com/66072f39417a2a35b2589cc7/66072fb51b89448912e2671e_image2.jpeg" }, "variantPrice": {"unit": "USD", "value": "5892", "string": " 53.44 USD"}, "weight": 38, @@ -2096,12 +1966,10 @@ async def test_refund(client: Webflow, async_client: AsyncWebflow) -> None: ], "purchasedItemsCount": 2, "stripeDetails": { - "subscriptionId": "sub_1J6xwG2eZvKYlo2CXu9Zt0Tn", "paymentMethod": "pm_1OzmzBJYFi4lcbXWHKNdXU7j", "paymentIntentId": "pi_3OzmzDJYFi4lcbXW1hTBW6ft", "customerId": "cus_PpRsNHwWdUoRKR", "chargeId": "ch_3OzmzDJYFi4lcbXW1ndkkrH2", - "disputeId": "disputeId", "refundId": "re_3OzmzDJYFi4lcbXW1kFAmlBk", "refundReason": "fraudulent", }, @@ -2111,14 +1979,6 @@ async def test_refund(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -2265,24 +2125,14 @@ async def test_refund(client: Webflow, async_client: AsyncWebflow) -> None: ), "purchasedItemsCount": None, "stripeDetails": { - "subscriptionId": None, "paymentMethod": None, "paymentIntentId": None, "customerId": None, "chargeId": None, - "disputeId": None, "refundId": None, "refundReason": None, }, "stripeCard": {"last4": None, "brand": None, "ownerName": None, "expires": {"year": None, "month": None}}, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, diff --git a/tests/test_pages.py b/tests/test_pages.py index 716c201..12e01dd 100644 --- a/tests/test_pages.py +++ b/tests/test_pages.py @@ -7,8 +7,12 @@ import datetime from webflow import PageSeo from webflow import PageOpenGraph -from webflow import TextNodeWrite -from webflow import ComponentInstanceNodePropertyOverridesWrite +from webflow import TextNode +from webflow import Select +from webflow import SelectNodeWriteChoicesItem +from webflow import TextInput +from webflow import SubmitButton +from webflow import ComponentInstance from webflow import ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem @@ -20,15 +24,12 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "siteId": "6258612d1ee792848f805dcf", "title": "Guide to the Galaxy", "slug": "guide-to-the-galaxy", - "parentId": "6419db964a9c435aa3af6251", - "collectionId": "6390c49774a71f12831a08e3", "createdOn": "2024-03-11T10:42:00Z", "lastUpdated": "2024-03-11T10:42:42Z", "archived": False, "draft": False, "canBranch": True, "isBranch": False, - "isMembersOnly": False, "seo": { "title": "The Ultimate Hitchhiker's Guide to the Galaxy", "description": "Everything you need to know about the galaxy, from avoiding Vogon poetry to the importance of towels.", @@ -47,15 +48,12 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "siteId": "6258612d1ee792848f805dcf", "title": "Towel Day Celebrations", "slug": "towel-day", - "parentId": "6419db964a9c435aa3af6251", - "collectionId": "6390c49774a71f12831a08e3", "createdOn": "2024-05-25T09:00:00Z", "lastUpdated": "2024-05-25T09:42:00Z", "archived": False, "draft": False, "canBranch": True, "isBranch": False, - "isMembersOnly": False, "seo": { "title": "Celebrate Towel Day - The Hitchhiker's Guide to the Galaxy", "description": "A guide to celebrating Towel Day, in honor of the most massively useful thing an interstellar hitchhiker can have.", @@ -81,15 +79,12 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "siteId": None, "title": None, "slug": None, - "parentId": None, - "collectionId": None, "createdOn": "datetime", "lastUpdated": "datetime", "archived": None, "draft": None, "canBranch": None, "isBranch": None, - "isMembersOnly": None, "seo": {"title": None, "description": None}, "openGraph": {"title": None, "titleCopied": None, "description": None, "descriptionCopied": None}, "localeId": None, @@ -100,15 +95,12 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "siteId": None, "title": None, "slug": None, - "parentId": None, - "collectionId": None, "createdOn": "datetime", "lastUpdated": "datetime", "archived": None, "draft": None, "canBranch": None, "isBranch": None, - "isMembersOnly": None, "seo": {"title": None, "description": None}, "openGraph": {"title": None, "titleCopied": None, "description": None, "descriptionCopied": None}, "localeId": None, @@ -133,15 +125,12 @@ async def test_get_metadata(client: Webflow, async_client: AsyncWebflow) -> None "siteId": "6258612d1ee792848f805dcf", "title": "Guide to the Galaxy", "slug": "guide-to-the-galaxy", - "parentId": "6419db964a9c435aa3af6251", - "collectionId": "6390c49774a71f12831a08e3", "createdOn": "2024-03-11T10:42:00Z", "lastUpdated": "2024-03-11T10:42:42Z", "archived": False, "draft": False, "canBranch": True, "isBranch": False, - "isMembersOnly": False, "seo": { "title": "The Ultimate Hitchhiker's Guide to the Galaxy", "description": "Everything you need to know about the galaxy, from avoiding Vogon poetry to the importance of towels.", @@ -160,15 +149,12 @@ async def test_get_metadata(client: Webflow, async_client: AsyncWebflow) -> None "siteId": None, "title": None, "slug": None, - "parentId": None, - "collectionId": None, "createdOn": "datetime", "lastUpdated": "datetime", "archived": None, "draft": None, "canBranch": None, "isBranch": None, - "isMembersOnly": None, "seo": {"title": None, "description": None}, "openGraph": {"title": None, "titleCopied": None, "description": None, "descriptionCopied": None}, "localeId": None, @@ -189,15 +175,12 @@ async def test_update_page_settings(client: Webflow, async_client: AsyncWebflow) "siteId": "6258612d1ee792848f805dcf", "title": "Guide to the Galaxy", "slug": "guide-to-the-galaxy", - "parentId": "6419db964a9c435aa3af6251", - "collectionId": "6390c49774a71f12831a08e3", "createdOn": "2024-03-11T10:42:00Z", "lastUpdated": "2024-03-11T10:42:42Z", "archived": False, "draft": False, "canBranch": True, "isBranch": False, - "isMembersOnly": False, "seo": { "title": "The Ultimate Hitchhiker's Guide to the Galaxy", "description": "Everything you need to know about the galaxy, from avoiding Vogon poetry to the importance of towels.", @@ -216,15 +199,12 @@ async def test_update_page_settings(client: Webflow, async_client: AsyncWebflow) "siteId": None, "title": None, "slug": None, - "parentId": None, - "collectionId": None, "createdOn": "datetime", "lastUpdated": "datetime", "archived": None, "draft": None, "canBranch": None, "isBranch": None, - "isMembersOnly": None, "seo": {"title": None, "description": None}, "openGraph": {"title": None, "titleCopied": None, "description": None, "descriptionCopied": None}, "localeId": None, @@ -291,50 +271,43 @@ async def test_get_content(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { "pageId": "658205daa3e8206a523b5ad4", "nodes": [ + {"id": "id", "text": {}, "attributes": {"key": "value"}, "type": "text"}, + {"id": "id", "text": {}, "attributes": {"key": "value"}, "type": "text"}, + {"id": "id", "image": {}, "attributes": {"key": "value"}, "type": "image"}, { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad623", - "componentId": "nodes", - "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], - }, - { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad627", - "componentId": "nodes", - "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], + "id": "id", + "choices": [{"value": "value", "text": "text"}], + "attributes": {"key": "value"}, + "type": "select", }, + {"id": "id", "placeholder": "placeholder", "attributes": {"key": "value"}, "type": "text-input"}, + {"id": "id", "text": {}, "attributes": {"key": "value"}, "type": "text"}, { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad629", - "componentId": "nodes", + "id": "id", + "componentId": "componentId", "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], - }, - { "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad631", - "componentId": "6258612d1ee792848f805dcf", - "propertyOverrides": [ - { - "propertyId": "a245c12d-995b-55ee-5ec7-aa36a6cad633", - "type": "Plain Text", - "label": "Catchphrase", - "text": {"text": "Don't Panic!"}, - }, - { - "propertyId": "a245c12d-995b-55ee-5ec7-aa36a6cad635", - "type": "Rich Text", - "label": "Tagline", - "text": {"html": "

Always know where your towel is.

"}, - }, - ], }, ], "pagination": {"limit": 4, "offset": 0, "total": 4}, + "lastUpdated": "2016-10-24T19:42:38Z", } expected_types: typing.Any = { "pageId": None, - "nodes": ("list", {0: "no_validate", 1: "no_validate", 2: "no_validate", 3: "no_validate"}), + "nodes": ( + "list", + { + 0: "no_validate", + 1: "no_validate", + 2: "no_validate", + 3: "no_validate", + 4: "no_validate", + 5: "no_validate", + 6: "no_validate", + }, + ), "pagination": {"limit": None, "offset": None, "total": None}, + "lastUpdated": "datetime", } response = client.pages.get_content(page_id="63c720f9347c2139b248e552", locale_id="65427cf400e02b306eaa04a0") validate_response(response, expected_response, expected_types) @@ -352,14 +325,23 @@ async def test_update_static_content(client: Webflow, async_client: AsyncWebflow page_id="63c720f9347c2139b248e552", locale_id="localeId", nodes=[ - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623", text="

The Hitchhiker's Guide to the Galaxy

" ), - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627", text="

Don't Panic!

Always know where your towel is.

", ), - ComponentInstanceNodePropertyOverridesWrite( + Select( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635", + choices=[ + SelectNodeWriteChoicesItem(value="choice-1", text="First choice"), + SelectNodeWriteChoicesItem(value="choice-2", text="Second choice"), + ], + ), + TextInput(node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642", placeholder="Enter something here..."), + SubmitButton(node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671", value="Submit", waiting_text="Submitting..."), + ComponentInstance( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629", property_overrides=[ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem( @@ -379,14 +361,23 @@ async def test_update_static_content(client: Webflow, async_client: AsyncWebflow page_id="63c720f9347c2139b248e552", locale_id="localeId", nodes=[ - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623", text="

The Hitchhiker's Guide to the Galaxy

" ), - TextNodeWrite( + TextNode( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627", text="

Don't Panic!

Always know where your towel is.

", ), - ComponentInstanceNodePropertyOverridesWrite( + Select( + node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635", + choices=[ + SelectNodeWriteChoicesItem(value="choice-1", text="First choice"), + SelectNodeWriteChoicesItem(value="choice-2", text="Second choice"), + ], + ), + TextInput(node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642", placeholder="Enter something here..."), + SubmitButton(node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671", value="Submit", waiting_text="Submitting..."), + ComponentInstance( node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629", property_overrides=[ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem( diff --git a/tests/test_products.py b/tests/test_products.py index 03d28db..d361d46 100644 --- a/tests/test_products.py +++ b/tests/test_products.py @@ -4,7 +4,15 @@ from webflow import AsyncWebflow import typing from .utilities import validate_response +from webflow.resources.products import ProductSkuCreateProduct +from webflow import ProductFieldData +from webflow import SkuPropertyList +from webflow import SkuPropertyListEnumItem +from webflow.resources.products import ProductSkuCreateSku +from webflow import SkuFieldData +from webflow import SkuFieldDataPrice from webflow import Sku +import datetime async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: @@ -28,24 +36,33 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: { "id": "Color", "name": "Color", - "enum": [{"id": "id", "name": "Royal Blue", "slug": "royal-blue"}], + "enum": [{"id": "royal-blue", "name": "Royal Blue", "slug": "royal-blue"}], } ], }, }, "skus": [ { - "id": "580e63fc8c9a982ac9b8b745", + "id": "66072fb71b89448912e2681c", "cmsLocaleId": "653ad57de882f528b32e810e", "lastPublished": "2023-03-17T18:47:35Z", "lastUpdated": "2023-03-17T18:47:35Z", "createdOn": "2023-03-17T18:47:35Z", "fieldData": { - "sku-values": {"ff42fee0113744f693a764e3431a9cc2": "64a74715c456e36762fc39a1"}, - "name": "Blue T-shirt", - "slug": "t-shirt-blue", - "price": {"value": 100, "unit": "USD"}, + "sku-values": {"color": "blue", "size": "small"}, + "name": "Colorful T-shirt - Default", + "slug": "colorful-t-shirt-default", + "price": {"value": 2499, "unit": "USD", "currency": "USD"}, "quantity": 10, + "main-image": "https://www.example.com/image.jpg", + "sku": "1234567890", + "sku-properties": [ + { + "id": "Color", + "name": "Color", + "enum": [{"id": "royal-blue", "name": "Royal Blue", "slug": "royal-blue"}], + } + ], }, } ], @@ -93,11 +110,23 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "datetime", "createdOn": "datetime", "fieldData": { - "sku-values": ("dict", {0: (None, None)}), + "sku-values": ("dict", {0: (None, None), 1: (None, None)}), "name": None, "slug": None, - "price": {"value": None, "unit": None}, + "price": {"value": None, "unit": None, "currency": None}, "quantity": None, + "main-image": None, + "sku": None, + "sku-properties": ( + "list", + { + 0: { + "id": None, + "name": None, + "enum": ("list", {0: {"id": None, "name": None, "slug": None}}), + } + }, + ), }, } }, @@ -130,9 +159,13 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "description": "A plain cotton t-shirt.", "shippable": True, "sku-properties": [ - {"id": "Color", "name": "Color", "enum": [{"id": "id", "name": "Royal Blue", "slug": "royal-blue"}]} + { + "id": "Color", + "name": "Color", + "enum": [{"id": "royal-blue", "name": "Royal Blue", "slug": "royal-blue"}], + } ], - "categories": ["categories"], + "category": ["category"], "tax-category": "standard-taxable", "default-sku": "default-sku", "ec-product-type": "ff42fee0113744f693a764e3431a9cc2", @@ -140,17 +173,26 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: }, "skus": [ { - "id": "580e63fc8c9a982ac9b8b745", + "id": "66072fb71b89448912e2681c", "cmsLocaleId": "653ad57de882f528b32e810e", "lastPublished": "2023-03-17T18:47:35Z", "lastUpdated": "2023-03-17T18:47:35Z", "createdOn": "2023-03-17T18:47:35Z", "fieldData": { - "sku-values": {"ff42fee0113744f693a764e3431a9cc2": "64a74715c456e36762fc39a1"}, - "name": "Blue T-shirt", - "slug": "t-shirt-blue", - "price": {"value": 100, "unit": "USD"}, + "sku-values": {"color": "blue", "size": "small"}, + "name": "Colorful T-shirt - Default", + "slug": "colorful-t-shirt-default", + "price": {"value": 2499, "unit": "USD", "currency": "USD"}, "quantity": 10, + "main-image": "https://www.example.com/image.jpg", + "sku": "1234567890", + "sku-properties": [ + { + "id": "Color", + "name": "Color", + "enum": [{"id": "royal-blue", "name": "Royal Blue", "slug": "royal-blue"}], + } + ], }, } ], @@ -173,7 +215,7 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "list", {0: {"id": None, "name": None, "enum": ("list", {0: {"id": None, "name": None, "slug": None}})}}, ), - "categories": ("list", {0: None}), + "category": ("list", {0: None}), "tax-category": None, "default-sku": None, "ec-product-type": None, @@ -189,20 +231,108 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "datetime", "createdOn": "datetime", "fieldData": { - "sku-values": ("dict", {0: (None, None)}), + "sku-values": ("dict", {0: (None, None), 1: (None, None)}), "name": None, "slug": None, - "price": {"value": None, "unit": None}, + "price": {"value": None, "unit": None, "currency": None}, "quantity": None, + "main-image": None, + "sku": None, + "sku-properties": ( + "list", + { + 0: { + "id": None, + "name": None, + "enum": ("list", {0: {"id": None, "name": None, "slug": None}}), + } + }, + ), }, } }, ), } - response = client.products.create(site_id="580e63e98c9a982ac9b8b741") + response = 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.0, 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", + ) + ), + ) validate_response(response, expected_response, expected_types) - async_response = await async_client.products.create(site_id="580e63e98c9a982ac9b8b741") + async_response = await async_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.0, 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", + ) + ), + ) validate_response(async_response, expected_response, expected_types) @@ -222,9 +352,13 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "description": "A plain cotton t-shirt.", "shippable": True, "sku-properties": [ - {"id": "Color", "name": "Color", "enum": [{"id": "id", "name": "Royal Blue", "slug": "royal-blue"}]} + { + "id": "Color", + "name": "Color", + "enum": [{"id": "royal-blue", "name": "Royal Blue", "slug": "royal-blue"}], + } ], - "categories": ["categories"], + "category": ["category"], "tax-category": "standard-taxable", "default-sku": "default-sku", "ec-product-type": "ff42fee0113744f693a764e3431a9cc2", @@ -232,17 +366,26 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: }, "skus": [ { - "id": "580e63fc8c9a982ac9b8b745", + "id": "66072fb71b89448912e2681c", "cmsLocaleId": "653ad57de882f528b32e810e", "lastPublished": "2023-03-17T18:47:35Z", "lastUpdated": "2023-03-17T18:47:35Z", "createdOn": "2023-03-17T18:47:35Z", "fieldData": { - "sku-values": {"ff42fee0113744f693a764e3431a9cc2": "64a74715c456e36762fc39a1"}, - "name": "Blue T-shirt", - "slug": "t-shirt-blue", - "price": {"value": 100, "unit": "USD"}, + "sku-values": {"color": "blue", "size": "small"}, + "name": "Colorful T-shirt - Default", + "slug": "colorful-t-shirt-default", + "price": {"value": 2499, "unit": "USD", "currency": "USD"}, "quantity": 10, + "main-image": "https://www.example.com/image.jpg", + "sku": "1234567890", + "sku-properties": [ + { + "id": "Color", + "name": "Color", + "enum": [{"id": "royal-blue", "name": "Royal Blue", "slug": "royal-blue"}], + } + ], }, } ], @@ -265,7 +408,7 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "list", {0: {"id": None, "name": None, "enum": ("list", {0: {"id": None, "name": None, "slug": None}})}}, ), - "categories": ("list", {0: None}), + "category": ("list", {0: None}), "tax-category": None, "default-sku": None, "ec-product-type": None, @@ -281,11 +424,23 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "datetime", "createdOn": "datetime", "fieldData": { - "sku-values": ("dict", {0: (None, None)}), + "sku-values": ("dict", {0: (None, None), 1: (None, None)}), "name": None, "slug": None, - "price": {"value": None, "unit": None}, + "price": {"value": None, "unit": None, "currency": None}, "quantity": None, + "main-image": None, + "sku": None, + "sku-properties": ( + "list", + { + 0: { + "id": None, + "name": None, + "enum": ("list", {0: {"id": None, "name": None, "slug": None}}), + } + }, + ), }, } }, @@ -315,9 +470,13 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: "description": "A plain cotton t-shirt.", "shippable": True, "sku-properties": [ - {"id": "Color", "name": "Color", "enum": [{"id": "id", "name": "Royal Blue", "slug": "royal-blue"}]} + { + "id": "Color", + "name": "Color", + "enum": [{"id": "royal-blue", "name": "Royal Blue", "slug": "royal-blue"}], + } ], - "categories": ["categories"], + "category": ["category"], "tax-category": "standard-taxable", "default-sku": "default-sku", "ec-product-type": "ff42fee0113744f693a764e3431a9cc2", @@ -340,7 +499,7 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: "list", {0: {"id": None, "name": None, "enum": ("list", {0: {"id": None, "name": None, "slug": None}})}}, ), - "categories": ("list", {0: None}), + "category": ("list", {0: None}), "tax-category": None, "default-sku": None, "ec-product-type": None, @@ -359,17 +518,26 @@ async def test_create_sku(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { "skus": [ { - "id": "580e63fc8c9a982ac9b8b745", + "id": "66072fb71b89448912e2681c", "cmsLocaleId": "653ad57de882f528b32e810e", "lastPublished": "2023-03-17T18:47:35Z", "lastUpdated": "2023-03-17T18:47:35Z", "createdOn": "2023-03-17T18:47:35Z", "fieldData": { - "sku-values": {"ff42fee0113744f693a764e3431a9cc2": "64a74715c456e36762fc39a1"}, - "name": "Blue T-shirt", - "slug": "t-shirt-blue", - "price": {"value": 100, "unit": "USD"}, + "sku-values": {"color": "blue", "size": "small"}, + "name": "Colorful T-shirt - Default", + "slug": "colorful-t-shirt-default", + "price": {"value": 2499, "unit": "USD", "currency": "USD"}, "quantity": 10, + "main-image": "https://www.example.com/image.jpg", + "sku": "1234567890", + "sku-properties": [ + { + "id": "Color", + "name": "Color", + "enum": [{"id": "royal-blue", "name": "Royal Blue", "slug": "royal-blue"}], + } + ], }, } ] @@ -385,44 +553,95 @@ async def test_create_sku(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "datetime", "createdOn": "datetime", "fieldData": { - "sku-values": ("dict", {0: (None, None)}), + "sku-values": ("dict", {0: (None, None), 1: (None, None)}), "name": None, "slug": None, - "price": {"value": None, "unit": None}, + "price": {"value": None, "unit": None, "currency": None}, "quantity": None, + "main-image": None, + "sku": None, + "sku-properties": ( + "list", + { + 0: { + "id": None, + "name": None, + "enum": ("list", {0: {"id": None, "name": None, "slug": None}}), + } + }, + ), }, } }, ) } response = client.products.create_sku( - site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", skus=[Sku()] + site_id="580e63e98c9a982ac9b8b741", + product_id="580e63fc8c9a982ac9b8b745", + skus=[ + Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + last_updated=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + created_on=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice(value=2499.0, unit="USD", currency="USD"), + ), + ) + ], ) validate_response(response, expected_response, expected_types) async_response = await async_client.products.create_sku( - site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", skus=[Sku()] + site_id="580e63e98c9a982ac9b8b741", + product_id="580e63fc8c9a982ac9b8b745", + skus=[ + Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + last_updated=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + created_on=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice(value=2499.0, unit="USD", currency="USD"), + ), + ) + ], ) validate_response(async_response, expected_response, expected_types) async def test_update_sku(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "580e63fc8c9a982ac9b8b745", + "id": "66072fb71b89448912e2681c", "cmsLocaleId": "653ad57de882f528b32e810e", "lastPublished": "2023-03-17T18:47:35Z", "lastUpdated": "2023-03-17T18:47:35Z", "createdOn": "2023-03-17T18:47:35Z", "fieldData": { - "sku-values": {"ff42fee0113744f693a764e3431a9cc2": "64a74715c456e36762fc39a1"}, - "name": "Blue T-shirt", - "slug": "t-shirt-blue", - "price": {"value": 100, "unit": "USD"}, + "sku-values": {"color": "blue", "size": "small"}, + "name": "Colorful T-shirt - Default", + "slug": "colorful-t-shirt-default", + "price": {"value": 2499, "unit": "USD", "currency": "USD"}, "compare-at-price": {"value": 100, "unit": "USD"}, "ec-sku-billing-method": "one-time", "ec-sku-subscription-plan": {"interval": "day", "frequency": 1, "trial": 7, "plans": [{}]}, "track-inventory": True, "quantity": 10, + "main-image": "https://www.example.com/image.jpg", + "sku": "1234567890", + "sku-properties": [ + { + "id": "Color", + "name": "Color", + "enum": [{"id": "royal-blue", "name": "Royal Blue", "slug": "royal-blue"}], + } + ], }, } expected_types: typing.Any = { @@ -432,10 +651,10 @@ async def test_update_sku(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "datetime", "createdOn": "datetime", "fieldData": { - "sku-values": ("dict", {0: (None, None)}), + "sku-values": ("dict", {0: (None, None), 1: (None, None)}), "name": None, "slug": None, - "price": {"value": None, "unit": None}, + "price": {"value": None, "unit": None, "currency": None}, "compare-at-price": {"value": None, "unit": None}, "ec-sku-billing-method": None, "ec-sku-subscription-plan": { @@ -446,13 +665,30 @@ async def test_update_sku(client: Webflow, async_client: AsyncWebflow) -> None: }, "track-inventory": None, "quantity": None, + "main-image": None, + "sku": None, + "sku-properties": ( + "list", + {0: {"id": None, "name": None, "enum": ("list", {0: {"id": None, "name": None, "slug": None}})}}, + ), }, } response = client.products.update_sku( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", sku_id="5e8518516e147040726cc415", - sku=Sku(), + sku=Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + last_updated=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + created_on=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice(value=2499.0, unit="USD", currency="USD"), + ), + ), ) validate_response(response, expected_response, expected_types) @@ -460,6 +696,17 @@ async def test_update_sku(client: Webflow, async_client: AsyncWebflow) -> None: site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", sku_id="5e8518516e147040726cc415", - sku=Sku(), + sku=Sku( + id="66072fb71b89448912e2681c", + cms_locale_id="653ad57de882f528b32e810e", + last_published=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + last_updated=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + created_on=datetime.datetime.fromisoformat("2023-03-17 18:47:35+00:00"), + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice(value=2499.0, unit="USD", currency="USD"), + ), + ), ) validate_response(async_response, expected_response, expected_types) diff --git a/tests/test_scripts.py b/tests/test_scripts.py index 6432530..e884c23 100644 --- a/tests/test_scripts.py +++ b/tests/test_scripts.py @@ -14,7 +14,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "canCopy": False, "displayName": "Alert", "hostedLocation": "https://cdn.webflow.io/.../alert-0.0.1.js", - "integrityHash": "integrityHash", "createdOn": "2022-10-26T00:28:54.191Z", "lastUpdated": "lastUpdated", "version": "0.0.1", @@ -24,7 +23,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "canCopy": False, "displayName": "Alert", "hostedLocation": "https://cdn.webflow.io/.../alert-0.0.2.js", - "integrityHash": "integrityHash", "createdOn": "2022-10-26T00:28:54.191Z", "lastUpdated": "lastUpdated", "version": "0.0.2", @@ -39,7 +37,8 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "lastUpdated", "version": "1.0.0", }, - ] + ], + "pagination": {"limit": 100, "offset": 0, "total": 3}, } expected_types: typing.Any = { "registeredScripts": ( @@ -50,7 +49,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "canCopy": None, "displayName": None, "hostedLocation": None, - "integrityHash": None, "createdOn": None, "lastUpdated": None, "version": None, @@ -60,7 +58,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "canCopy": None, "displayName": None, "hostedLocation": None, - "integrityHash": None, "createdOn": None, "lastUpdated": None, "version": None, @@ -76,7 +73,8 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "version": None, }, }, - ) + ), + "pagination": {"limit": None, "offset": None, "total": None}, } response = client.scripts.list(site_id="580e63e98c9a982ac9b8b741") validate_response(response, expected_response, expected_types) @@ -131,7 +129,6 @@ async def test_register_inline(client: Webflow, async_client: AsyncWebflow) -> N "canCopy": False, "displayName": "Alert", "hostedLocation": "https://uploads-ssl.webflow.com/6258612d1ee792848f805dcf%2F64b6c769ff52ba6c3d904a91%2F660d6e15b3d1696f2d2b1447%2Falert-0.0.1.js", - "integrityHash": "integrityHash", "createdOn": "2022-10-26T00:28:54.191Z", "lastUpdated": "lastUpdated", "version": "0.0.1", @@ -141,7 +138,6 @@ async def test_register_inline(client: Webflow, async_client: AsyncWebflow) -> N "canCopy": None, "displayName": None, "hostedLocation": None, - "integrityHash": None, "createdOn": None, "lastUpdated": None, "version": None, diff --git a/tests/test_sites.py b/tests/test_sites.py index 6e9dd9b..5381bc5 100644 --- a/tests/test_sites.py +++ b/tests/test_sites.py @@ -11,40 +11,14 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "id": "670ecf86817e3cc7a510eb6a", "workspaceId": "625860a7a6c16d624927122f", "createdOn": "2024-10-15T20:24:38Z", - "displayName": "The Hitchiker‘s Guide", + "displayName": "The Hitchiker's Guide", "shortName": "hitchikers-guide", - "lastPublished": "2016-10-24T19:43:17Z", "lastUpdated": "2024-10-15T20:24:38Z", - "previewUrl": "https://d1otoma47x30pg.cloudfront.net/580e63e98c9a982ac9b8b741/201610241243.png", - "timeZone": "America/Los_Angeles", "parentFolderId": "670ece123598db72d9648be1", "customDomains": [ {"id": "589a331aa51e760df7ccb89d", "url": "test-api-domain.com", "lastPublished": "2022-12-07T16:51:37Z"} ], - "locales": { - "primary": { - "id": "653fd9af6a07fc9cfd7a5e57", - "cmsLocaleId": "653ad57de882f528b32e810e", - "enabled": False, - "displayName": "English (United States)", - "displayImageId": "displayImageId", - "redirect": True, - "subdirectory": "", - "tag": "en-US", - }, - "secondary": [ - { - "id": "653fd9af6a07fc9cfd7a5e57", - "cmsLocaleId": "653ad57de882f528b32e810e", - "enabled": False, - "displayName": "English (United States)", - "redirect": True, - "subdirectory": "", - "tag": "en-US", - } - ], - }, - "dataCollectionEnabled": False, + "dataCollectionEnabled": True, "dataCollectionType": "always", } expected_types: typing.Any = { @@ -53,38 +27,9 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "createdOn": "datetime", "displayName": None, "shortName": None, - "lastPublished": "datetime", "lastUpdated": "datetime", - "previewUrl": None, - "timeZone": None, "parentFolderId": None, "customDomains": ("list", {0: {"id": None, "url": None, "lastPublished": "datetime"}}), - "locales": { - "primary": { - "id": None, - "cmsLocaleId": None, - "enabled": None, - "displayName": None, - "displayImageId": None, - "redirect": None, - "subdirectory": None, - "tag": None, - }, - "secondary": ( - "list", - { - 0: { - "id": None, - "cmsLocaleId": None, - "enabled": None, - "displayName": None, - "redirect": None, - "subdirectory": None, - "tag": None, - } - }, - ), - }, "dataCollectionEnabled": None, "dataCollectionType": None, } @@ -108,7 +53,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "shortName": "heart-of-gold", "lastPublished": "2023-04-02T12:42:00Z", "lastUpdated": "2016-10-24T19:43:17Z", - "previewUrl": "https://d1otoma47x30pg.cloudfront.net/42e63e98c9a982ac9b8b741/197910121200.png", + "previewUrl": "https://dev-assets.website-files.com/42e63e98c9a982ac9b8b741/197910121200.png", "timeZone": "DeepSpace/InfiniteImprobability", "parentFolderId": "1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6", "customDomains": [ @@ -160,9 +105,8 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "shortName": "paranoid-android", "lastPublished": "2023-04-02T12:45:00Z", "lastUpdated": "2016-10-24T19:43:17Z", - "previewUrl": "https://d1otoma47x30pg.cloudfront.net/42e63e98c9a982ac9b8b742/198110121200.png", + "previewUrl": "https://dev-assets.website-files.com/42e63e98c9a982ac9b8b742/198110121200.png", "timeZone": "DeepSpace/Depression", - "parentFolderId": "1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6", "customDomains": [ {"id": "589a331aa51e760df7ccb89f", "url": "marvin.blog", "lastPublished": "2022-12-07T16:51:37Z"} ], @@ -199,9 +143,8 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "shortName": "vogon-poetry", "lastPublished": "2023-04-02T12:50:00Z", "lastUpdated": "2016-10-24T19:43:17Z", - "previewUrl": "https://d1otoma47x30pg.cloudfront.net/42e63e98c9a982ac9b8b743/198210121200.png", + "previewUrl": "https://dev-assets.website-files.com/42e63e98c9a982ac9b8b743/198210121200.png", "timeZone": "Vogsphere/PoetryHall", - "parentFolderId": "1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6", "customDomains": [ { "id": "589a331aa51e760df7ccb8a0", @@ -299,7 +242,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "datetime", "previewUrl": None, "timeZone": None, - "parentFolderId": None, "customDomains": ("list", {0: {"id": None, "url": None, "lastPublished": "datetime"}}), "locales": { "primary": { @@ -339,7 +281,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "datetime", "previewUrl": None, "timeZone": None, - "parentFolderId": None, "customDomains": ("list", {0: {"id": None, "url": None, "lastPublished": "datetime"}}), "locales": { "primary": { @@ -630,8 +571,16 @@ async def test_publish(client: Webflow, async_client: AsyncWebflow) -> None: "customDomains": ("list", {0: {"id": None, "url": None, "lastPublished": "datetime"}}), "publishToWebflowSubdomain": None, } - response = client.sites.publish(site_id="580e63e98c9a982ac9b8b741") + response = client.sites.publish( + site_id="580e63e98c9a982ac9b8b741", + custom_domains=["660c6449dd97ebc7346ac629", "660c6449dd97ebc7346ac62f"], + publish_to_webflow_subdomain=False, + ) validate_response(response, expected_response, expected_types) - async_response = await async_client.sites.publish(site_id="580e63e98c9a982ac9b8b741") + async_response = await async_client.sites.publish( + site_id="580e63e98c9a982ac9b8b741", + custom_domains=["660c6449dd97ebc7346ac629", "660c6449dd97ebc7346ac62f"], + publish_to_webflow_subdomain=False, + ) validate_response(async_response, expected_response, expected_types) diff --git a/tests/test_token.py b/tests/test_token.py index d57ee3b..d81bdea 100644 --- a/tests/test_token.py +++ b/tests/test_token.py @@ -57,7 +57,7 @@ async def test_introspect(client: Webflow, async_client: AsyncWebflow) -> None: "userIds": ("list", {0: None}), }, }, - "application": None, + "application": {"id": None, "description": None, "homepage": None, "displayName": None}, } response = client.token.introspect() validate_response(response, expected_response, expected_types) diff --git a/tests/test_users.py b/tests/test_users.py index abcbfd6..a4e1338 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -4,7 +4,8 @@ from webflow import AsyncWebflow import typing from .utilities import validate_response -from webflow.resources.users import UsersUpdateRequestData +import datetime +from webflow import UserAccessGroupsItem async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: @@ -237,16 +238,28 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: response = client.users.update( site_id="580e63e98c9a982ac9b8b741", user_id="580e63e98c9a982ac9b8b741", - data=UsersUpdateRequestData(name="Some One", accept_privacy=False, accept_communications=False), - access_groups=["webflowers", "platinum", "free-tier"], + id="6287ec36a841b25637c663df", + is_email_verified=True, + last_updated=datetime.datetime.fromisoformat("2022-05-20 13:46:12+00:00"), + invited_on=datetime.datetime.fromisoformat("2022-05-20 13:46:12+00:00"), + created_on=datetime.datetime.fromisoformat("2022-05-20 13:46:12+00:00"), + last_login=datetime.datetime.fromisoformat("2022-05-20 13:46:12+00:00"), + status="verified", + access_groups=[UserAccessGroupsItem(slug="webflowers", type="admin")], ) validate_response(response, expected_response, expected_types) async_response = await async_client.users.update( site_id="580e63e98c9a982ac9b8b741", user_id="580e63e98c9a982ac9b8b741", - data=UsersUpdateRequestData(name="Some One", accept_privacy=False, accept_communications=False), - access_groups=["webflowers", "platinum", "free-tier"], + id="6287ec36a841b25637c663df", + is_email_verified=True, + last_updated=datetime.datetime.fromisoformat("2022-05-20 13:46:12+00:00"), + invited_on=datetime.datetime.fromisoformat("2022-05-20 13:46:12+00:00"), + created_on=datetime.datetime.fromisoformat("2022-05-20 13:46:12+00:00"), + last_login=datetime.datetime.fromisoformat("2022-05-20 13:46:12+00:00"), + status="verified", + access_groups=[UserAccessGroupsItem(slug="webflowers", type="admin")], ) validate_response(async_response, expected_response, expected_types) @@ -291,11 +304,11 @@ async def test_invite(client: Webflow, async_client: AsyncWebflow) -> None: }, } response = client.users.invite( - site_id="580e63e98c9a982ac9b8b741", email="some.one@home.com", access_groups=["webflowers"] + site_id="580e63e98c9a982ac9b8b741", email="some.one@home.com", access_groups=["accessGroups"] ) validate_response(response, expected_response, expected_types) async_response = await async_client.users.invite( - site_id="580e63e98c9a982ac9b8b741", email="some.one@home.com", access_groups=["webflowers"] + site_id="580e63e98c9a982ac9b8b741", email="some.one@home.com", access_groups=["accessGroups"] ) validate_response(async_response, expected_response, expected_types) diff --git a/tests/test_webhooks.py b/tests/test_webhooks.py index 4c19188..2607cf1 100644 --- a/tests/test_webhooks.py +++ b/tests/test_webhooks.py @@ -9,7 +9,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "pagination": {"limit": 100, "offset": 0, "total": 100}, "webhooks": [ { "id": "57ca0a9e418c504a6e1acbb6", @@ -42,9 +41,9 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "createdOn": "2016-07-19T01:43:40Z", }, ], + "pagination": {"limit": 100, "offset": 0, "total": 100}, } expected_types: typing.Any = { - "pagination": {"limit": None, "offset": None, "total": None}, "webhooks": ( "list", { @@ -80,6 +79,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: }, }, ), + "pagination": {"limit": None, "offset": None, "total": None}, } response = client.webhooks.list(site_id="580e63e98c9a982ac9b8b741") validate_response(response, expected_response, expected_types) @@ -95,7 +95,6 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "url": "https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f", "workspaceId": "4f4e46fd476ea8c507000001", "siteId": "562ac0395358780a1f5e6fbd", - "filter": {"name": "My Form"}, "lastTriggered": "2023-02-08T23:59:28Z", "createdOn": "2022-11-08T23:59:28Z", } @@ -105,7 +104,6 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "url": None, "workspaceId": None, "siteId": None, - "filter": {"name": None}, "lastTriggered": "datetime", "createdOn": "datetime", } @@ -141,7 +139,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "url": "https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f", "workspaceId": "4f4e46fd476ea8c507000001", "siteId": "562ac0395358780a1f5e6fbd", - "filter": {"name": "My Form"}, "lastTriggered": "2023-02-08T23:59:28Z", "createdOn": "2022-11-08T23:59:28Z", } @@ -151,7 +148,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "url": None, "workspaceId": None, "siteId": None, - "filter": {"name": None}, "lastTriggered": "datetime", "createdOn": "datetime", } diff --git a/tests/workspaces/__init__.py b/tests/workspaces/__init__.py new file mode 100644 index 0000000..f3ea265 --- /dev/null +++ b/tests/workspaces/__init__.py @@ -0,0 +1,2 @@ +# This file was auto-generated by Fern from our API Definition. + diff --git a/tests/workspaces/test_audit_logs.py b/tests/workspaces/test_audit_logs.py new file mode 100644 index 0000000..f1d25db --- /dev/null +++ b/tests/workspaces/test_audit_logs.py @@ -0,0 +1,53 @@ +# This file was auto-generated by Fern from our API Definition. + +from webflow import Webflow +from webflow import AsyncWebflow +import typing +import datetime +from ..utilities import validate_response + + +async def test_get_workspace_audit_logs(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "items": [ + { + "eventSubType": "login", + "eventType": "user_access", + "timestamp": "2025-04-29T20:30:06Z", + "actor": {"id": "6661ccb359b561c69f29d554", "email": "someone@email.com"}, + "workspace": {"id": "6621ccb459b561c69f29d57c", "slug": "hitchhikers-workspace"}, + }, + { + "eventSubType": "user_added", + "eventType": "workspace_membership", + "timestamp": "2025-04-30T20:30:06Z", + "actor": {"id": "60492e55bbddce079561cd7a", "email": "someone@webflow.com"}, + "workspace": {"id": "6621ccb459b561c69f29d57c", "slug": "hitchhikers-workspace"}, + }, + { + "eventSubType": "user_added", + "eventType": "site_membership", + "timestamp": "2025-04-30T00:33:31Z", + "actor": {"id": "671fe00d185fc8c1ad409d37", "email": "someone@webflow.com"}, + "workspace": {"id": "6621ccb459b561c69f29d57c", "slug": "hitchhikers-workspace"}, + }, + ], + "pagination": {"limit": 10, "offset": 0, "total": 3}, + } + expected_types: typing.Any = { + "items": ("list", {0: "no_validate", 1: "no_validate", 2: "no_validate"}), + "pagination": {"limit": None, "offset": None, "total": None}, + } + response = client.workspaces.audit_logs.get_workspace_audit_logs( + workspace_id_or_slug="hitchhikers-workspace", + from_=datetime.datetime.fromisoformat("2024-04-22 16:00:31+00:00"), + to=datetime.datetime.fromisoformat("2024-04-22 16:00:31+00:00"), + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.workspaces.audit_logs.get_workspace_audit_logs( + workspace_id_or_slug="hitchhikers-workspace", + from_=datetime.datetime.fromisoformat("2024-04-22 16:00:31+00:00"), + to=datetime.datetime.fromisoformat("2024-04-22 16:00:31+00:00"), + ) + validate_response(async_response, expected_response, expected_types)